The SSR/Fly CMS contract and a static build profile
Table of contents
The SSR/Fly CMS contract and a static build profile
Codingstairs serves the same screens through two deliberate data boundaries. Docker SSR reads PostgreSQL, while Fly.io builds static pages from the /api/export snapshot captured at delivery time. Forcing both into one runtime would make the Fly build require database credentials or make the static mirror lag behind an SSR change without an explicit release.
The public function contract
frontend/codingstairs/src/lib/cms-contract.ts lists the minimum functions both adapters must provide. cms.ts and cms.fly.ts expose cmsAdapterContract, so removing a function from either side fails TypeScript verification immediately.
The contract does not merge the data providers:
- SSR applies SQL filters, ordering, pagination, and pool timeouts.
- Fly reads the export payload once and reproduces the same lookup meaning in memory.
- Writes are SSR-only; the Fly adapter intentionally rejects
createInquiry.
The static build profile
Next.js dynamic and dynamicParams are statically analyzed, so changing them safely with one environment variable is not enough. scripts/prepare-fly-build.mjs runs only inside the image build layer and:
- changes only the literal exports listed in the static route manifest;
- switches
@/lib/cmsand@/lib/dbimports to the export and stub providers; - fails if a dynamic export or DB provider import remains;
- leaves the working tree untouched.
Adding a new route without updating the manifest therefore fails the Fly build instead of silently publishing an incomplete contract.
Content delivery order
- Edit the UTF-8 sources under
courses/andnotes/. - In an authenticated Admin session, run the schema migration and idempotent seed/upsert.
- Check Docker SSR Korean/English routes and
/api/export. - Rebuild the snapshot with
fly deploy --no-cache --build-secret CS_EXPORT_SECRET=.... - Check Fly health, both locales, series/lesson/note routes, and the canonical host.
A successful DB seed without a Fly redeploy leaves users on the old snapshot. Conversely, a successful Fly build with no corresponding row in the DB export should produce a 404 for that series or note; that is a useful consistency signal.
Completion criteria
- SSR and Fly expose the same adapter function list.
- The build-profile residue checks pass.
- The secret is absent from Docker
ARG,ENV, and the final image. - After seeding, Docker and Fly return the same bilingual content.