How content moves from Directus or the fixture into typed modules, and the shared contracts that keep the exporter and the site in agreement.

Reference Value
Subject Exporter, source policy, generated modules, shared schemas, locales, asset contracts; for anyone changing content shapes or the build export
Verified source export-fallbacks.ts, apps/cms/scripts/lib, packages/shared on main at f40e8704, checked 2026-11-07; build-published images (build-media.ts, #677), project one-liner validation (#678) and image block fields (#691) re-verified on main at 0461e045, checked 2026-11-10
Support state Export and metric-output contracts checked against main f40e8704; the registry in lib/export-modules.ts declares 21 outputs. Site and llms-full.txt metric output excludes source/date fields
flowchart LR
  D["Directus<br/>published rows"] -- "fetchers" --> EX["export-fallbacks.ts"]
  FX["packages/shared/fixtures<br/>export-data.json"] --> EX
  C[".cms-cache.json<br/>local only"] -. "soft fallback" .-> EX
  EX -- "validate with<br/>@repo/shared schemas" --> EM["emitter registry"]
  EM --> MOD["apps/web/src/lib/content<br/>21 modules"]
  MAN["assets-manifest.json<br/>assets-id-map.json"] --> EX
  EX --> MV["media variants"]
  D -- "Build Bot read<br/>unmirrored images" --> BM["static/images/cms<br/>generated, ignored"]
  EX --> BM

Source policy

Saving CMS content does not itself start a build. A production build uses live CMS content, whether triggered by Publish site or a merge to main. A merge after a CMS content write therefore publishes that content when the production build succeeds; the code diff does not bound the content published.

Target Detected by Source On failure
Vercel Production VERCEL_ENV=production Live CMS only; fixture mode is refused Build fails before emitting
Vercel Preview Any other VERCEL_ENV Fixture; a live request is ignored with a warning n/a
Local and CI No VERCEL_ENV Fixture by default; EXPORT_FALLBACKS_SOURCE=live for an explicit operator read Live failure falls back to .cms-cache.json; no cache means failure

The whole live fetch has a 60 second stall guard. Exit codes come from decideExit: under the production fail policy anything but a live export fails, and every policy fails when no source exists.

What the exporter enforces

Generated modules

lib/export-modules.ts is the single registry for fetches, schemas, cross-entity checks and outputs. emitters/configs.ts derives output configurations from it. Fetchers in lib/fetchers/ map Directus rows to product types.