Where things stand
Version 2 is now running in production. It adds an authenticated AWS content plane for Writing and Field Notes while Version 1 remains the application delivery platform underneath it.
This was an evolution rather than a replacement. CloudFront, the load balancer, Fargate, SES, and the Node application still deliver the site; Cognito, DynamoDB, S3, and the CMS now let authenticated editors publish content without rebuilding that application.
Version 1 — the deployment architecture
The original goal was to run a real full-stack personal site on AWS without pretending it needed hyperscale complexity. Visitors enter through Amazon CloudFront. Hashed client assets go to object storage; HTML, server functions, RSS, and application routes go through an Application Load Balancer to a Node container on ECS Fargate.
Browser ──► DNS ──► CloudFront (TLS)
│
┌───────────────┴───────────────┐
│ │
/assets/* default (*)
│ │
▼ ▼
S3 object storage Application Load
hashed JS / CSS Balancer
│
▼
ECS Fargate
Node + SSR app
│
┌───────────┴───────────┐
▼ ▼
DynamoDB SES
Dispatch signups notificationsThis split-origin design is still sound. Immutable files are cheap to cache at the edge, while requests that need execution reach the application tier. The /assets/* CloudFront behavior must remain more specific than the default behavior or the browser will ask the wrong origin for its CSS and JavaScript.
What v1 taught me
The hosting architecture worked. The publishing architecture was the part that did not scale gracefully.
In v1, an essay is a React/TSX module registered inside the application. Its metadata, body, related links, search entry, RSS entry, sitemap URL, and images all travel with the codebase. Publishing one article or Field Note therefore means:
- edit source files and discovery files;
- build the client and server bundles;
- sync hashed assets to S3;
- build and push a Docker image;
- register and roll out a new ECS task definition;
- invalidate CloudFront and verify production.
That process is appropriate for changing application behavior. It is too much ceremony for publishing prose. It also places content images inside the application artifact, making container pushes larger than they need to be.
Version 2 — the content architecture
Version 2 introduces a separate content plane. The application asks repository contracts for Writing and Field Notes metadata and bodies. It does not need to know whether the provider is a local Markdown directory or AWS services.
Readers ──► CloudFront ──► existing Node application
│
▼
Content repositories
/ \
/ \
local Markdown AWS content plane
development adapter production adapter
│
┌─────────────┴─────────────┐
▼ ▼
DynamoDB S3
metadata + revisions Markdown + images
Editors ──► Cognito ──► /admin ──► draft / preview / publish
│ │
└── individual identities └──► targeted cache invalidation
and controlled accessThe local adapter is the first implementation. It reads validated Markdown and YAML front matter from the repository. Existing TSX essays remain available through a compatibility adapter, so migration can happen one item at a time instead of through a risky all-at-once conversion.
The production adapter now uses DynamoDB for metadata, publication state, and revisions; S3 for Markdown bodies and uploaded media; and Cognito for editor authentication. The same repository contracts feed Writing and Field Notes pages, Search, RSS, related reading where applicable, and SEO metadata.
Why this version was chosen
- Publishing becomes independent. Writing and Field Notes can be created, previewed, and published without rebuilding or restarting the application.
- Authorship can become collaborative. Multiple editors can receive individual Cognito identities and controlled CMS access without sharing AWS credentials, repository permissions, or a deployment workstation. Identity and editor attribution also provide the foundation for future roles, approvals, and audit history.
- The migration stays reversible. The repository boundary lets local Markdown, legacy TSX, and future AWS content coexist.
- Content remains portable. Markdown is easier to export, review, version, and move than prose embedded in application components.
- The rendering surface stays controlled. The site supports a safe Markdown vocabulary rather than arbitrary executable MDX or raw HTML.
- Images leave the container. Moving article media to S3 reduces Docker image size and makes ECR deployments faster and more reliable.
- One source can feed every discovery surface. Search, RSS, sitemap data, structured metadata, and eventually
llms.txtcan be generated from the published catalog instead of updated by hand in several places.
Compared with a static-site blog workflow
A conventional repository-backed static blog—whether built with Astro or another static site generator—often treats a new article as a source-code change. An author edits a Markdown file, opens a pull request or pushes to Git, waits for a site build, and publishes a new artifact. That can be wonderfully simple for one technical author.
This architecture chooses a different boundary. Authors work through authenticated CMS accounts; publishing updates the content plane while the application artifact stays unchanged. That makes onboarding additional writers and editors substantially easier and avoids giving every contributor access to the repository and release pipeline.
The distinction is architectural, not a limitation of Astro. Astro can also consume a headless CMS and support multiple authors. The advantage here is that collaboration, identity, and no-rebuild publishing are native properties of this deployed system rather than conventions layered onto a code-backed editorial workflow.
The publishing flow
The deployed v2 workflow is deliberately ordinary:
Sign in ──► write or upload ──► preview ──► publish
│
┌──────────────────────────┼──────────────────────┐
▼ ▼ ▼
content becomes live feeds/search update targeted CDN clearApplication deployments still exist, but only for application changes. Content changes use the content plane. That is the central architectural decision.
What stays from v1
Version 2 keeps the useful operational lessons of the first architecture:
- CloudFront remains the public edge and TLS front door.
- The load balancer remains the stable origin for application requests.
- ECS Fargate still runs SSR and server-side application logic.
- Task IAM roles remain preferable to credentials baked into containers.
- Security groups continue to limit the application port to the load balancer.
- Build-once discipline still applies whenever the application itself is released.
In other words, v1 becomes the application platform underneath v2 rather than a discarded experiment.
Migration status
- Deployed: Cognito editor authentication, encrypted sessions, DynamoDB metadata and revisions, private S3 Markdown bodies, public CloudFront media, and targeted invalidation.
- Also deployed: validated Markdown, draft preview, Writing and Field Notes editing, legacy fallback, Search, RSS, sitemap, related reading, and SEO metadata integration.
- Later: revision browsing and rollback UI, scheduling, dynamic AI discovery output, signed preview links, and incremental legacy content migration.
Version 1 remains the application delivery platform underneath the site. Version 2 is now the production content plane, so new Writing and Field Notes can publish without an application image rollout.
Cost and operational tradeoffs
The v2 services are intentionally small and managed. DynamoDB and S3 fit a low-volume publishing workload well; Cognito avoids inventing an authentication system; targeted invalidations are cheaper and less disruptive than treating every essay like an application release.
The tradeoff is more application logic around permissions, revisions, cache behavior, and failure handling. That complexity is justified because it removes repeated deployment work from the common publishing path while preserving a simple export format.
Related
- Colophon — stack, fonts, and local tooling.
- V1 production runbook:
docs/deploy-aws-architecture.md. - V2 migration design:
docs/cms-architecture.md. - Discovery maintenance:
docs/seo-and-ai.md.