From 7425cb409e99e96e7a01a8a99fca82b47e6869b7 Mon Sep 17 00:00:00 2001 From: Mina Choi Date: Tue, 15 Sep 2026 08:22:53 +0900 Subject: [PATCH] =?UTF-8?q?[fix]=20site,docs:=20=EB=AA=A9=EC=97=85=20?= =?UTF-8?q?=EC=8A=AC=EB=9F=AC=EA=B7=B8=EB=8A=94=20=EA=B5=BD=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=EB=8B=A4=20=E2=80=94=20=EB=B0=9C=ED=96=89=20?= =?UTF-8?q?=ED=95=98=EB=82=98=EC=97=90=20/s/stay=20=EC=8B=9C=EC=97=B0?= =?UTF-8?q?=EB=B3=B8=EC=9D=B4=20=ED=86=B5=EC=A7=B8=EB=A1=9C=20=EB=8D=AE?= =?UTF-8?q?=EC=98=80=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 실측(2026-09-15): 누가 빌더에서 슬러그 `stay` 로 발행해 `payloads/stay.json` 이 생기자 프리렌더가 기동하며 그 payload 로 `/s/stay` 를 구웠다 — 손으로 만든 유일본이 사라졌다 (캐치프레이즈 100개 · 미니 플레이어 · 날씨 문구 · 주입분 전부). 백업에서 되돌렸다. "payload 가 없으면 안 굽는다"(AGENTS.md 함정 1)는 목업을 못 지킨다 — payload 가 생기는 순간 덮인다. - prerender.ts: PROTECTED_SLUGS(기본 stay,stay2,stay3 · PRERENDER_PROTECTED_SLUGS 로 덮어씀). 그 슬러그는 굽지 않고 실패 보고서를 쓴다 — 사장님 화면에 사유가 뜨고 목업은 남는다 - AGENTS.md: 함정 1에 이 경로와 payloads-mockup-hold 를 적는다 tsc·eslint 통과 · vitest 75 passed Co-Authored-By: Claude Opus 5 (1M context) --- AGENTS.md | 6 ++++++ solution/site/scripts/prerender.ts | 32 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 8d169a8..7bbb7de 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -34,6 +34,12 @@ → **`out/assets` 에서 파일을 지우는 코드는 `out/s/**` 의 HTML 이 참조하는 것을 먼저 뺀다** (`prerender.ts` `referencedAssets`). 보관 기간으로는 못 막는다 — 기간이 지나면 같은 일이 난다. → 목업을 다루는 작업은 `out/s/` 를 먼저 열어 **payload 가 없는 디렉토리가 무엇인지** 본다. + → ★ **목업 슬러그는 프리렌더가 굽지 않는다** (`prerender.ts` `PROTECTED_SLUGS`, 기본 + `stay,stay2,stay3` · `PRERENDER_PROTECTED_SLUGS` 로 덮어쓴다). "payload 가 없으면 안 굽는다" + 는 보호가 못 된다 — **payload 가 생기는 순간** 덮인다. 실측(2026-09-15): 누가 빌더에서 + 슬러그 `stay` 로 발행해 `payloads/stay.json` 이 생기자 프리렌더가 `/s/stay` 를 그 payload 로 + 구워 목업을 통째로 날렸다(캐치프레이즈 100개·미니 플레이어·날씨 문구·주입분 전부). + 그 payload 는 `solution/site/payloads-mockup-hold/` 로 옮긴다 — 지우면 재발행 때 또 온다. - **번들 파일명은 콘텐츠 해시다.** HTML 은 `/assets/index-DvNTmLhy.css` 를 **루트 절대경로**로 가리킨다. 경로는 프리렌더가 `dist/client/.vite/manifest.json` 에서 읽어 박는다 diff --git a/solution/site/scripts/prerender.ts b/solution/site/scripts/prerender.ts index 204c0c3..da38513 100644 --- a/solution/site/scripts/prerender.ts +++ b/solution/site/scripts/prerender.ts @@ -75,6 +75,29 @@ import {MOONLIGHT_STAY_PAYLOAD} from '@site/fixtures/moonlight-stay'; /** 사이트별 산출물이 놓이는 디렉터리. 발행 주소 `/s/` 와 같은 모양이다. */ const SITE_DIR = 's'; +/** + * 손으로 만든 시연본(목업)이 차지한 슬러그. **이 슬러그는 굽지 않는다.** + * + * ★ 왜 (2026-09-15, 실측) + * `/s/stay` 는 payload 가 없는 목업이고 그 index.html 이 **유일본**이다(AGENTS.md 함정 1). + * 그런데 누군가 빌더에서 슬러그 `stay` 로 발행하자 `payloads/stay.json` 이 생겼고, 프리렌더가 + * 기동하며 그 payload 로 같은 자리를 구워 **목업을 통째로 덮었다** — 캐치프레이즈 100개 · + * 미니 플레이어 · 날씨 문구 · 주입분이 전부 사라졌다. 파일을 백업에서 되돌려야 했다. + * "payload 가 없으면 안 굽는다" 는 목업을 지켜 주지 못한다. **payload 가 생기는 순간** 덮인다. + * + * ★ 슬러그를 막는 것이지 발행을 막는 것이 아니다. 백엔드는 발행에 성공했다고 보고, 여기서 + * 실패 보고서를 써 준다 — 사장님 화면에 사유가 뜨고, 목업은 그대로 남는다. + * + * ★ 목업을 늘리거나 걷어낼 때는 `PRERENDER_PROTECTED_SLUGS`(쉼표) 로 덮어쓴다. 값을 비우면 + * 보호가 전부 풀린다 — 목업을 정식 사이트로 넘길 때만 그렇게 한다. + */ +const PROTECTED_SLUGS = new Set( + (process.env.PRERENDER_PROTECTED_SLUGS ?? 'stay,stay2,stay3') + .split(',') + .map((slug) => slug.trim()) + .filter(Boolean), +); + const HERE = dirname(fileURLToPath(import.meta.url)); const SITE_ROOT = resolve(HERE, '..', '..'); // dist/prerender → site/ // 백엔드가 노래 파일을 떨구는 자리. payload 디렉토리와 나란히 둔다(한 디렉토리 약속). @@ -883,6 +906,15 @@ function main() { continue; } + // ★ 목업이 쓰는 슬러그는 굽지 않는다 — 구우면 손으로 만든 유일본을 덮는다(PROTECTED_SLUGS). + if (PROTECTED_SLUGS.has(entry.payload.site.slug)) { + fail( + entry, + `슬러그 '${entry.payload.site.slug}' 는 시연본이 쓰고 있어 발행할 수 없습니다. 다른 슬러그로 발행해 주세요.`, + ); + continue; + } + try { const result = prerenderSite(entry.payload, args.out, assets, referenced); const payload = result.payload;