SSR·Fly CMS 계약과 정적 빌드 profile
콘텐츠 서비스는 같은 화면을 두 가지 데이터 공급 경계에서 제공할 수 있다. Docker SSR은 PostgreSQL을 읽고, 정적 호스트는 배포 시점의 /api/export snapshot을 읽어 페이지를 만든다. 둘을 억지로 하나의 runtime으로 합치면 static build가 DB 자격 증명을 요구하거나, SS…
목차
SSR·Fly CMS 계약과 정적 빌드 profile
콘텐츠 서비스는 같은 화면을 두 가지 데이터 공급 경계에서 제공할 수 있다. Docker SSR은 PostgreSQL을 읽고, 정적 호스트는 배포 시점의 /api/export snapshot을 읽어 페이지를 만든다. 둘을 억지로 하나의 runtime으로 합치면 static build가 DB 자격 증명을 요구하거나, SSR 변경이 정적 mirror에 늦게 반영되는 모순이 생긴다.
공개 함수 계약
apps/web/src/lib/cms-contract.ts는 두 adapter가 반드시 제공해야 하는 최소 공개 함수를 고정한다. cms.ts와 cms.static.ts 모두 cmsAdapterContract를 컴파일 때 만족하므로 함수가 한쪽에서 빠지면 TypeScript 검증에서 즉시 실패한다.
이 계약은 데이터 공급자를 통합하지 않는다.
- SSR: SQL의 필터·정렬·페이지네이션·pool timeout을 적용한다.
- Fly: export payload를 한 번 읽고 메모리에서 동일한 조회 의미를 재현한다.
- 쓰기: SSR에서만 가능하며 Fly adapter의
createInquiry는 의도적으로 실패한다.
정적 build profile
Next.js의 dynamic·dynamicParams는 정적 분석 대상이라 환경변수 하나로 안전하게 바꾸기 어렵다. scripts/prepare-fly-build.mjs는 이미지 build layer 안에서만 다음을 수행한다.
- 정적 전환 대상 route manifest를 읽고 예상한 literal export만 바꾼다.
@/lib/cms와@/lib/dbimport를 각각 export·stub provider로 바꾼다.- 동적 export나 DB provider import가 남으면 build를 실패시킨다.
- working tree에는 어떠한 변환도 남기지 않는다.
따라서 새 route를 추가할 때 manifest를 갱신하지 않으면 Fly build가 조용히 오래된 계약을 제공하지 않고 실패한다.
콘텐츠 반영 순서
courses/와notes/의 UTF-8 원본을 수정한다.- 인증된 Admin에서 schema migration과 idempotent seed/upsert를 실행한다.
- Docker SSR의 한국어·영어 route와
/api/export내용을 확인한다. - 정적 배포 명령으로 snapshot을 새로 만든다.
- 정적 호스트 health, 양언어 series/lesson/note route, canonical host를 확인한다.
DB seed만 성공하고 Fly를 재배포하지 않으면 사용자는 이전 snapshot을 보게 된다. 반대로 Fly build만 성공해도 DB export에 없는 series·note URL은 404가 되는 것이 정상적인 일관성 신호다.
완료 기준
- SSR·Fly adapter 공개 함수 목록이 동일하다.
- build profile 잔여물 검사가 통과한다.
- secret이 Docker
ARG·ENV·최종 image에 남지 않는다. - seed 후 Docker와 Fly가 같은 양언어 콘텐츠를 반환한다.