diff --git a/.github/assets/readme-header.png b/.github/assets/readme-header.png new file mode 100644 index 0000000..ca754a4 Binary files /dev/null and b/.github/assets/readme-header.png differ diff --git a/.github/assets/social-preview.png b/.github/assets/social-preview.png new file mode 100644 index 0000000..c154374 Binary files /dev/null and b/.github/assets/social-preview.png differ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd945f6..af6de18 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,14 @@ jobs: - name: Checkout uses: actions/checkout@v6 + - name: Set up Node 22 + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Verify DevsLab OSS brand assets + run: node scripts/check-brand-assets.mjs + - name: Set up JDK 21 uses: actions/setup-java@v5 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e9866c2..54e86ec 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,6 +17,14 @@ jobs: - name: Checkout uses: actions/checkout@v6 + - name: Set up Node 22 + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Verify DevsLab OSS brand assets + run: node scripts/check-brand-assets.mjs + - name: Set up JDK 21 uses: actions/setup-java@v5 with: diff --git a/README.ko.md b/README.ko.md index 60bbeca..cb90481 100644 --- a/README.ko.md +++ b/README.ko.md @@ -1,5 +1,11 @@ # api-log-spring-boot-starter +

+ api-log - DevsLab 오픈소스 +

+ +**[DevsLab 오픈소스](https://devslab.kr/)** · [OSS 브랜드 가이드](https://devslab.kr/brand/open-source/) · Registry O09 + [English](README.md) · **한국어** > Spring Boot용 이벤트 드리븐 API 호출 로깅. 비동기 이벤트 파이프라인 + PostgreSQL JSONB. 요청 경로를 막지 않고 외부 API 호출을 모두 기록합니다. diff --git a/README.md b/README.md index 3938fab..bc0a3c9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # api-log-spring-boot-starter +

+ api-log - Open source by DevsLab +

+ +**Open source by [DevsLab](https://devslab.kr/)** · [OSS brand guide](https://devslab.kr/brand/open-source/) · Registry O09 + **English** · [한국어](README.ko.md) > Event-driven API call logging for Spring Boot. Async event pipeline with PostgreSQL JSONB storage. diff --git a/docs/assets/favicon.svg b/docs/assets/favicon.svg new file mode 100644 index 0000000..c16d18c --- /dev/null +++ b/docs/assets/favicon.svg @@ -0,0 +1 @@ +api-log \ No newline at end of file diff --git a/docs/assets/logo.svg b/docs/assets/logo.svg index 188ac30..c16d18c 100644 --- a/docs/assets/logo.svg +++ b/docs/assets/logo.svg @@ -1,3 +1 @@ - - - +api-log \ No newline at end of file diff --git a/docs/assets/social-preview.png b/docs/assets/social-preview.png new file mode 100644 index 0000000..c154374 Binary files /dev/null and b/docs/assets/social-preview.png differ diff --git a/docs/index.ko.md b/docs/index.ko.md index 5d70dd4..fb88549 100644 --- a/docs/index.ko.md +++ b/docs/index.ko.md @@ -4,6 +4,11 @@ title: api-log — Spring Boot용 이벤트 드리븐 API 호출 로깅 # api-log + + + api-logDevsLab 오픈소스 + + > **Spring Boot용 이벤트 드리븐 API 호출 로깅.** > 비동기 이벤트 파이프라인 + PostgreSQL JSONB. 요청 경로를 막지 않고 외부 API 호출을 모두 기록합니다. diff --git a/docs/index.md b/docs/index.md index c06f493..5f47d84 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,6 +4,11 @@ title: api-log — Event-driven API call logging for Spring Boot # api-log + + + api-logOpen source by DevsLab + + > **Event-driven API call logging for Spring Boot.** > Async event pipeline + PostgreSQL JSONB. Log every outbound call without slowing the request path. diff --git a/docs/overrides/main.html b/docs/overrides/main.html new file mode 100644 index 0000000..05a9b2e --- /dev/null +++ b/docs/overrides/main.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} + +{% block site_meta %} + {{ super() }} + + + + + + + +{% endblock %} diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 40cd97f..1ebe889 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -241,3 +241,59 @@ html[lang="ko"] .md-header [aria-label="Select language"]::before, html[lang="ko"] .md-header [aria-label*="언어"]::before { content: "한"; } + +/* === O09 project identity ================================================== + * The event-ledger mark stays a small, linked source of provenance above the + * existing documentation hero. The atmosphere is decorative only. + * ========================================================================== */ +.oss-project-intro { + position: relative; + isolation: isolate; + display: inline-flex; + align-items: center; + gap: 0.65rem; + min-height: 2.5rem; + margin: 0 0 0.85rem; + padding: 0.35rem 0.55rem 0.35rem 0.4rem; + overflow: hidden; + border-radius: 0.4rem; + color: var(--md-default-fg-color); + text-decoration: none; +} + +.oss-project-intro:hover, +.oss-project-intro:focus { + color: var(--md-default-fg-color); + text-decoration: none; +} + +.oss-project-intro[data-atmosphere="project"]::before { + position: absolute; + inset: -1.75rem -3.5rem; + z-index: -1; + pointer-events: none; + background: radial-gradient(ellipse at 18% 50%, rgb(14 116 144 / 0.10), transparent 68%); + content: ""; +} + +.oss-project-intro img { + width: 2rem; + height: 2rem; + flex: none; +} + +.oss-project-intro span { + display: grid; + line-height: 1.2; +} + +.oss-project-intro strong { font-size: 0.9rem; } +.oss-project-intro small { color: var(--md-default-fg-color--light); font-size: 0.72rem; } + +[data-md-color-scheme="slate"] .oss-project-intro[data-atmosphere="project"]::before { + background: radial-gradient(ellipse at 18% 50%, rgb(34 211 238 / 0.10), transparent 68%); +} + +@media (forced-colors: active), print { + .oss-project-intro[data-atmosphere="project"]::before { display: none; } +} diff --git a/mkdocs.yml b/mkdocs.yml index 9c55d5d..acbc421 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -12,9 +12,10 @@ docs_dir: docs theme: name: material + custom_dir: docs/overrides language: en logo: assets/logo.svg - favicon: assets/logo.svg + favicon: assets/favicon.svg features: - navigation.tabs - navigation.sections diff --git a/scripts/check-brand-assets.mjs b/scripts/check-brand-assets.mjs new file mode 100644 index 0000000..e830ce2 --- /dev/null +++ b/scripts/check-brand-assets.mjs @@ -0,0 +1,88 @@ +import { createHash } from 'node:crypto'; +import { access, readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const guide = 'https://devslab.kr/brand/open-source/'; +const socialImage = 'https://api-log.devslab.kr/assets/social-preview.png'; +const read = (relative) => readFile(path.join(root, relative), 'utf8'); +const file = (relative) => path.join(root, relative); + +function expect(contents, expected, message) { + if (!contents.includes(expected)) throw new Error(`${message}: expected ${JSON.stringify(expected)}`); +} + +function reject(contents, pattern, message) { + if (pattern.test(contents)) throw new Error(message); +} + +async function sha256(relative) { + return createHash('sha256').update(await readFile(file(relative))).digest('hex'); +} + +const expectedAssets = new Map([ + ['.github/assets/readme-header.png', 'fea39433ffb685add26050558b2758858610be982f893014a1eead2d5469fbcc'], + ['.github/assets/social-preview.png', '3120931330d7604cda9ee4aa27d42e849e9f05f24cd8cb50b95e389d97a86842'], + ['docs/assets/logo.svg', '94697c47e87ac17d9209b890da0993b9d85c04ddb2d91b27afc7cfc31dc0380d'], + ['docs/assets/favicon.svg', '94697c47e87ac17d9209b890da0993b9d85c04ddb2d91b27afc7cfc31dc0380d'], + ['docs/assets/social-preview.png', '3120931330d7604cda9ee4aa27d42e849e9f05f24cd8cb50b95e389d97a86842'], +]); + +for (const [relative, expected] of expectedAssets) { + await access(file(relative)); + if ((await sha256(relative)) !== expected) throw new Error(`${relative} must match the O09 v0.1.1 asset checksum`); +} + +const glyph = await read('docs/assets/logo.svg'); +expect(glyph, 'data-oss-project="O09"', 'O09 registry id'); +expect(glyph, 'M5 8H13', 'O09 event-ledger input row'); +expect(glyph, 'M15 6H27V12H15Z', 'O09 event-ledger record cell'); +reject(glyph, /M\s*4\s*4\s*L\s*28\s*4/i, 'O09 must replace the former shared backend mark'); +reject(glyph, /M7 6H21V20H7Z/i, 'O09 must remain distinct from O08'); +reject(glyph, /M5 5H13V13H5Z/i, 'O09 must remain distinct from O10'); + +const [readme, readmeKo, mkdocs, index, indexKo, override, css] = await Promise.all([ + read('README.md'), + read('README.ko.md'), + read('mkdocs.yml'), + read('docs/index.md'), + read('docs/index.ko.md'), + read('docs/overrides/main.html'), + read('docs/stylesheets/extra.css'), +]); + +for (const [relative, contents, endorsement] of [ + ['README.md', readme, 'Open source by DevsLab'], + ['README.ko.md', readmeKo, 'DevsLab 오픈소스'], +]) { + expect(contents, '.github/assets/readme-header.png', `${relative} O09 README header`); + expect(contents, guide, `${relative} canonical OSS guide`); + expect(contents, endorsement, `${relative} localized endorsement`); +} + +for (const [relative, contents, endorsement] of [ + ['docs/index.md', index, 'Open source by DevsLab'], + ['docs/index.ko.md', indexKo, 'DevsLab 오픈소스'], +]) { + expect(contents, 'oss-project-intro', `${relative} O09 project introduction`); + expect(contents, guide, `${relative} canonical OSS guide`); + expect(contents, endorsement, `${relative} localized endorsement`); +} + +expect(mkdocs, 'custom_dir: docs/overrides', 'MkDocs override source'); +expect(mkdocs, 'favicon: assets/favicon.svg', 'MkDocs O09 favicon'); +expect(mkdocs, 'stylesheets/extra.css', 'MkDocs atmosphere stylesheet'); +expect(override, socialImage, 'source-only O09 social preview metadata'); +expect(override, 'og:image:alt', 'Open Graph alt metadata'); +expect(override, 'twitter:image:alt', 'Twitter alt metadata'); +expect(css, '.oss-project-intro', 'O09 docs project introduction styling'); +expect(css, 'data-atmosphere="project"', 'O09 project atmosphere'); +const slateAtmosphere = `[data-md-color-scheme="slate"] .oss-project-intro[data-atmosphere="project"]::before { + background: radial-gradient(ellipse at 18% 50%, rgb(34 211 238 / 0.10), transparent 68%); +}`; +expect(css, slateAtmosphere, 'Material slate O09 atmosphere at the 0.10 cyan opacity cap'); +expect(css, 'pointer-events: none', 'O09 atmosphere ignores interaction'); +expect(css, '@media (forced-colors: active), print', 'O09 print and forced-colors fallback'); + +console.log(`check:brand: verified O09 event-ledger identity, metadata, and ${expectedAssets.size} checksummed v0.1.1 assets`);