[fix] site,docs: 목업 슬러그는 굽지 않는다 — 발행 하나에 /s/stay 시연본이 통째로 덮였다

실측(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) <noreply@anthropic.com>
This commit is contained in:
Mina Choi 2026-09-15 08:22:53 +09:00
parent 93bd5435ac
commit 7425cb409e
2 changed files with 38 additions and 0 deletions

View File

@ -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` 에서 읽어 박는다

View File

@ -75,6 +75,29 @@ import {MOONLIGHT_STAY_PAYLOAD} from '@site/fixtures/moonlight-stay';
/** 사이트별 산출물이 놓이는 디렉터리. 발행 주소 `<host>/s/<slug>` 와 같은 모양이다. */
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;