Examples/Content
Headless CMS and publication site (example)
A headless CMS that stores drafts, revisions and schedules in Postgres and publishes them on a timer. A Next.js site renders the pages, a CDN caches them, and an image CDN resizes uploaded media.
Scale: 30 editors; 2M page views/day; 95% CDN hit rate
Select a component to see what it is responsible for and which state it owns.
- 1CMS admin → CMS API: Save draft
- 2CMS API → Postgres: Write revision
- 3CMS admin → Media storage: Upload image
- 4CMS API → Scheduler: Publish event
- 5Scheduler → Postgres: Claim due posts
- 6Scheduler → Next.js site: Revalidate paths
- 7Scheduler → Hosted search: Update index
- 8Readers → CDN: Read article
- 9CDN → Next.js site: Render on miss
- 10Next.js site → CMS API: Fetch published content
- 11Readers → Image CDN: Load image
- 12Image CDN → Media storage: Fetch original
- Request / response
- Bulk data
- Asynchronous
Select a part to trace its flows.
- Request / response
- Bulk data
- Asynchronous
Parts 10
Flows 12
- 1CMS admin → CMS APISave draftRequest / response
- 2CMS API → PostgresWrite revisionRequest / response
- 3CMS admin → Media storageUpload imageBulk data
- 4CMS API → SchedulerPublish eventAsynchronous
- 5Scheduler → PostgresClaim due postsRequest / response
- 6Scheduler → Next.js siteRevalidate pathsRequest / response
- 7Scheduler → Hosted searchUpdate indexRequest / response
- 8Readers → CDNRead articleRequest / response
- 9CDN → Next.js siteRender on missRequest / response
- 10Next.js site → CMS APIFetch published contentRequest / response
- 11Readers → Image CDNLoad imageRequest / response
- 12Image CDN → Media storageFetch originalBulk data
Invariants 3
One editor's save never silently overwrites another's
Optimistic concurrency: UPDATE … WHERE id = $1 AND revision = $2; zero rows shows a conflict.
Kept by
A scheduled post is published once
Due rows claimed with FOR UPDATE SKIP LOCKED; publishing an already-published revision is a no-op.
Kept by
Readers see a published change within a minute
Revalidation is sent after commit and retried with backoff; pages also expire after 10 minutes.
Kept by