# Release Checklist (ํ•œ๊ตญ์–ด) ๐ŸŒ **Languages:** ๐Ÿ‡บ๐Ÿ‡ธ [English](../../../../ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ช๐Ÿ‡น [am](../../../am/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ธ๐Ÿ‡ฆ [ar](../../../ar/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฆ๐Ÿ‡ฟ [az](../../../az/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ง๐Ÿ‡ฌ [bg](../../../bg/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ง๐Ÿ‡ฉ [bn](../../../bn/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ง๐Ÿ‡ฆ [bs](../../../bs/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡จ๐Ÿ‡ฟ [cs](../../../cs/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฉ๐Ÿ‡ฐ [da](../../../da/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฉ๐Ÿ‡ช [de](../../../de/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฌ๐Ÿ‡ท [el](../../../el/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ช๐Ÿ‡ธ [es](../../../es/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ช๐Ÿ‡ช [et](../../../et/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ท [fa](../../../fa/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ซ๐Ÿ‡ฎ [fi](../../../fi/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ซ๐Ÿ‡ท [fr](../../../fr/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ช [ga](../../../ga/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [gu](../../../gu/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ณ๐Ÿ‡ฌ [ha](../../../ha/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ฑ [he](../../../he/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [hi](../../../hi/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ญ๐Ÿ‡ท [hr](../../../hr/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ญ๐Ÿ‡บ [hu](../../../hu/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฆ๐Ÿ‡ฒ [hy](../../../hy/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ฉ [id](../../../id/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ณ๐Ÿ‡ฌ [ig](../../../ig/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡น [it](../../../it/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฏ๐Ÿ‡ต [ja](../../../ja/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฌ๐Ÿ‡ช [ka](../../../ka/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฐ๐Ÿ‡ญ [km](../../../km/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [kn](../../../kn/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฑ๐Ÿ‡น [lt](../../../lt/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฑ๐Ÿ‡ป [lv](../../../lv/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [ml](../../../ml/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [mr](../../../mr/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฒ๐Ÿ‡พ [ms](../../../ms/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฒ๐Ÿ‡น [mt](../../../mt/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฒ๐Ÿ‡ฒ [my](../../../my/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ณ๐Ÿ‡ต [ne](../../../ne/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ณ๐Ÿ‡ฑ [nl](../../../nl/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ณ๐Ÿ‡ด [no](../../../no/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [or](../../../or/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [pa](../../../pa/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ต๐Ÿ‡ญ [phi](../../../phi/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ต๐Ÿ‡ฑ [pl](../../../pl/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ต๐Ÿ‡น [pt](../../../pt/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ง๐Ÿ‡ท [pt-BR](../../../pt-BR/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ท๐Ÿ‡ด [ro](../../../ro/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ท๐Ÿ‡บ [ru](../../../ru/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฑ๐Ÿ‡ฐ [si](../../../si/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ธ๐Ÿ‡ฐ [sk](../../../sk/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ธ๐Ÿ‡ฎ [sl](../../../sl/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ท๐Ÿ‡ธ [sr](../../../sr/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ธ๐Ÿ‡ช [sv](../../../sv/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฐ๐Ÿ‡ช [sw](../../../sw/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [ta](../../../ta/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [te](../../../te/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡น๐Ÿ‡ญ [th](../../../th/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡น๐Ÿ‡ท [tr](../../../tr/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡บ๐Ÿ‡ฆ [uk-UA](../../../uk-UA/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ต๐Ÿ‡ฐ [ur](../../../ur/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡บ๐Ÿ‡ฟ [uz](../../../uz/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ป๐Ÿ‡ณ [vi](../../../vi/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡ณ๐Ÿ‡ฌ [yo](../../../yo/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡จ๐Ÿ‡ณ [zh-CN](../../../zh-CN/docs/ops/RELEASE_CHECKLIST.md) ยท ๐Ÿ‡น๐Ÿ‡ผ [zh-TW](../../../zh-TW/docs/ops/RELEASE_CHECKLIST.md) --- > **์ตœ์ข… ์—…๋ฐ์ดํŠธ:** 2026-08-28 โ€” v3.8.51 > ์ž๋™ํ™”๋ฅผ ์œ„ํ•ด Claude Code ์Šคํ‚ฌ์„ ํ™œ์šฉํ•˜๋„๋ก ๋ฆด๋ฆฌ์Šค ํ๋ฆ„์„ ๊ฐ„์†Œํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค. > > **๋ฆด๋ฆฌ์Šค ์‚ฌ์ด์—๋„ ํ/๋ธŒ๋žœ์น˜๋ฅผ ์ •์ƒ ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜์„ธ์š”:** [RELEASE_GREEN.md](./RELEASE_GREEN.md)๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. > (`/green-prs` ์ œํ’ˆ๊ตฐ + `npm run check:release-green` + `/babysit` + ์•ผ๊ฐ„ ์‹คํ–‰). ์ด๋ฅผ > ์ฃผ๊ธฐ์ ์œผ๋กœ, ํŠนํžˆ ์ด ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ **์ „์—** ์ˆ˜ํ–‰ํ•˜๋ฉด ๋ฆด๋ฆฌ์Šค PR์„ ์ •์ƒ ์ƒํƒœ๋กœ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ## ์š”์•ฝ ```bash # 1. ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ + CHANGELOG ์ƒ์„ฑ(์Šคํ‚ฌ) /version-bump-cc patch # ๋˜๋Š” minor/major # 2. ๋กœ์ปฌ์—์„œ ํ’ˆ์งˆ ๊ฒŒ์ดํŠธ ์‹คํ–‰ npm run check # ๋ฆฐํŠธ + ํ…Œ์ŠคํŠธ npm run test:coverage # ์ „์ฒด ์ปค๋ฒ„๋ฆฌ์ง€ ๊ฒŒ์ดํŠธ(60/60/60/60) # 3. ๋นŒ๋“œ ๋ฐ ์Šค๋ชจํฌ ํ…Œ์ŠคํŠธ npm run build npm run test:e2e # ์„ ํƒ ์‚ฌํ•ญ์ด์ง€๋งŒ ๊ถŒ์žฅ # 4. ๋ฆด๋ฆฌ์Šค ์ƒ์„ฑ(์Šคํ‚ฌ) /generate-release-cc # 5. ๋ฐฐํฌ(์Šคํ‚ฌ) /deploy-vps-both-cc # ๋˜๋Š” akamai-cc / local-cc # 6. ๋ฆด๋ฆฌ์Šค ์ฆ๋น™ ์บก์ฒ˜(์Šคํ‚ฌ) /capture-release-evidences-cc ``` ## npm Trusted Publishing(v3.8.51๋ถ€ํ„ฐ ๊ธฐ๋ณธ๊ฐ’) โ€” ์š”์ฒญ ์‹œ ์Šคํ…Œ์ด์ง•, ๋Œ€์ฒด ์ˆ˜๋‹จ์œผ๋กœ ์ง์ ‘ ๊ฒŒ์‹œ `npm-publish.yml`์€ ๊ธฐ๋ณธ์ ์œผ๋กœ **npm Trusted Publishing(OIDC)**์„ ํ†ตํ•ด ๊ฒŒ์‹œํ•ฉ๋‹ˆ๋‹ค. `stage-npm` ์ž‘์—…(github-hosted)์€ ํ•ด๋‹น ์‹คํ–‰์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก GitHub์˜ id-token์„ ์ˆ˜๋ช…์ด ์งง์€ npm ์ž๊ฒฉ ์ฆ๋ช…์œผ๋กœ ๊ตํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ €์žฅ์†Œ ์‹œํฌ๋ฆฟ์— ์ˆ˜๋ช…์ด ๊ธด npm ํ† ํฐ์ด ํ•„์š”ํ•˜์ง€ ์•Š๊ณ , 2FA ํ”„๋กฌํ”„ํŠธ๋„ ์—†์œผ๋ฉฐ, ์ถœ์ฒ˜ ์ฆ๋ช…์ด ์ฒจ๋ถ€๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” 2FA๋ฅผ ๊ฑด๋„ˆ๋›ฐ๋Š” ํ† ํฐ์ด ํ์ง€๋จ์— ๋”ฐ๋ผ npm์ด ํ˜„์žฌ ํ—ˆ์šฉํ•˜๋Š” ์šฐํšŒ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. WS1.3 ๋ณด์žฅ(์œ ์ถœ๋œ ํ† ํฐ๋งŒ์œผ๋กœ๋Š” ๊ฒŒ์‹œํ•  ์ˆ˜ ์—†์Œ โ€” ์• ์ดˆ์— ํ† ํฐ์ด ์—†์Œ)์„ ์œ ์ง€ํ•˜๋ฉด์„œ, ํ”„๋กœ์ ํŠธ๊ฐ€ v3.8.48๊นŒ์ง€ ์‚ฌ์šฉํ•˜๋˜ ์™„์ „ ์ž๋™ํ™” ํ๋ฆ„์„ ๋ณต์›ํ•ฉ๋‹ˆ๋‹ค. **์ผํšŒ์„ฑ ์„ค์ •(์†Œ์œ ์ž):** npmjs.com โ†’ package `omniroute` โ†’ Settings โ†’ _Trusted Publisher_ โ†’ GitHub: owner `diegosouzapw`, repo `OmniRoute`, workflow `npm-publish.yml` (environment: none). ์ด ์„ค์ •์ด ์กด์žฌํ•˜๊ธฐ ์ „์—๋Š” ์ž๋™ ๋‹จ๊ณ„๊ฐ€ `ENEEDAUTH`์™€ ํ•จ๊ป˜ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์˜ `publish_mode=staged` ๋˜๋Š” `direct`๋กœ ๋‹ค์‹œ ๋””์ŠคํŒจ์น˜ํ•˜์„ธ์š”. ### ์Šคํ…Œ์ด์ง• ๊ฒŒ์‹œ(์š”์ฒญ ์‹œ โ€” `publish_mode=staged`) npm-publish ์›Œํฌํ”Œ๋กœ๋Š” ๋” ์ด์ƒ ์ง์ ‘ ๊ฒŒ์‹œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํŒจํ‚น๋œ tarball์„ ๋ถ€ํŒ…ํ•˜์—ฌ (`check:pack-boot`) ํ™•์ธํ•œ ๋‹ค์Œ `npm stage publish`๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ •ํ™•ํžˆ ๋™์ผํ•œ ๋ฐ”์ดํŠธ๊ฐ€ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ๋ณด๊ด€๋˜์ง€๋งŒ, ์†Œ์œ ์ž๊ฐ€ ์Šน์ธํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” **์„ค์น˜ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค**. ์‚ฌ๋žŒ์˜ 2FA ๊ฒŒ์ดํŠธ๋Š” ๊ฒ€์ฆ ์ „์ด ์•„๋‹ˆ๋ผ ๊ฒ€์ฆ ํ›„๋กœ ์ด๋™ํ–ˆ์Šต๋‹ˆ๋‹ค. **์›Œํฌํ”Œ๋กœ๊ฐ€ ์ •์ƒ ์™„๋ฃŒ๋œ ํ›„ ์†Œ์œ ์ž๊ฐ€ ์ˆ˜ํ–‰ํ•  ์ ˆ์ฐจ:** 1. `npm stage list omniroute` โ€” stage id๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค(์›Œํฌํ”Œ๋กœ ์š”์•ฝ์—๋„ ์ถœ๋ ฅ๋จ). 2. ์Šคํ…Œ์ด์ง•๋œ ๋ฐ”์ดํŠธ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค(๊ถŒ์žฅ): `npm stage download `๋ฅผ ์‹คํ–‰ํ•œ ๋‹ค์Œ, ๋‹ค์šด๋กœ๋“œํ•œ tarball์„ ์ž„์‹œ prefix์— ์„ค์น˜ํ•˜๊ณ  ๋ถ€ํŒ…ํ•ฉ๋‹ˆ๋‹ค(`npm run check:pack-boot`๋Š” CI์—์„œ ๋™์ผํ•œ packโ†’installโ†’boot ํŒ์ •์„ ์ž๋™ํ™”ํ•จ). 3. `npm stage approve ` โ€” 2FA ํ”„๋กฌํ”„ํŠธ ์Šน์ธ์ด ๊ณง ๊ฒŒ์‹œ์ž…๋‹ˆ๋‹ค. `npm stage reject `๋Š” ํ๊ธฐํ•ฉ๋‹ˆ๋‹ค. 4. ๊ฒŒ์‹œ ํ›„ ์•ˆ์ „๋ง: ๊ฒŒ์‹œ ํ›„ ๊ฒ€์ฆ ๋„๊ตฌ(v3.8.49 ๊ณ„ํš์˜ WS1.4)๋Š” ๊ณต๊ฐœ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์—์„œ ๊ฒŒ์‹œ๋œ ๋ฒ„์ „์„ ๊นจ๋—ํ•œ ์ปจํ…Œ์ด๋„ˆ์— ์„ค์น˜ํ•˜๊ณ  ๋ถ€ํŒ…ํ•ฉ๋‹ˆ๋‹ค. **๊ธด๊ธ‰ ๋Œ€์ฒด ์ˆ˜๋‹จ:** `publish_mode=direct`๋ฅผ ์‚ฌ์šฉํ•œ `workflow_dispatch`๋Š” ๊ธฐ์กด์˜ ์ฆ‰์‹œ `npm publish` ๋ฐฉ์‹์„ ๋ณต์›ํ•ฉ๋‹ˆ๋‹ค(์Šคํ…Œ์ด์ง• ์ž์ฒด๊ฐ€ ์˜ค์ž‘๋™ํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜๊ณ , ๊ทธ ์ด์œ ๋ฅผ ๊ธฐ๋กํ•˜์„ธ์š”). **์ผํšŒ์„ฑ ๊ฐ•ํ™”(์†Œ์œ ์ž, npmjs.com):** ์œ ์ถœ๋œ ์ˆ˜๋ช…์ด ๊ธด ํ† ํฐ์œผ๋กœ ์–ด๋””์„œ๋“  ์ง์ ‘ `npm publish`๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๋„๋ก `omniroute`์˜ Trusted Publisher๋ฅผ stage-only ๋ชจ๋“œ๋กœ ๊ตฌ์„ฑํ•˜์„ธ์š”. CI์—์„œ๋Š” ์Šคํ…Œ์ด์ง•๋งŒ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ์†Œ์œ ์ž์˜ 2FA๋ฅผ ํ†ตํ•ด์„œ๋งŒ ๋ฆด๋ฆฌ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. **์†์ƒ๋œ ์•„ํ‹ฐํŒฉํŠธ ๋Œ€์‘ ์ ˆ์ฐจ(๋ณ€๊ฒฝ ์—†์Œ):** ๊ธฐ๋ณธ์ ์œผ๋กœ ์ฆ‰์‹œ `npm deprecate omniroute@ " โ€” use "`๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค(๋ช‡ ๋ถ„์ด๋ฉด ์™„๋ฃŒ๋˜๋ฉฐ ๋˜๋Œ๋ฆด ์ˆ˜ ์žˆ์Œ). `npm unpublish`๋Š” 72์‹œ๊ฐ„ ์ด๋‚ด์ด๊ณ  ์ข…์† ํ•ญ๋ชฉ์ด ์—†๋Š” ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ ˆ๋Œ€๋กœ ์ฒซ ๋ฒˆ์งธ ์กฐ์น˜๋กœ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”. Docker์—์„œ๋Š” ๋ฒ„์ „ ํƒœ๊ทธ๋ฅผ ์ ˆ๋Œ€ ๋‹ค์‹œ ์ž‘์„ฑํ•˜์ง€ ๋งˆ์„ธ์š”. ๋กค๋ฐฑ์€ `latest`๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ •์ƒ์ธ digest๋ฅผ ๋‹ค์‹œ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. **Docker Hub `latest`(๋ชจ๋“  ์•ˆ์ • SemVer ๊ฒŒ์‹œ ์‹œ ํ•„์ˆ˜):** `docker-publish` ์›Œํฌํ”Œ๋กœ๋Š” ๋ฐ˜๋“œ์‹œ `X.Y.Z` ํƒœ๊ทธ๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•˜๋ฉฐ, `should-promote-latest.sh`๊ฐ€ ํ•ด๋‹น ๋ฒ„์ „์ด ๊ฐ€์žฅ ๋†’์€ ์•ˆ์ • SemVer์ž„์„ ํ™•์ธํ•˜๋ฉด ๋™์ผํ•œ **digest**๋กœ `:latest` ํƒœ๊ทธ๋„ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ž‘์—… ์™„๋ฃŒ ํ›„ Hub์˜ `latest` digest๋Š” ์ƒˆ SemVer digest์™€ ๊ฐ™์•„์•ผ ํ•˜๋ฉฐ, `last_updated`๋„ ๊ฐฑ์‹ ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฆด๋ฆฌ์Šค ๋…ธํŠธ์—์„œ git์—๋งŒ ์กด์žฌํ•˜๋Š” ์ˆ˜์ • ์‚ฌํ•ญ์„ ์„ค๋ช…ํ•˜๋ฉด์„œ `:latest`๋Š” ์ด์ „ ๋นŒ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ๋ฐฉ์น˜ํ•˜์ง€ ๋งˆ์„ธ์š”. Compose ๋น ๋ฅธ ์‹œ์ž‘์—์„œ๋Š” `:latest`๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, GitOps์—์„œ๋Š” ๊ณ„์† `X.Y.Z`๋กœ ๊ณ ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. [Docker ๋ฆด๋ฆฌ์Šค ์ฑ„๋„](../guides/DOCKER_GUIDE.md#release-channels)๊ณผ #10317์„ ์ฐธ์กฐํ•˜์„ธ์š”. ## ํ•ซํ”ฝ์Šค ํŒจ์ŠคํŠธ ๋ ˆ์ธ(๋ผ๋ฒจ `hotfix`) `hotfix` ๋ผ๋ฒจ์ด ์ง€์ •๋œ PR์€ ๋ฌด๊ฑฐ์šด CI ๋งคํŠธ๋ฆญ์Šค(9์ƒค๋“œ E2E, ์ปค๋ฒ„๋ฆฌ์ง€ ๋ž˜์นซ, quality-gate, quality-extended)๋ฅผ ๊ฑด๋„ˆ๋›ฐ๊ณ  ๋น ๋ฅด๊ณ  ์‹ ํ˜ธ๋„๊ฐ€ ๋†’์€ ๊ฒŒ์ดํŠธ์ธ ๋นŒ๋“œ, ์œ ๋‹› ์ƒค๋“œ, ํ†ตํ•ฉ, vitest, ๋ฆฐํŠธ/ํƒ€์ž… ๊ฒ€์‚ฌ, ๋ฌธ์„œ ๋™๊ธฐํ™”, `check:pack-artifact` ๋ฐ tarball ๋ถ€ํŒ… ์Šค๋ชจํฌ ํ…Œ์ŠคํŠธ(`check:pack-boot`)๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๋ชฉํ‘œ: ์•ฝ 33๋ถ„์ด ์•„๋‹Œ โ‰ค15๋ถ„ ๋‚ด ํ†ต๊ณผ. **์ง„์ž… ์ •์ฑ… โ€” ๋„ค ๊ฐ€์ง€ ๋ชจ๋‘ ํ•„์ˆ˜(Chromium/VS Code/Node ๊ธด๊ธ‰ ๋ ˆ์ธ์„ ๋ชจ๋ธ๋กœ ํ•จ):** 1. **์‹ฌ๊ฐ๋„**: ํ”„๋กœ๋•์…˜์ด ์ค‘๋‹จ๋œ ์ƒํƒœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๊ฒŒ์‹œ๋œ ์•„ํ‹ฐํŒฉํŠธ๊ฐ€ ๋ถ€ํŒ… ์‹œ ์ถฉ๋Œํ•˜๊ฑฐ๋‚˜, ๋ณด์•ˆ ์ˆ˜์ •์ด ํ•„์š”ํ•˜๊ฑฐ๋‚˜, ๋ฆด๋ฆฌ์Šค์˜ ๋ชจ๋“  ์‚ฌ์šฉ์ž๊ฐ€ ์˜ํ–ฅ์„ ๋ฐ›๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. "์ค‘์š”ํ•จ"์€ "์ค‘๋‹จ๋จ"์ด ์•„๋‹™๋‹ˆ๋‹ค. 2. **๊ถŒํ•œ**: ์ €์žฅ์†Œ ์†Œ์œ ์ž๋งŒ `hotfix` ๋ผ๋ฒจ์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ผ๋ฒจ ์ž์ฒด๊ฐ€ ์Šน์ธ์ž…๋‹ˆ๋‹ค. ์บ ํŽ˜์ธ PR์—์„œ ์ž์ฒด์ ์œผ๋กœ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. 3. **์ฆ๊ฑฐ**: PR ๋ณธ๋ฌธ์— ์ด์ „์— ์™„์ „ํžˆ ํ†ต๊ณผํ•œ ๋ฌด๊ฑฐ์šด ์‹คํ–‰(๊ฑด๋„ˆ๋›ด ์ž‘์—…์ด ์žฌ๊ฒ€์ฆํ•  ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ)๊ณผ ์ˆ˜์ • ์‚ฌํ•ญ ์ž์ฒด์˜ ์‹คํŒจ ํ›„ ํ†ต๊ณผ ํ…Œ์ŠคํŠธ๋ฅผ ๋งํฌํ•ฉ๋‹ˆ๋‹ค. 4. **๋ฒ”์œ„**: cherry-pick ์ „์šฉ์ž…๋‹ˆ๋‹ค. ์ตœ์†Œํ•œ์˜ ์ˆ˜์ •๋งŒ ํฌํ•จํ•˜๋ฉฐ, ๋ฆฌํŒฉํ„ฐ๋ง์ด๋‚˜ ๋ผ์›Œ ๋„ฃ๋Š” ๋ณ€๊ฒฝ์€ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฑด๋„ˆ๋›ด ์ปค๋ฒ„๋ฆฌ์ง€/๋ž˜์นซ ์˜์—ญ์€ ๋ฆด๋ฆฌ์Šค ๋ธŒ๋žœ์น˜์˜ ๋‹ค์Œ ์ „์ฒด ์‹คํ–‰์—์„œ ์žฌ๊ฒ€์ฆ๋ฉ๋‹ˆ๋‹ค(์ง€์†์ ์ธ ๋ฆด๋ฆฌ์Šค ํ†ต๊ณผ ์ƒํƒœ). ์ด ๋ ˆ์ธ์€ ๊ฒ€์ฆ์ด ์•„๋‹ˆ๋ผ ๋Œ€๊ธฐ๋งŒ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ ์ „์šฉ ๋ณ€๊ฒฝ ์‚ฌํ•ญ(๋ชจ๋“  ํŒŒ์ผ์ด `tests/` ์•„๋ž˜์— ์žˆ๊ณ  `tests/e2e/` ์•„๋ž˜์—๋Š” ์—†์Œ)์€ ๋ผ๋ฒจ ์—†์ด ์ž๋™์œผ๋กœ E2E ๋งคํŠธ๋ฆญ์Šค๋ฅผ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค. ## ์ƒ์„ธ ์ฒดํฌ๋ฆฌ์ŠคํŠธ ### ๋ฆด๋ฆฌ์Šค ์ „ - [ ] ์ด ๋ฆด๋ฆฌ์Šค๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ๋ชจ๋“  PR์ด `release/vX.Y.0`์— ๋ณ‘ํ•ฉ๋จ - [ ] ์ด ๋ฒ„์ „์˜ ๋ชจ๋“  ์—ด๋ฆฐ Linear/์ด์Šˆ ํ•ญ๋ชฉ์ด ์ข…๋ฃŒ๋˜์—ˆ๊ฑฐ๋‚˜ ๋‹ค์Œ ๋งˆ์ผ์Šคํ†ค์œผ๋กœ ์ด๋™๋จ - [ ] `release/vX.Y.0` ๋ธŒ๋žœ์น˜์—์„œ CI ํ†ต๊ณผ - [ ] ์ฝ”๋“œ์— `TODO(release)` ๋งˆ์ปค๊ฐ€ ์—†์Œ: `grep -r "TODO(release)" src/ open-sse/` - [ ] Docker ๋ฒ ์ด์Šค ์ด๋ฏธ์ง€๊ฐ€ ์ตœ์‹  ์ƒํƒœ์ž„(ํ˜„์žฌ `node:24.15.0-trixie-slim`) ### ๋ฒ„์ „ ๋ฐ ๋ณ€๊ฒฝ ๋กœ๊ทธ - [ ] `/version-bump-cc ` ์‹คํ–‰(Claude Code ์Šคํ‚ฌ) - `package.json`, `electron/package.json` ๋ฒ„์ „ ์ƒํ–ฅ - ๋งˆ์ง€๋ง‰ ํƒœ๊ทธ ์ดํ›„์˜ git ์ปค๋ฐ‹์—์„œ `CHANGELOG.md` ์žฌ์ƒ์„ฑ - README.md ๋ฐฐ์ง€ ์—…๋ฐ์ดํŠธ - [ ] CHANGELOG.md๋ฅผ ์ˆ˜๋™์œผ๋กœ ๊ฒ€ํ† ํ•˜๊ณ  ํ•„์š”ํ•˜๋ฉด ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋ฅผ ์ •๋ฆฌ - [ ] `CHANGELOG.md`์˜ ์ตœ์‹  semver ์„น์…˜์ด `package.json` ๋ฒ„์ „๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ - [ ] ํ–ฅํ›„ ์ž‘์—…์„ ์œ„ํ•ด `## [Unreleased]`๋ฅผ ๋ณ€๊ฒฝ ๋กœ๊ทธ์˜ ์ฒซ ๋ฒˆ์งธ ์„น์…˜์œผ๋กœ ์œ ์ง€ - [ ] `docs/openapi.yaml` ์—…๋ฐ์ดํŠธ โ†’ `info.version`์€ `package.json` ๋ฒ„์ „๊ณผ ์ผ์น˜ํ•ด์•ผ ํ•จ ### ์ฝ”๋“œ ํ’ˆ์งˆ - [ ] `npm run lint` โ€” ์˜ค๋ฅ˜ 0๊ฐœ(๊ฒฝ๊ณ ๋Š” ๊ธฐ์กด์— ์กด์žฌํ•จ) - [ ] `npm run typecheck:core` โ€” ๋ฌธ์ œ ์—†์Œ - [ ] `npm run typecheck:noimplicit:core` โ€” ๋ฌธ์ œ ์—†์Œ(์—„๊ฒฉ ๋ชจ๋“œ) - [ ] `npm run check:cycles` โ€” ์ˆœํ™˜ ์˜์กด์„ฑ ์—†์Œ - [ ] `npm run check:any-budget:t11` โ€” ์˜ˆ์‚ฐ ๋ฒ”์œ„ ๋‚ด - [ ] `npm run check:route-validation:t06` โ€” ๋ฌธ์ œ ์—†์Œ - [ ] `npm run check:node-runtime` โ€” ์ง€์›๋˜๋Š” ์ตœ์†Œ ๋Ÿฐํƒ€์ž„ ์ถฉ์กฑ(`src/shared/utils/nodeRuntimeSupport.ts`์˜ `SUPPORTED_NODE_RANGE`์— ๋”ฐ๋ผ `>=22.22.2 <23`, `>=24.0.0 <27`; `package.json`์˜ `engines`์™€ ์ผ์น˜) ### ํ…Œ์ŠคํŠธ - [ ] `npm run test:unit` โ€” ํ†ต๊ณผ - [ ] `npm run test:vitest` โ€” ํ†ต๊ณผ(MCP ์„œ๋ฒ„, autoCombo, ์บ์‹œ) - [ ] `npm run test:coverage` โ€” 60/60/60/60 ๊ฒŒ์ดํŠธ ์ถฉ์กฑ(๊ตฌ๋ฌธ/๋ผ์ธ/ํ•จ์ˆ˜/๋ถ„๊ธฐ) - [ ] `npm run test:integration` โ€” ํ†ต๊ณผ(๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด DB/ํ•ธ๋“ค๋Ÿฌ์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ๊ฒฝ์šฐ) - [ ] `npm run test:combo:matrix` โ€” ํ†ต๊ณผ(์ฝค๋ณด ์ „๋žต ๋งคํŠธ๋ฆญ์Šค: ๊ณต๊ฐœ๋œ 19๊ฐœ ๋ผ์šฐํŒ… ์ „๋žต ๋ชจ๋‘์˜ ์„ ํƒ ๊ฒฐ์ •์„ ๊ฒฐ์ •๋ก ์ ์œผ๋กœ ์ž…์ฆํ•จ. ์ฝค๋ณด ๋ผ์šฐํŒ…, ์ „๋žต ํ•ด์„ ๋˜๋Š” ํด๋ฐฑ ๋กœ์ง์„ ๋ณ€๊ฒฝํ•  ๋•Œ ์‹คํ–‰) - [ ] `RUN_COMBO_LIVE=1 npm run test:combo:live` โ€” **์„ ํƒ ์‚ฌํ•ญ/์ˆ˜๋™**(๊ฒŒ์ดํŠธ๋กœ ์ œํ•œ๋œ ์‹ค์ œ ์—…์ŠคํŠธ๋ฆผ ์Šค๋ชจํฌ ํ…Œ์ŠคํŠธ. VPS `root@192.168.0.15`์—์„œ ์ฝ๊ธฐ ์ „์šฉ DB ์Šค๋ƒ…์ƒท์„ ๊ฐ€์ ธ์˜ค๋ฉฐ, ์‹ค์ œ ๊ณต๊ธ‰์ž๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ํฌ๋ ˆ๋”ง์„ ์†Œ๋น„ํ•จ. CI์—์„œ๋Š” ์ ˆ๋Œ€ ์‹คํ–‰๋˜์ง€ ์•Š์œผ๋ฉฐ, ๊ฒŒ์ดํŠธ๊ฐ€ ์—†์œผ๋ฉด ๋ฌธ์ œ์—†์ด ๊ฑด๋„ˆ๋œ€) - [ ] `npm run test:combo:live:vps` โ€” **์„ ํƒ ์‚ฌํ•ญ/์ˆ˜๋™**(3๋‹จ๊ณ„ VPS ๋ผ์ด๋ธŒ ์Šค๋ชจํฌ ํ…Œ์ŠคํŠธ: ์ผ๋ฐ˜ Node ESM์„ ํ†ตํ•ด ๋ผ์ด๋ธŒ `.15` ์„œ๋ฒ„๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” 7๊ฐ€์ง€ HTTP ์‹œ๋‚˜๋ฆฌ์˜ค. `ssh root@192.168.0.15`๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ, `__live_test__*` ์ฝค๋ณด๋งŒ ์ƒ์„ฑ/์‚ญ์ œํ•จ. ์‹ค์ œ ๊ณต๊ธ‰์ž๋ฅผ ํ˜ธ์ถœํ•˜๋ฉฐ CI์—์„œ๋Š” ์ ˆ๋Œ€ ์‹คํ–‰๋˜์ง€ ์•Š์Œ) - [ ] `npm run test:e2e` โ€” ํ†ต๊ณผ(UI ๋ณ€๊ฒฝ) - [ ] `npm run test:protocols:e2e` โ€” ํ†ต๊ณผ(MCP/A2A ๋ณ€๊ฒฝ) - [ ] `npm run test:ecosystem` โ€” ํ†ต๊ณผ ### ํ›…(Husky ๊ฒ€์ฆ ์™„๋ฃŒ) Husky ํ›…์€ `.husky/`์— ์žˆ์œผ๋ฉฐ git ์ž‘์—… ์‹œ ์ž๋™์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. - **pre-commit:** `npx lint-staged + node scripts/check/check-docs-sync.mjs + npm run check:any-budget:t11` - **pre-push:** ๋น ๋ฅด๊ณ  ๊ฒฐ์ •๋ก ์ ์ธ ๊ฒŒ์ดํŠธ โ€” `npm run check:any-budget:t11 && npm run check:tracked-artifacts`(2026-06-13 ํ™œ์„ฑํ™”). ์˜๋„์ ์œผ๋กœ `test:unit`์€ ์ œ์™ธ๋จ(๋А๋ฆฌ๋ฉฐ CI `test-unit` ์ž‘์—…์—์„œ ์ฒ˜๋ฆฌ๋จ). - ๋ฆด๋ฆฌ์Šค ๋ธŒ๋žœ์น˜๋ฅผ ํ‘ธ์‹œํ•˜๊ธฐ ์ „์— `npm run test:unit`์„ ์ˆ˜๋™์œผ๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ํ›…์ด ์‹คํŒจํ•˜๋ฉด `--no-verify`๋กœ ์šฐํšŒํ•˜์ง€ ๋ง๊ณ  ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค. ### Conventional Commits ๋ฆด๋ฆฌ์Šค์— ํฌํ•จ๋˜๋Š” ๋ชจ๋“  ์ปค๋ฐ‹์€ `type(scope): subject` ํ˜•์‹์„ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค. **์œ ํšจํ•œ ํƒ€์ž…:** `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `perf`, `style`, `ci` **์œ ํšจํ•œ ๋ฒ”์œ„:** `db`, `sse`, `oauth`, `dashboard`, `api`, `cli`, `docker`, `ci`, `mcp`, `a2a`, `memory`, `skills`, `cloud-agent`, `guardrails`, `compression`, `auto-combo`, `resilience`, `providers`, `executors`, `translator`, `domain`, `authz` ํ˜ธํ™˜์„ฑ์„ ๊นจ๋Š” ๋ณ€๊ฒฝ: `BREAKING CHANGE:` ํ‘ธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ฒ”์œ„ ๋’ค์— `!`๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: `feat(api)!: drop /v0`). ### ๋ฌธ์„œ - [ ] `npm run check:docs-sync` ํ†ต๊ณผ(์ปค๋ฐ‹ ์ „ ํ›…์—์„œ ์ž๋™ ์‹คํ–‰) - [ ] `npm run check:docs-all` ํ†ต๊ณผ(ํ†ตํ•ฉ ๊ฒ€์‚ฌ: docs-sync + docs-counts + env-doc-sync + deprecated-versions + doc-links) - [ ] `npm run check:env-doc-sync`๊ฐ€ ์ข…๋ฃŒ ์ฝ”๋“œ 0์œผ๋กœ ์™„๋ฃŒ โ€” ์ฝ”๋“œ โ†” `.env.example` โ†” `docs/reference/ENVIRONMENT.md` ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ณ„์•ฝ์ด ์˜จ์ „ํ•จ - [ ] `npm run check:doc-links`๊ฐ€ ์ข…๋ฃŒ ์ฝ”๋“œ 0์œผ๋กœ ์™„๋ฃŒ โ€” ๊ตฌ์กฐ ๋ณ€๊ฒฝ ํ›„ ๊นจ์ง„ ๋‚ด๋ถ€ ๋งˆํฌ๋‹ค์šด ์ฐธ์กฐ๊ฐ€ ์—†์Œ - [ ] ์Šคํ† ๋ฆฌ์ง€/๋Ÿฐํƒ€์ž„ ๋ถˆ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด `docs/architecture/ARCHITECTURE.md` ๊ฒ€ํ†  - [ ] ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋ฐ ์šด์˜ ๊ด€๋ จ ๋ถˆ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด `docs/guides/TROUBLESHOOTING.md` ๊ฒ€ํ†  - [ ] `.env.example`์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ: `docs/reference/ENVIRONMENT.md` ์—…๋ฐ์ดํŠธ - [ ] ์ƒˆ ๊ธฐ๋Šฅ์— UI๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ: `docs/guides/USER_GUIDE.md`์— ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ์–ธ๊ธ‰ - [ ] ์ƒˆ ๊ธฐ๋Šฅ์— API๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ: `docs/reference/API_REFERENCE.md` + `docs/openapi.yaml` ์—…๋ฐ์ดํŠธ - [ ] ์ƒˆ ๊ธฐ๋Šฅ์ด ๋ชจ๋“ˆ์ธ ๊ฒฝ์šฐ: ์ „์šฉ `docs/.md`๊ฐ€ ์กด์žฌ - [ ] ํ˜ธํ™˜์„ฑ์„ ๊นจ๋Š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ๋Š” ๊ฒฝ์šฐ: `docs/guides/TROUBLESHOOTING.md`์— ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ฐธ๊ณ  ์‚ฌํ•ญ ์ถ”๊ฐ€ ### i18n - [ ] `npm run i18n:check`๊ฐ€ ์ข…๋ฃŒ ์ฝ”๋“œ 0์œผ๋กœ ์™„๋ฃŒ โ€” ๋ฒˆ์—ญ ์ƒํƒœ(`.i18n-state.json`)๊ฐ€ ์›๋ณธ ๋ฌธ์„œ์™€ ๋™๊ธฐํ™”๋จ(์—„๊ฒฉ ๋ชจ๋“œ์—์„œ๋Š” ๋ณ€๊ฒฝ๋œ ์›๋ณธ์ด ์—†์–ด์•ผ ํ•จ. ๋ง‰๋ฐ”์ง€ ๋ฌธ์„œ ์ˆ˜์ •์—๋Š” ๊ฒฝ๊ณ  ๋ชจ๋“œ ์•ˆ๋‚ด๋ฅผ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ํƒœ๊ทธ ์ƒ์„ฑ ์ „์—๋Š” 0์ด์–ด์•ผ ํ•จ) - [ ] `npm run i18n:check-ui-coverage`๊ฐ€ ์ข…๋ฃŒ ์ฝ”๋“œ 0์œผ๋กœ ์™„๋ฃŒ โ€” ๋ชจ๋“  UI ๋กœ์ผ€์ผ์ด 80% ์ด์ƒ์˜ ์ปค๋ฒ„๋ฆฌ์ง€ ๊ธฐ์ค€์„ ์ถฉ์กฑ - [ ] `npm run i18n:sync-ui:dry`๊ฐ€ 42๊ฐœ ๋ชจ๋“  ๋กœ์ผ€์ผ์—์„œ ๋ˆ„๋ฝ๋œ ํ‚ค 0๊ฐœ๋ฅผ ๋ณด๊ณ  - [ ] ์˜์–ด ์›๋ณธ ๋ฌธ์„œ๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ ํƒœ๊ทธ ์ƒ์„ฑ ์ „์— `npm run i18n:run` ์‹คํ–‰(`.env`์— `OMNIROUTE_TRANSLATION_API_KEY` ํ•„์š”) - [ ] ์‚ฌ์†Œํ•œ ๋ฒˆ์—ญ ๊ธฐ์—ฌ๋Š” ๋‹ค์Œ ๋ฆด๋ฆฌ์Šค๋กœ ์—ฐ๊ธฐ ๊ฐ€๋Šฅ(CHANGELOG์—์„œ ์ถ”์ ) ### ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ - [ ] `src/lib/db/migrations/`์— ์ƒˆ ํŒŒ์ผ์ด ์žˆ๋Š” ๊ฒฝ์šฐ: - [ ] ๊ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์ด ๋ฉฑ๋“ฑ์„ฑ์„ ๊ฐ€์ง(`CREATE TABLE IF NOT EXISTS` ๋“ฑ) - [ ] ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์ด ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ž˜ํ•‘๋จ - [ ] ๋ฒˆํ˜ธ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ง€์ •๋จ(์ˆœ์„œ์— ๋ˆ„๋ฝ ์—†์Œ) - [ ] ์ƒˆ ์„ค์น˜์—์„œ ํ…Œ์ŠคํŠธ: `~/.omniroute/omniroute.db`๋ฅผ ์‚ญ์ œํ•˜๊ณ  `npm run dev` ์‹คํ–‰ - [ ] ๊ธฐ์กด ์„ค์น˜์—์„œ ํ…Œ์ŠคํŠธ: DB๋ฅผ ๋ฐฑ์—…ํ•˜๊ณ  ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์‹คํ–‰ํ•œ ๋’ค ์Šคํ‚ค๋งˆ ํ™•์ธ - [ ] ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์ด ํ…Œ์ด๋ธ”์„ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ WAL ํŒŒ์ผ(`-wal`, `-shm`)์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ๋จ ### ์ œ๊ณต์ž ์นดํƒˆ๋กœ๊ทธ(Zod ๊ฒ€์ฆ) - [ ] `src/shared/constants/providers.ts`์˜ Zod ์Šคํ‚ค๋งˆ๊ฐ€ ๋กœ๋“œ ์‹œ ์œ ํšจํ•จ - [ ] ๋ชจ๋“  ์ œ๊ณต์ž์— ํ•„์ˆ˜ ํ•„๋“œ(`id`, `label`, `kind` ๋“ฑ)๊ฐ€ ์žˆ์Œ - [ ] ์ƒˆ๋กœ์šด ๋ฌด๋ฃŒ ์ œ๊ณต์ž์— `freeNote`๊ฐ€ ์ œ๊ณต๋จ - [ ] OAuth ์ œ๊ณต์ž์˜ `oauthConfig`๊ฐ€ `src/lib/oauth/constants/oauth.ts`์— ๋“ฑ๋ก๋จ - [ ] ์ƒˆ ์ œ๊ณต์ž๋ฅผ ์ถ”๊ฐ€ํ•œ ๊ฒฝ์šฐ: `open-sse/executors/`์— ํ•ด๋‹น ์‹คํ–‰๊ธฐ ์ถ”๊ฐ€ - [ ] OpenAI ํ˜•์‹์ด ์•„๋‹Œ ๊ฒฝ์šฐ: `open-sse/translator/`์— ๋ณ€ํ™˜๊ธฐ ์ถ”๊ฐ€ - [ ] ๋ชจ๋ธ์ด `open-sse/config/providerRegistry.ts`์— ๋“ฑ๋ก๋จ - [ ] `tests/unit/`์˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์—์„œ ์ œ๊ณต์ž ๋ถ„๋ฅ˜ ๋ฐ ๋ผ์šฐํŒ…์„ ๋‹ค๋ฃธ ### ๋ฐ์Šคํฌํ†ฑ(Electron) `electron/`์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ: - [ ] `npm run electron:smoke:packaged` ํ†ต๊ณผ - [ ] `:win`, `:mac`, `:linux` ์ค‘ ํ•˜๋‚˜ ์ด์ƒ์˜ ๋นŒ๋“œ ํ…Œ์ŠคํŠธ - [ ] ์ฝ”๋“œ ์„œ๋ช… ์‹œ ์ธ์ฆ์„œ๊ฐ€ ๋งŒ๋ฃŒ๋˜์ง€ ์•Š์Œ - [ ] `electron/package.json` ๋ฒ„์ „์ด ๋ฃจํŠธ `package.json`๊ณผ ์ผ์น˜ - [ ] `stable`๋กœ ๋ฆด๋ฆฌ์Šคํ•˜๋Š” ๊ฒฝ์šฐ ์ž๋™ ์—…๋ฐ์ดํŠธ ์ฑ„๋„ ํฌ์ธํ„ฐ ์—…๋ฐ์ดํŠธ ### ๋นŒ๋“œ ๋ ˆ์ด์•„์›ƒ ์ €์žฅ์†Œ๋Š” ์„œ๋กœ ๊ตฌ๋ถ„๋˜๋Š” ์„ธ ๊ฐœ์˜ ์ถœ๋ ฅ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ ˆ๋Œ€ ํ˜ผ๋™ํ•˜์ง€ ๋งˆ์„ธ์š”. | ๋””๋ ‰ํ„ฐ๋ฆฌ | ์šฉ๋„ | ์ถ”์  ์—ฌ๋ถ€ | | --------- | -------------------------------------------------- | ------------------ | | `src/` | ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์†Œ์Šค(TypeScript / TSX) | ์˜ˆ | | `.build/` | ๋นŒ๋“œ ์ค‘๊ฐ„ ์‚ฐ์ถœ๋ฌผ โ€” `next build` ์ถœ๋ ฅ(`distDir`) | ์•„๋‹ˆ์š”(gitignored) | | `dist/` | ๋ฐฐํฌ ๊ฐ€๋Šฅํ•œ npm ๋ฒˆ๋“ค โ€” `assembleStandalone`๋กœ ์กฐ๋ฆฝ | ์•„๋‹ˆ์š”(gitignored) | > **์šด์˜์ž ์ฐธ๊ณ :** ์›๊ฒฉ VPS ์ด๋ฏธ์ง€ ๋””๋ ‰ํ„ฐ๋ฆฌ๋Š” ๊ณ„์† `/usr/lib/node_modules/omniroute/app/`์ž…๋‹ˆ๋‹ค. > **์ €์žฅ์†Œ ๋‚ด๋ถ€** ๋นŒ๋“œ ์ถœ๋ ฅ๋งŒ ์ด๋™ํ–ˆ์Šต๋‹ˆ๋‹ค(`app/` โ†’ `dist/`). ๋ฐฐํฌ ์Šคํ‚ฌ์€ `dist/`์˜ > ๋‚ด์šฉ์„ ์›๊ฒฉ `app/` ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ rsyncํ•˜๋ฏ€๋กœ VPS ๊ฒฝ๋กœ๋ฅผ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. **๋‹จ์ผ ๋นŒ๋“œ ํ๋ฆ„:** ``` npm run build:release โ””โ”€ rm -rf .build dist (์ •๋ฆฌ) โ””โ”€ next build โ†’ .build/next/ (์ค‘๊ฐ„ ์‚ฐ์ถœ๋ฌผ) โ””โ”€ assembleStandalone (standalone + static + public + natives๋ฅผ dist/๋กœ ๋ณต์‚ฌ) โ””โ”€ dist/BUILD_SHA ์ž‘์„ฑ (HEAD ์„ผํ‹ฐ๋„) ``` ๋ฐฐํฌ๋ฅผ ์œ„ํ•ด `npm run build`๋ฅผ ์‹คํ–‰ํ•œ ๋’ค ๋ณ„๋„๋กœ `npm run build:cli`๋ฅผ ์‹คํ–‰ํ•˜์ง€ ๋งˆ์„ธ์š”. ํ•œ ๋ฒˆ์˜ ๋ช…๋ น์œผ๋กœ ํด๋ฆฐ ์žฌ๋นŒ๋“œ์™€ ์„ผํ‹ฐ๋„ ์ƒ์„ฑ์„ ์ˆ˜ํ–‰ํ•˜๋Š” `npm run build:release`๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ### ์•„ํ‹ฐํŒฉํŠธ ๊ฒ€์ฆ - [ ] `npm run build:release`๊ฐ€ ์„ฑ๊ณตํ•˜๊ณ  `dist/BUILD_SHA` == `git rev-parse --short HEAD` - [ ] `npm run check:pack-artifact`๊ฐ€ ๊นจ๋—ํ•˜๊ฒŒ ํ†ต๊ณผ โ€” `app.__qa_backup`, `scripts/scratch`, `package-lock.json` ๋˜๋Š” ๊ธฐํƒ€ ๋กœ์ปฌ ์ž”์—ฌ๋ฌผ์ด ์—†์Œ - [ ] ๋นŒ๋“œ ํ›„ `dist/server.js`๊ฐ€ ์กด์žฌ - [ ] ์„ ํƒ์  ๋กœ์ปฌ ํŒจํ‚ค์ง€ ๋Ÿฐํƒ€์ž„ ์Šค๋ชจํฌ ํ…Œ์ŠคํŠธ: `npm run dev:candidate -- build` ํ›„ `npm run dev:candidate -- validate`๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๊ฒฉ๋ฆฌ๋œ `DATA_DIR`์—์„œ ํŒจํ‚ค์ง•๋œ tarball์„ ๋ถ€ํŒ…ํ•˜๊ณ  `/api/health` + `/v1/models`๋ฅผ ๊ฒ€์‚ฌํ•จ([๊ธฐ์—ฌ ๊ณจ๋“  ํŒจ์Šค](CONTRIBUTION_GOLDEN_PATH.md#local-candidate-loop) ์ฐธ์กฐ) ### ํƒœ๊ทธ ์ƒ์„ฑ ๋ฐ ๋ฆด๋ฆฌ์Šค - [ ] `/generate-release-cc` ์‹คํ–‰(Claude Code ์Šคํ‚ฌ): - `vX.Y.Z` ํƒœ๊ทธ ์ƒ์„ฑ - ํƒœ๊ทธ์™€ ๋ธŒ๋žœ์น˜ ํ‘ธ์‹œ - ๋ณ€๊ฒฝ ๋กœ๊ทธ ๋ณธ๋ฌธ์œผ๋กœ GitHub Release ์ƒ์„ฑ - Electron ์„ค์น˜ ํ”„๋กœ๊ทธ๋žจ ์ฒจ๋ถ€(๋นŒ๋“œํ•œ ๊ฒฝ์šฐ) - [ ] ๋˜๋Š” ์ˆ˜๋™์œผ๋กœ ์‹คํ–‰: ```bash git tag -a vX.Y.Z -m "Release vX.Y.Z" git push origin vX.Y.Z gh release create vX.Y.Z --notes-from-tag ``` ### ๋ฐฐํฌ ๋ฐฐํฌ ์Šคํ‚ฌ์€ ๊ฒฝ๋Ÿ‰ rsync ํ๋ฆ„์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. `npm pack`์ด๋‚˜ `npm i -g`๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค: - [ ] ๋Œ€์ƒ๊ณผ ์ผ์น˜ํ•˜๋Š” ๋ฐฐํฌ ์Šคํ‚ฌ ์‚ฌ์šฉ: - `/deploy-vps-local-cc` โ€” ๋กœ์ปฌ VPS (192.168.0.15) - `/deploy-vps-akamai-cc` โ€” Akamai VPS (69.164.221.35) - `/deploy-vps-both-cc` โ€” ๋‘˜ ๋‹ค - [ ] ๋ฐฐํฌ ์ „์— `dist/BUILD_SHA` == `git rev-parse --short HEAD`์ธ์ง€ ํ™•์ธ - [ ] ๋นŒ๋“œ๋Š” `node_modules`๊ฐ€ ์‹ค์ œ๋กœ ์กด์žฌํ•˜๋Š” ์œ„์น˜์—์„œ ์‹คํ–‰ํ•ด์•ผ ํ•จ(๋ฉ”์ธ ์ฒดํฌ์•„์›ƒ ๋˜๋Š” `npm ci`๋ฅผ ์‹คํ–‰ํ•œ worktree โ€” ์‹ฌ๋ณผ๋ฆญ ๋งํฌ๋กœ ์—ฐ๊ฒฐ๋œ worktree๋Š” ๋ถˆ๊ฐ€) - [ ] ๋ฐฐํฌ๋œ ์ธ์Šคํ„ด์Šค ์Šค๋ชจํฌ ํ…Œ์ŠคํŠธ: - `/dashboard/health` ์—ด๊ธฐ โ†’ ๋ฒ„์ „ ๋ฌธ์ž์—ด์ด ๋ฆด๋ฆฌ์Šค์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ - ์•Œ๋ ค์ง„ ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ๋Œ€์ƒ์œผ๋กœ `/v1/chat/completions` ์š”์ฒญ ์‹คํ–‰ - `/api/monitoring/health`๊ฐ€ `CLOSED` ํšŒ๋กœ ์ฐจ๋‹จ๊ธฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€ ํ™•์ธ - MCP ์ „์†ก์ด ์‘๋‹ตํ•˜๋Š”์ง€ ํ™•์ธ(`/mcp` HTTP, `/mcp-sse` SSE) ### ๋ฆด๋ฆฌ์Šค ํ›„ - [ ] `/capture-release-evidences-cc` ์‹คํ–‰(Claude Code ์Šคํ‚ฌ) - ์ƒˆ ๊ธฐ๋Šฅ์˜ WebP ์Šคํฌ๋ฆฐ์ƒท/๋…นํ™” ์บก์ฒ˜ - ๋ฆด๋ฆฌ์Šค ๋…ธํŠธ/๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ์— ์ฒจ๋ถ€ - [ ] GitHub Discussions/Discord์— ๋ฆด๋ฆฌ์Šค ๊ณต์ง€ ๊ฒŒ์‹œ - [ ] ๋‹ค์Œ ๋ฒ„์ „์˜ ๋งˆ์ผ์Šคํ†ค ์ƒ์„ฑ - [ ] ์ค‘์š” ๋ฆด๋ฆฌ์Šค์ธ ๊ฒฝ์šฐ: ํ† ๋ก ์„ ๊ณ ์ •ํ•˜๊ฑฐ๋‚˜ ์•ฑ ๋‚ด ๋ฐฐ๋„ˆ์šฉ `news.json`์— ๊ฒŒ์‹œ ### Radar ๊ณต๊ฐœ ์ถœ์‹œ ๊ฒŒ์ดํŠธ Radar ๊ณต์ง€๋Š” ์˜๋„์ ์œผ๋กœ `active: false` ์ƒํƒœ๋กœ ์ปค๋ฐ‹๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ๋ชจ๋“  ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฆ๋น™์ด ์™„๋ฃŒ๋œ ํ›„ ๋ณ„๋„์˜ ๋ณ€๊ฒฝ์œผ๋กœ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค: - [ ] ์Šคํƒ๋œ ๋ชจ๋“  Radar PR์ด ๋ณ‘ํ•ฉ๋˜๊ณ  ๋ฆด๋ฆฌ์Šค ํŒ CI๊ฐ€ ํ†ต๊ณผํ–ˆ๋Š”์ง€ ํ™•์ธ - [ ] `RADAR_ENABLED`๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”๋œ ์ƒํƒœ์—์„œ OSS Radar ๊ฒฝ๋กœ๋ฅผ ๋ฐฐํฌํ•˜๊ณ  ์Šค๋ชจํฌ ํ…Œ์ŠคํŠธ - [ ] ์ง€์ •๋œ Radar ํ˜ธ์ŠคํŠธ์—์„œ `GET /planos`, `/termos`, `/privacidade`, `/reembolso` ์Šค๋ชจํฌ ํ…Œ์ŠคํŠธ - [ ] ๋น„๊ณต๊ฐœ ์„œ๋น„์Šค์— ์šด์˜์ž ์‹ ์›/์—ฐ๋ฝ์ฒ˜/์ฃผ์†Œ ๋ฐ ์†Œ์œ ์ž๊ฐ€ ์Šน์ธํ•œ ๋ฒ•๋ฅ  ๊ฒ€ํ†  ๊ธฐ๋ก - [ ] ํ…Œ์ŠคํŠธ ๋ชจ๋“œ์—์„œ๋งŒ Stripe Checkout ๋ฐ ์„œ๋ช…๋œ webhook ํ…Œ์ŠคํŠธ - [ ] ์Šน์ธ๋œ ๋ฐœ์‹ ์ž/๋„๋ฉ”์ธ์œผ๋กœ ์•”ํ˜ธํ™”๋œ ํŠธ๋žœ์žญ์…˜ ์ด๋ฉ”์ผ 1๊ฑด์˜ ์ „์†ก ํ…Œ์ŠคํŠธ - [ ] ๋ฐฑ์—… ๋ณต์› ๋ฐ ๊ฐ๋…ํ•˜์— ์˜ˆ์‚ฐ ํ•œ๋„๊ฐ€ ์ ์šฉ๋œ ์—ฐ๊ตฌ ์‹คํ–‰ 1ํšŒ๋ฅผ ์ž…์ฆ - [ ] ๊ธฐ๋ถ€ ์ฆ๋น™์„ ์ˆ˜๋ฝํ•˜๊ธฐ ์ „์— BRL/PIX ๊ฒ€ํ†  ์ •์ฑ… ์Šน์ธ - [ ] ์•ž์„  ๊ฒŒ์ดํŠธ๋ฅผ ๋ชจ๋‘ ํ†ต๊ณผํ•œ ํ›„์—๋งŒ ๊ณต๊ฐœ Checkout์„ ํ™œ์„ฑํ™”ํ•œ ๋‹ค์Œ, ์ƒˆ๋กœ์šด `news.json` ID ํ™œ์„ฑํ™” - [ ] Home ๋ฐฐ๋„ˆ๊ฐ€ ํ˜„์ง€ํ™”๋œ ๋ฌธ๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ด์ „ ID๋ฅผ ๋‹ซ์€ ํ›„ ์ƒˆ ID๊ฐ€ ๋‹ค์‹œ ํ‘œ์‹œ๋˜๋Š”์ง€ ํ™•์ธ ## ์ž„๋ฒ ๋””๋“œ ์„œ๋น„์Šค ์Šค๋ชจํฌ ํ…Œ์ŠคํŠธ (v3.8.4+) ์ž„๋ฒ ๋””๋“œ ์„œ๋น„์Šค ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ํฌํ•จ๋œ ๋ฆด๋ฆฌ์Šค๋ฅผ ๋ฐฐํฌํ•˜๊ธฐ ์ „์— ๋‹ค์Œ์„ ํ™•์ธํ•˜์„ธ์š”. ### ์ƒˆ DB ๋ถ€ํŒ… (๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ถฉ๋Œ ๊ฐ์ง€ โ€” v3.8.4 ํ•ซํ”ฝ์Šค ์ดํ›„ ์ถ”๊ฐ€๋จ) - [ ] `DATA_DIR=$(mktemp -d) npm start &` โ€” ๋ถ€ํŒ…๋  ๋•Œ๊นŒ์ง€ 10์ดˆ ๋Œ€๊ธฐ - [ ] `curl -s http://127.0.0.1:20128/api/services/9router/status | jq '.tool'`์ด `"9router"`๋ฅผ ๋ฐ˜ํ™˜ํ•จ(404 ๋˜๋Š” 500์ด ์•„๋‹ˆ์–ด์•ผ ํ•จ). ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ `071_services.sql`์ด ์ ์šฉ๋˜๊ณ  ํ–‰์ด ์‹œ๋”ฉ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. - [ ] `sqlite3 $DATA_DIR/storage.sqlite "PRAGMA table_info(version_manager);" | grep -E "provider_expose|logs_buffer_path|last_sync_at"`๊ฐ€ 3๊ฐœ ํ–‰์„ ๋ฐ˜ํ™˜ํ•จ. - [ ] `sqlite3 $DATA_DIR/storage.sqlite "PRAGMA table_info(webhooks);" | grep -E "kind|metadata_encrypted"`๊ฐ€ 2๊ฐœ ํ–‰์„ ๋ฐ˜ํ™˜ํ•จ(`070_webhooks_kind_metadata.sql`์ด ์ ์šฉ๋˜์—ˆ๋Š”์ง€ ๊ฒ€์ฆ). - [ ] `node --import tsx/esm --test tests/unit/db/no-migration-collisions.test.ts`๊ฐ€ ํ†ต๊ณผํ•จ โ€” ํ–ฅํ›„ ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ### 9Router - [ ] `POST /api/services/9router/install`์ด 2๋ถ„ ์ด๋‚ด์— `installedVersion`๊ณผ ํ•จ๊ป˜ 200์„ ๋ฐ˜ํ™˜ํ•จ - [ ] `POST /api/services/9router/start`๊ฐ€ 30์ดˆ ์ด๋‚ด์— 200๊ณผ `state: "running"`์„ ๋ฐ˜ํ™˜ํ•จ - [ ] `GET /api/services/9router/status`๊ฐ€ `health: "healthy"`๋ฅผ ๋ณด๊ณ ํ•จ - [ ] `"model": "9router/auto/..."`์ด ํฌํ•จ๋œ `POST /v1/chat/completions`๊ฐ€ 200์„ ๋ฐ˜ํ™˜ํ•จ(9Router๋ฅผ ํ†ตํ•œ ์—”๋“œํˆฌ์—”๋“œ ๋ผ์šฐํŒ…) - [ ] `GET /dashboard/providers/services/9router/embed/dashboard`๊ฐ€ ํ”„๋ก์‹œ ๋‚ด๋ถ€์— 9Router ๋„ค์ดํ‹ฐ๋ธŒ UI๋ฅผ ๋ Œ๋”๋งํ•จ(์ง์ ‘์ ์ธ `127.0.0.1:port` iframe์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ) - [ ] `POST /api/services/9router/rotate-key`๊ฐ€ `{ keyRotated: true }`๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์„œ๋น„์Šค๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์žฌ์‹œ์ž‘๋จ - [ ] `POST /api/services/9router/stop`์ด 200๊ณผ `state: "stopped"`๋ฅผ ๋ฐ˜ํ™˜ํ•จ - [ ] `GET /api/services/9router/logs?tail=50`์ด ์ตœ๊ทผ ๋กœ๊ทธ ํ–‰์„ ํฌํ•จํ•œ `snapshot` ์ด๋ฒคํŠธ๊ฐ€ ์žˆ๋Š” SSE ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜ํ™˜ํ•จ - [ ] PATH์— `npm`์ด ์—†๋Š” ํ™˜๊ฒฝ์—์„œ ์„ค์น˜ํ•  ๊ฒฝ์šฐ ์นœ์ ˆํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€(์Šคํƒ ํŠธ๋ ˆ์ด์Šค๊ฐ€ ์•„๋‹Œ ๋ฉ”์‹œ์ง€)์™€ ํ•จ๊ป˜ 500์„ ๋ฐ˜ํ™˜ํ•จ ### CLIProxyAPI - [ ] `POST /api/services/cliproxy/install`์ด 2๋ถ„ ์ด๋‚ด์— 200์„ ๋ฐ˜ํ™˜ํ•จ - [ ] `POST /api/services/cliproxy/start`๊ฐ€ 30์ดˆ ์ด๋‚ด์— 200๊ณผ `state: "running"`์„ ๋ฐ˜ํ™˜ํ•จ - [ ] `GET /api/services/cliproxy/status`๊ฐ€ `health: "healthy"`๋ฅผ ๋ณด๊ณ ํ•จ - [ ] `POST /api/services/cliproxy/stop`์ด 200๊ณผ `state: "stopped"`๋ฅผ ๋ฐ˜ํ™˜ํ•จ - [ ] `GET /api/services/cliproxy/logs?tail=50`์ด SSE ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜ํ™˜ํ•จ ### ๋ณด์•ˆ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ - [ ] `curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:20128/api/services/9router/start`๊ฐ€ `403 LOCAL_ONLY`๋ฅผ ๋ฐ˜ํ™˜ํ•จ - [ ] `curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:20128/api/services/cliproxy/start`๊ฐ€ `403 LOCAL_ONLY`๋ฅผ ๋ฐ˜ํ™˜ํ•จ - [ ] `/api/services/*`์˜ ์˜ค๋ฅ˜ ์‘๋‹ต์— `err.stack`์ด๋‚˜ ์ ˆ๋Œ€ ํŒŒ์ผ ๊ฒฝ๋กœ๊ฐ€ ํฌํ•จ๋˜์ง€ ์•Š์Œ ## v3.8.0+ ํ™•์ธ ์‚ฌํ•ญ v3.8.x ๋ฆด๋ฆฌ์Šค๋ฅผ ๋ฐฐํฌํ•˜๊ธฐ ์ „์— ๋‹ค์Œ ์ถ”๊ฐ€ ํ•ญ๋ชฉ์„ ํ™•์ธํ•˜์„ธ์š”. - [ ] `omniroute --tray`๊ฐ€ macOS์—์„œ ๋ถ€ํŒ…๋จ(systray2๊ฐ€ `~/.omniroute/runtime/`์— ์„ค์น˜๋จ) - [ ] `omniroute --tray`๊ฐ€ Linux์—์„œ ๋ถ€ํŒ…๋จ(DISPLAY ํ•„์š”, ์„ค์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ •์ƒ์ ์œผ๋กœ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ) - [ ] `omniroute --tray`๊ฐ€ Windows์—์„œ ๋ถ€ํŒ…๋จ(PowerShell NotifyIcon ์‚ฌ์šฉ, ์ถ”๊ฐ€ ๋ฐ”์ด๋„ˆ๋ฆฌ ์—†์Œ) - [ ] `omniroute config tray enable`์ด ์ž๋™ ์‹œ์ž‘ ํ•ญ๋ชฉ์„ ์ƒ์„ฑํ•˜๊ณ , ๋น„ํ™œ์„ฑํ™”ํ•˜๋ฉด ํ•ด๋‹น ํ•ญ๋ชฉ์ด ์ œ๊ฑฐ๋จ - [ ] `npm install -g omniroute@`์ด ์น˜๋ช…์ ์ธ ์ข…๋ฃŒ ์—†์ด postinstall์„ ์‹คํ–‰ํ•จ - [ ] ์—…๋ฐ์ดํŠธ ๊ฒฝ๋กœ๊ฐ€ ์„ ํƒ์  ์˜์กด์„ฑ์„ ์œ ์ง€ํ•จ: `omniroute update --apply`์™€ ์ž๋™ ์—…๋ฐ์ดํŠธ ํ”„๋กœ๊ทธ๋žจ์ด `npm install -g โ€ฆ --include=optional`์„ ์‹คํ–‰ํ•˜์—ฌ `optionalDependencies`(better-sqlite3, keytar, tls-client ๋ฐ llmlingua SLM ์Šคํƒ: `@atjsh/llmlingua-2@2.0.5`, `js-tiktoken`)๊ฐ€ ์—…๋ฐ์ดํŠธ ํ›„์—๋„ ์œ ์ง€๋˜๋„๋ก ํ•จ. ultra `modelPath` SLM ํ‹ฐ์–ด์—๋Š” tinybert ๋ชจ๋ธ๋„ ํ•„์š”ํ•˜๋ฉฐ, ์ตœ์ดˆ ์‚ฌ์šฉ ์‹œ `${DATA_DIR}/models/llmlingua`์— ์ž๋™์œผ๋กœ ๋‹ค์šด๋กœ๋“œ๋จ. ์ดํ›„ postinstall (`scripts/build/colocateOptionals.mjs`)์€ SLM ์„ ํƒ์  ์˜์กด์„ฑ ํด๋กœ์ €๋ฅผ `dist/node_modules`์— ํ•จ๊ป˜ ๋ฐฐ์น˜ํ•˜์—ฌ ์›Œ์ปค๊ฐ€ ๋‹จ์ผ `@huggingface/transformers` ^4.2.0 ์ธ์Šคํ„ด์Šค๋ฅผ ํ•ด์„ํ•˜๋„๋ก ํ•จ โ€” ๋…๋ฆฝ ์‹คํ–‰ํ˜• ํŠธ๋ ˆ์ด์Šค๋Š” ๋™์ ์œผ๋กœ ๊ฐ€์ ธ์˜ค๋Š” ์„ ํƒ์  ์˜์กด์„ฑ์ด ์•„๋‹ˆ๋ผ transformers๋งŒ ๋ฒˆ๋“ค๋งํ•˜๋ฏ€๋กœ, ์ด ๊ณผ์ •์ด ์—†์œผ๋ฉด ์›Œ์ปค๊ฐ€ ๋ฃจํŠธ์˜ transformers์— ๋Œ€ํ•ด llmlingua-2๋ฅผ ๋กœ๋“œํ•˜๊ณ  SLM ํ‹ฐ์–ด๊ฐ€ ์กฐ์šฉํžˆ ์‹คํŒจ ํ›„ ์šฐํšŒ ์ฒ˜๋ฆฌ๋จ. - [ ] `.env`๊ฐ€ ์—†์–ด๋„ `omniroute status`๊ฐ€ ์ž‘๋™ํ•จ(CLI ํ† ํฐ ๊ฒฝ๋กœ, ๋ฃจํ”„๋ฐฑ ์ „์šฉ) - [ ] `curl http://localhost:20128/api/shutdown`์ด 401์„ ๋ฐ˜ํ™˜ํ•จ(ํ•ญ์ƒ ๋ณดํ˜ธ๋˜๋Š” ๊ฒฝ๋กœ) - [ ] `curl -H "host: evil.com" http://localhost:20128/api/mcp/sse`๊ฐ€ 401์„ ๋ฐ˜ํ™˜ํ•จ(๋ฃจํ”„๋ฐฑ ๊ฐ€๋“œ) - [ ] ์ตœ์ดˆ ์‹คํ–‰ ์‹œ SQLite ๋Ÿฐํƒ€์ž„์ด `bundled`๋กœ ํ•ด์„๋จ(๋ฒˆ๋“ค ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ํ•ด๋‹น ํ”Œ๋žซํผ์—์„œ ์œ ํšจํ•จ) - [ ] `node_modules/better-sqlite3`๊ฐ€ ์‚ญ์ œ๋˜๋ฉด SQLite ๋Ÿฐํƒ€์ž„์ด `runtime`์œผ๋กœ ํด๋ฐฑํ•จ - [ ] Smart MCP ํ•„ํ„ฐ๊ฐ€ ์‹ค์ œ `playwright-mcp browser_snapshot` ์ถœ๋ ฅ์„ ์••์ถ•ํ•จ(50% ์ด์ƒ ๊ฐ์†Œ) - [ ] `skills/omniroute*/SKILL.md` ํŒŒ์ผ 10๊ฐœ ๋ชจ๋‘ raw GitHub URL์„ ํ†ตํ•ด ๊ณต๊ฐœ์ ์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Œ - [ ] ์ƒˆ๋กœ ์„ค์ •ํ•  ๋•Œ ์˜จ๋ณด๋”ฉ ๋งˆ๋ฒ•์‚ฌ์— "์ž‘๋™ ๋ฐฉ์‹" ํ‹ฐ์–ด ๋‘˜๋Ÿฌ๋ณด๊ธฐ ๋‹จ๊ณ„๊ฐ€ ํ‘œ์‹œ๋จ - [ ] ํ™ˆ ๋Œ€์‹œ๋ณด๋“œ์˜ ํ‹ฐ์–ด ์ปค๋ฒ„๋ฆฌ์ง€ ์œ„์ ฏ์— ๊ตฌ์„ฑ๋œ ๊ฐœ์ˆ˜์™€ ํ™œ์„ฑ ๊ฐœ์ˆ˜๊ฐ€ ํ‘œ์‹œ๋จ --- ## 3.9.0 LTS ๋ถ„๊ธฐ (3.8.58์—์„œ ๋ฆฌํ—ˆ์„ค) v3.8.59 ๋‹ค์Œ ๋ฒ„์ „์€ 3.9.0์ด๋ฉฐ, ๊ทธ ์ตœ์ข… ์ปค๋ฐ‹์€ ์ˆ˜๋ช…์ด ๊ธด ๋‘ ๋ธŒ๋žœ์น˜๊ฐ€ ๋ฉ๋‹ˆ๋‹ค: `stable/v3`(v3 LTS ๋ผ์ธ, npm `latest`)์™€ `develop`(v4, 4.0.0์œผ๋กœ ๋ฒ„์ „ ์ƒํ–ฅ, npm `nightly`). ๋ธŒ๋žœ์น˜/์ฑ„๋„ ๋ชจ๋ธ, ์ •๋ฐฉํ–ฅ ํฌํŒ… ๋ฐ ๋ ˆ์ด๋ธ”์€ [RELEASE_STRATEGY.md](./RELEASE_STRATEGY.md)์— ์žˆ์œผ๋ฉฐ, ๊ณ„ํš์€ [ROADMAP](../../ROADMAP.md)(Phase 3)์— ์žˆ์Šต๋‹ˆ๋‹ค. ๋ถ„๊ธฐ๋Š” ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. 3.8.58์—์„œ๋Š” ํฌํฌ์—์„œ ์ „์ฒด ๊ณผ์ •์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ๋ฆฌํ—ˆ์„คํ•˜๊ณ , 3.8.59๋Š” [GO/NO-GO ์ฒดํฌ๋ฆฌ์ŠคํŠธ](./LTS_GO_NO_GO.md)๋กœ ๋งˆ๋ฌด๋ฆฌ๋ฉ๋‹ˆ๋‹ค. ### ๋“œ๋ผ์ด๋Ÿฐ(์ฝ๊ธฐ ์ „์šฉ, ์–ธ์ œ๋“  ์•ˆ์ „) ```bash npm run release:dry-run-lts-cut # ์‹ค์ œ ๋ถ„๊ธฐ: HEAD์—์„œ 3.9.0, ์ด์ „ ํƒœ๊ทธ v3.8.59 npm run release:dry-run-lts-cut -- --from <3.9.0-tip> # ์†Œ์Šค ์ปค๋ฐ‹ ๊ณ ์ • ``` `scripts/release/dry-run-lts-cut.mjs`๋Š” ์•„๋ฌด ์ž‘์—…๋„ ์‹คํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. git๊ณผ `gh`๋ฅผ ์ฝ๊ณ  ์ „์ฒด ์ˆœ์„œ๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ์‚ฌ์ „ ์กฐ๊ฑด(์†Œ์Šค๊ฐ€ ํ•ด์„๋จ, ์†Œ์Šค ์ €์žฅ์†Œ์— ์ „์ฒด ์ด๋ ฅ์ด ์žˆ์Œ โ€” ์–•์€ ํด๋ก ์—์„œ๋Š” `stable/v3`๋ฅผ ํ‘ธ์‹œํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ์ˆ˜์‹  ์ธก์—์„œ ์ฒซ ๋ฒˆ์งธ ์ ‘ํ•ฉ๋œ ๋ถ€๋ชจ ์ปค๋ฐ‹์˜ ํŒฉ์„ ๊ฑฐ๋ถ€ํ•˜๋ฏ€๋กœ ์ „์ฒด ํด๋ก ์—์„œ ๋ถ„๊ธฐํ•˜๊ฑฐ๋‚˜ ๋จผ์ € `git fetch --unshallow origin` ์‹คํ–‰ โ€” ์ด์ „ ํƒœ๊ทธ๊ฐ€ ์กด์žฌํ•จ, `package.json`์ด ๋Œ€์ƒ ๋ฒ„์ „์ž„, `release-freeze` ์ด์Šˆ๊ฐ€ ์—ด๋ ค ์žˆ์Œ, ๊ธฐ์กด ๋ฆด๋ฆฌ์Šค ๋ธŒ๋žœ์น˜์— ์—ด๋ฆฐ `Release branch not green` ์ด์Šˆ๊ฐ€ ์—†์Œ โ€” ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋ธŒ๋žœ์น˜๋Š” green์ด ์•„๋‹ˆ๋ผ `?` unknown์œผ๋กœ ๋ณด๊ณ ๋จ โ€” Mergify `release` ํ๊ฐ€ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Œ(G11: `queue_rules`, `checks_timeout`, ๋ ˆ์ด๋ธ” `queue`), `release/*` ๊ทœ์น™ ์„ธํŠธ๊ฐ€ ์—ฌ์ „ํžˆ ์‚ญ์ œ์™€ ๊ฐ•์ œ ํ‘ธ์‹œ๋ฅผ ์ฐจ๋‹จํ•จ, `stable/v3`์™€ `develop`์ด ์•„์ง ์กด์žฌํ•˜์ง€ ์•Š์Œ), ๋‘ ๋ธŒ๋žœ์น˜ ๋‹จ๊ณ„, ์–ด๋–ค ํœด๋ฉด ์›Œํฌํ”Œ๋กœ ํŠธ๋ฆฌ๊ฑฐ์™€ `if:` ์กฐ๊ฑด์ด ์ฐธ์ด ๋˜๋Š”์ง€(๊ทธ๋ฆฌ๊ณ  ์–ด๋–ค ๊ฒƒ์ด ์ €์žฅ์†Œ ๋ณ€์ˆ˜์— ์˜ํ•ด ๊ณ„์† ์ฐจ๋‹จ๋˜๊ฑฐ๋‚˜ ์ •์‹ ์ €์žฅ์†Œ๋กœ ๊ณ ์ •๋˜๋Š”์ง€), ์˜ˆ์ƒ dist-tag(`latest` โ†’ 3.9.0, `next`์™€ `nightly`๋Š” ๋น„์–ด ์žˆ์Œ), ๋กค๋ฐฑ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ข…๋ฃŒ ์ฝ”๋“œ `0` = `RESULT: READY`, `1` = ์ฐจ๋‹จ ์‚ฌ์ „ ์กฐ๊ฑด ์‹คํŒจ(`โœ—`), `2` = ์‚ฌ์šฉ๋ฒ• ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค. `--advisory `๋Š” ๊ฒ€์‚ฌ๋ฅผ ์ˆจ๊ธฐ์ง€ ์•Š์€ ์ฑ„ ๊ฒฝ๊ณ (`!`)๋กœ ๋‚ฎ์ถฅ๋‹ˆ๋‹ค. 3.9.0 ๋ฆด๋ฆฌ์Šค ๋™๊ฒฐ์ด ์•„์ง ์œ ์ง€๋˜๋Š” ๋™์•ˆ ์‹ค์ œ ๋ถ„๊ธฐ์˜ ๋“œ๋ผ์ด๋Ÿฐ์„ ์‹คํ–‰ํ•˜์‹ญ์‹œ์˜ค. ๋ธŒ๋žœ์น˜๋Š” ํƒœ๊ทธ ์ƒ์„ฑ ํ›„, Phase 12c์—์„œ ๋™๊ฒฐ์„ ํ•ด์ œํ•˜๊ธฐ ์ „์— ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ### 3.8.58 ๋ฆฌํ—ˆ์„ค(ํฌํฌ ์ „์šฉ) ```bash # 1. ๋ฆฌํ—ˆ์„ค ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜„์žฌ ์ตœ์ข… ์ปค๋ฐ‹์—์„œ ๋“œ๋ผ์ด๋Ÿฐ npm run release:dry-run-lts-cut -- --target-version 3.8.58 --previous-tag v3.8.57 \ --advisory freeze,base-green # 2. ํฌํฌ ์›๊ฒฉ ์ €์žฅ์†Œ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์‹คํ–‰(origin ๋˜๋Š” URL์ด ์ •์‹ # ์ €์žฅ์†Œ์ธ ์›๊ฒฉ ์ €์žฅ์†Œ๋Š” ๊ฑฐ๋ถ€๋จ; ๋ชจ๋“  ๋‹จ๊ณ„์—์„œ ํ„ฐ๋ฏธ๋„ ํ™•์ธ์„ ์š”์ฒญํ•จ) git remote add rehearsal https://github.com//OmniRoute.git node scripts/release/dry-run-lts-cut.mjs --execute --remote rehearsal \ --target-version 3.8.58 --previous-tag v3.8.57 --advisory freeze,base-green # 3. ํฌํฌ์—์„œ ํœด๋ฉด ์›Œํฌํ”Œ๋กœ ์‹คํ–‰(๋“œ๋ผ์ด๋Ÿฐ์—์„œ ์ •์‹ ์ €์žฅ์†Œ ๊ณ ์ •์ด # ๋ณด๊ณ ๋˜๋Š” ๊ฒฝ์šฐ workflow_dispatch ์‚ฌ์šฉ) ํ›„ ๋กค๋ฐฑ node scripts/release/dry-run-lts-cut.mjs --execute --rollback --remote rehearsal \ --target-version 3.8.58 --previous-tag v3.8.57 --advisory freeze,base-green ``` develop ๋ฒ„์ „ ์ƒํ–ฅ ์ปค๋ฐ‹์€ git plumbing์œผ๋กœ ์ƒ์„ฑ๋˜๋ฉฐ(์ž‘์—… ํŠธ๋ฆฌ๋Š” ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์Œ), ์ฃผ๊ธฐ ์‹œ์ž‘ ์ปค๋ฐ‹๊ณผ ๋™์ผํ•œ ๋‹ค์„ฏ ํŒŒ์ผ์˜ ๋ฒ„์ „์„ ์˜ฌ๋ฆฝ๋‹ˆ๋‹ค: `package.json`, `open-sse/package.json`, `electron/package.json`, `package-lock.json`, `docs/openapi.yaml`. ์ดํ›„ ์ฒซ ๋ฒˆ์งธ PR ์ „์— `develop`์—์„œ `[4.0.0]` CHANGELOG ์„น์…˜๊ณผ ๊ทธ i18n ๋ฏธ๋Ÿฌ๋ฅผ ์—ฝ๋‹ˆ๋‹ค. ์Šคํฌ๋ฆฝํŠธ๋Š” npm dist-tag๋ฅผ ์ ˆ๋Œ€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ์ž‘์—…์€ ์ž„์‹œ ํŒจํ‚ค์ง€์—์„œ ๋ฆฌํ—ˆ์„คํ•˜์‹ญ์‹œ์˜ค. ### PR ๋ฏธ๋ฆฌ ๋ณด๊ธฐ ์•„ํ‹ฐํŒฉํŠธ(ํ•œ ๋ฒˆ ๋นŒ๋“œํ•˜๊ณ  ๋™์ผํ•œ ๋ฐ”์ดํŠธ๋ฅผ ์Šน๊ฒฉ) `.github/workflows/preview-artifact.yml`์€ PR ํ—ค๋“œ์—์„œ ํ”„๋กœ๋•์…˜ tarball ํ•˜๋‚˜๋ฅผ ๋นŒ๋“œํ•˜๊ณ  ๋ฐ”๋กœ ๊ทธ ๋นŒ๋“œ๋ฅผ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค(#8084 ์Šฌ๋ผ์ด์Šค (a)). ๋™์ผ ์ €์žฅ์†Œ PR๋งŒ ์ง€์›ํ•˜๋ฉฐ, ์•„๋ฌด๊ฒƒ๋„ ๊ฒŒ์‹œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ```bash gh workflow run preview-artifact.yml -f pr_number= # ๋˜๋Š” `preview-artifact` ๋ ˆ์ด๋ธ” ์ถ”๊ฐ€ gh run download --name preview-artifact-pr- --dir preview cd preview && sha256sum -c SHA256SUMS gh attestation verify omniroute-*.tgz --repo diegosouzapw/OmniRoute npm install -g ./omniroute-*.tgz # ๋ฏธ๋ฆฌ ๋ณด๊ธฐ ์„ค์น˜ ``` ์‹คํ–‰ ๊ณผ์ •์—์„œ๋Š” `npm ci`, `npm run build:release`, `npm run check:pack-artifact`๋ฅผ ์‹คํ–‰ํ•˜๊ณ  tarball์„ ํŒจํ‚นํ•œ ๋‹ค์Œ, `npm run check:pack-boot`(๊ฐ€์งœ ์‹œํฌ๋ฆฟ, ์ž„์‹œ ๋ฐ์ดํ„ฐ ๋””๋ ‰ํ„ฐ๋ฆฌ)๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋‹ค์‹œ ํŒจํ‚นํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์ด์ œ์ŠคํŠธ๊ฐ€ ๋™์ผํ•˜์ง€ ์•Š์œผ๋ฉด ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ `artifact-identity.json`(ํ—ค๋“œ SHA, ๋ฒ ์ด์Šค SHA, lockfile ํ•ด์‹œ, ํ”Œ๋žซํผ, ์•„ํ‚คํ…์ฒ˜, node ABI, ๋ฒˆ๋“ค๋Ÿฌ, ๋นŒ๋“œ ์ •์ฑ… โ€” `scripts/release/artifact-identity.mjs`)์„ ๊ธฐ๋กํ•˜๊ณ , ๋ณ„๋„ ์ž‘์—…์—์„œ tarball์„ ์ฆ๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋ฏธ๋ฆฌ ๋ณด๊ธฐ๋ฅผ ์Šน๊ฒฉํ•œ๋‹ค๋Š” ๊ฒƒ์€ ํ•ด๋‹น tarball์„ ์„ค์น˜ํ•œ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ์†Œ์Šค์—์„œ ๋‹ค์‹œ ๋นŒ๋“œํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ### ๋ถ„๊ธฐ(3.9.0, GO ์ดํ›„) 1. [LTS_GO_NO_GO.md](./LTS_GO_NO_GO.md)์— GO๊ฐ€ ๊ธฐ๋ก๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. 2. `npm run release:dry-run-lts-cut -- --from v3.9.0`์ด `RESULT: READY`๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. 3. ๋“œ๋ผ์ด๋Ÿฐ์—์„œ ์ถœ๋ ฅํ•œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ `origin`์— ๋ธŒ๋žœ์น˜๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์Šคํฌ๋ฆฝํŠธ๋Š” `origin`์œผ๋กœ์˜ ํ‘ธ์‹œ๋ฅผ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ๊ฒ€ํ† ๋œ develop ์ปค๋ฐ‹์„ ์žฌ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋จผ์ € ํฌํฌ๋ฅผ ๋Œ€์ƒ์œผ๋กœ 3.9.0 ์ตœ์ข… ์ปค๋ฐ‹์—์„œ `--execute` ๋ฆฌํ—ˆ์„ค์„ ์‹คํ–‰ํ•˜์‹ญ์‹œ์˜ค. ๋‘ SHA๊ฐ€ ๋ชจ๋‘ ์ถœ๋ ฅ๋˜๋ฉฐ, ๋™์ผํ•œ ์ปค๋ฐ‹์„ ํ‘ธ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: ```bash git push origin :refs/heads/stable/v3 :refs/heads/develop ``` 4. ์ฒซ ๋ฒˆ์งธ PR์ด ๋ณ‘ํ•ฉ๋˜๊ธฐ ์ „์— `stable/v3` ๋ฐ `develop`์„ ๋ณดํ˜ธํ•ฉ๋‹ˆ๋‹ค(๊ทœ์น™ ์„ธํŠธ + ๋ณ‘ํ•ฉ ํ). 5. ๋น„ํ™œ์„ฑ ์›Œํฌํ”Œ๋กœ๋Š” ๋ธŒ๋žœ์น˜๊ฐ€ ์กด์žฌํ•˜๋ฉด ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค: `forward-port.yml`(`stable/v3`์— ํ‘ธ์‹œ), `validate-stable-pr.yml`(`stable/v3` ๋Œ€์ƒ PR) ๋ฐ `nightly-v4-build.yml` (`develop` ๋นŒ๋“œ). ์‹ค์ œ ๊ฐ€๋™ ์ „์— `secrets.FORWARD_PORT_TOKEN` ์ €์žฅ์†Œ ์‹œํฌ๋ฆฟ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค(ํฌ์›Œ๋“œ ํฌํŠธ PR์—์„œ CI๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•จ). ์•ผ๊ฐ„ ๊ฒŒ์‹œ๋Š” ์†Œ์œ ์ž๊ฐ€ ์ €์žฅ์†Œ ๋ณ€์ˆ˜ `vars.NIGHTLY_PUBLISH`๋ฅผ `true`๋กœ ์„ค์ •ํ•˜๊ณ  npm Trusted Publishing์ด `nightly-v4-build.yml`์„ ํ—ˆ์šฉํ•  ๋•Œ๊นŒ์ง€ ๋น„ํ™œ์„ฑ ์ƒํƒœ๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ์ฑ„๋„ ๊ฒฐ์ •์€ `scripts/release/dist-tag.mjs`์—์„œ ์ˆ˜ํ–‰๋˜๋ฉฐ, ์ด๋Š” `npm-publish.yml`์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ๋ฆฌ์กธ๋ฒ„์ž…๋‹ˆ๋‹ค. 6. ์ฑ„๋„์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค: `npm view omniroute dist-tags --json`์—์„œ `latest` = 3.9.0์œผ๋กœ ํ‘œ์‹œ๋˜๊ณ , v4๊ฐ€ ๊ฒŒ์‹œ๋˜๊ธฐ ์ „๊นŒ์ง€ `next` / `nightly`๋Š” ์—†์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 7. ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋กค๋ฐฑํ•ฉ๋‹ˆ๋‹ค: `git push origin --delete refs/heads/stable/v3 refs/heads/develop` ๋ฐ `npm dist-tag add omniroute@3.8.59 latest`. --- ## ๋กค๋ฐฑ ๋ฆด๋ฆฌ์Šค์— ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ: 1. `gh release edit vX.Y.Z --prerelease`(์ตœ์‹  ๋ฆด๋ฆฌ์Šค๊ฐ€ ์•„๋‹Œ ๊ฒƒ์œผ๋กœ ํ‘œ์‹œ) 2. `git tag -d vX.Y.Z && git push --delete origin vX.Y.Z`(์•„์ง ์‚ฌ์šฉ์ž๊ฐ€ ์ฑ„ํƒํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋งŒ) 3. ๋˜๋Š”: `release/vX.Y.0`์—์„œ ํ•ซํ”ฝ์Šค โ†’ ํŒจ์น˜ ๋ฆด๋ฆฌ์Šค `vX.Y.(Z+1)` 4. GitHub Discussions์™€ Discord์— ์ฆ‰์‹œ ๊ณต์ง€ ## ์—„๊ฒฉํ•œ ๊ทœ์น™ - `main`์— ์ง์ ‘ ์ปค๋ฐ‹ํ•˜์ง€ ์•Š๊ธฐ - `main` ๋˜๋Š” `release/*` ๋ธŒ๋žœ์น˜์— `git push --force`๋ฅผ ์ ˆ๋Œ€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ - Husky ํ›…์„ ์ ˆ๋Œ€ ๊ฑด๋„ˆ๋›ฐ์ง€ ์•Š๊ธฐ(`--no-verify`) - ๋น„๋ฐ€ ์ •๋ณด, ์ž๊ฒฉ ์ฆ๋ช… ๋˜๋Š” `.env` ํŒŒ์ผ์„ ์ ˆ๋Œ€ ์ปค๋ฐ‹ํ•˜์ง€ ์•Š๊ธฐ - ์ปค๋ฒ„๋ฆฌ์ง€๋Š” โ‰ฅ60/60/60/60(๊ตฌ๋ฌธ/๋ผ์ธ/ํ•จ์ˆ˜/๋ธŒ๋žœ์น˜)์„ ์œ ์ง€ํ•ด์•ผ ํ•จ - `src/`, `open-sse/`, `electron/` ๋˜๋Š” `bin/`์˜ ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ๋Š” ํ•ญ์ƒ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ## ์ž๋™ํ™”๋œ ๋™๊ธฐํ™” ๊ฒ€์‚ฌ PR์„ ์—ด๊ธฐ ์ „์— ๋กœ์ปฌ์—์„œ ๋ฌธ์„œ ๋™๊ธฐํ™” ๊ฒ€์‚ฌ๋ฅผ ์‹คํ–‰ํ•˜์„ธ์š”: ```bash npm run check:docs-sync ``` CI๋„ `.github/workflows/ci.yml`์—์„œ ์ด ๊ฒ€์‚ฌ(lint ์ž‘์—…)๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.