Happy Post is a cloud-native application with a Next.js frontend and FastAPI backend. The delivery architecture uses two independently deployable container images and ECS Fargate services.
- Architecture: primary solution architecture, AWS runtime, delivery/control plane, Terraform ownership, and deployed-state summary.
- Live sandbox application: deployed Happy Post MVP.
- Operations: smoke tests, CloudWatch logs, database migration, restart persistence, and recovery procedures.
The MVP application source is present: a FastAPI daily-entry API and a warm Next.js bedtime page where each signed-in user records at least three small happy things, with optional extra happy items when they have more to save. Local containerisation runs frontend, backend, and local PostgreSQL together through Docker Compose. P4's Terraform network, private RDS PostgreSQL data, ECR/ECS platform, edge, and both digest-pinned ECS service roots are applied. Terraform, application, security, image-publication, initial-service bootstrap, post-bootstrap deployment, and rollback workflows are implemented. The deployed frontend and backend services have been updated through the controlled ECS deployment workflow and their public HTTPS smoke tests pass.
- Backend MVP: email/password MVP auth, user-scoped daily-entry API, operational endpoints, PostgreSQL persistence, Alembic migration, tests, linting, and local configuration example.
- Frontend MVP: sign-in/sign-up UI, three-small-happy-things bedtime UI, private history calendar, backend API integration, operational endpoints, tests, linting, and local configuration example.
- Terraform foundation: version constraints, remote state, and applied sandbox network, RDS data, ECR/ECS platform, edge, and service roots.
- Terraform workflow controls: backend-free PR format, validate, native test, and TFLint checks plus manual target-selected plan, apply, and destroy controls.
- Application CI: changed-component backend and frontend linting, unit tests, and frontend build checks.
- Image publication: changed-component
mainpublication plus a main-only manual initial publication, Trivy gate, immutable ECR publication, and digest handoff artifact. - Service bootstrap: manually creates one selected initial service only after repository-specific digest and immutable source-commit-tag verification.
- Database migration: manually runs
alembic upgrade headas a one-off private ECS Fargate task from a verified backend image digest before deploying a backend release that requires schema changes. - ECS deployment: manually updates one existing service with a verified immutable digest, then verifies ECS, ALB, and public HTTPS health.
- ECS rollback: manually restores one existing service to its immediately preceding known-good task-definition revision.
| Check | URL |
|---|---|
| Application | https://happy-post.asksafe.ai |
| Frontend health check | https://happy-post.asksafe.ai/healthz |
| Frontend version check | https://happy-post.asksafe.ai/version |
| Backend health check | https://happy-post.asksafe.ai/backend/healthz |
| Backend version check | https://happy-post.asksafe.ai/backend/version |
The controlled ECS deployment workflow has successfully deployed both services. Backend smoke tests passed at /backend/healthz and /backend/version; the backend version response reports the deployed immutable image digest. Frontend smoke tests passed at /healthz and /version; the frontend version response currently reports the application version 0.1.0. The rollback workflow is available for component-scoped recovery and should be rehearsed only if time permits before assessment submission.
Database-changing releases require one extra controlled step before the backend deployment. After publishing the backend image from main, run the manual database migration workflow with the same backend image_digest and source_commit, confirm migrate-backend, verify success, and only then run the backend ECS deployment workflow with that digest. The migration workflow and required bootstrap permissions are now in place; keep future database-changing releases on the same migration-before-backend-deploy sequence.
Docker Compose defines db, backend-migrate, backend, and frontend for a
local PostgreSQL-backed run. From the repository root, run:
docker compose up --build -d
docker compose ps
docker compose down --remove-orphansThe frontend is available at http://127.0.0.1:3000; its relative /api/entries/*
requests are forwarded internally to http://backend:8000. The backend is available
at http://127.0.0.1:8000 by default. Local PostgreSQL binds to
127.0.0.1:5432 by default. If port 8000 or 5432 is temporarily in use, change
only the non-sensitive host-side bindings:
HAPPY_POST_BACKEND_HOST_PORT=18000 HAPPY_POST_DB_HOST_PORT=15432 docker compose up --build -d
HAPPY_POST_BACKEND_HOST_PORT=18000 HAPPY_POST_DB_HOST_PORT=15432 docker compose ps
HAPPY_POST_BACKEND_HOST_PORT=18000 HAPPY_POST_DB_HOST_PORT=15432 docker compose down --remove-orphansThis keeps internal frontend routing on backend:8000 and internal database
access on db:5432. Host ports bind only to loopback. The images run as non-root
users and contain no AWS secrets. Local Compose database credentials and session
secret are development-only defaults and must not be reused for AWS or real
users.
- AWS environment and GitHub environment:
sandbox - Parent DNS: Cloudflare manages
asksafe.ai - Route 53 hosted zone:
happy-post.asksafe.ai - Application domain:
happy-post.asksafe.ai - Route 53 hosted-zone ID:
Z07821441TT04VLUXZXPO(non-sensitive configuration) - Delivery model: two images, two ECS services, one ECS cluster, and one HTTPS ALB
- Database: deployed private RDS PostgreSQL 16.14 instance, accessed by the backend only
- Database recovery: automated backups and point-in-time recovery with one-day retention, the maximum permitted by the active AWS Free Plan
- Database sandbox configuration:
db.t4g.micro, Single-AZ, encrypted gp3 storage (20 GiB allocated; 40 GiB maximum); this is a cost-conscious sandbox configuration, not production sizing guidance. - Terraform state: private versioned S3 state plus deletion-protected DynamoDB locking
- ECS scaling: CPU target tracking for each service (1–2 tasks, 65% target)
- Disabled optional services: WAF, Service Connect, blue/green deployment, VPC endpoints, notifications, and end-to-end TLS
| Route | Destination |
|---|---|
/* |
Frontend service |
/api/* |
Backend service |
/frontend/healthz, /frontend/version |
Frontend service |
/backend/healthz, /backend/version |
Backend service |
flowchart LR
users[Internet users] --> cloudflare[Cloudflare DNS<br/>asksafe.ai]
cloudflare -->|NS delegation| route53[Route 53<br/>happy-post.asksafe.ai]
route53 -->|A alias resolution| alb[Internet-facing ALB<br/>HTTPS :443]
acm[ACM public certificate] -. "TLS certificate" .-> alb
alb -->|/*| frontend[Frontend ECS Fargate<br/>Next.js]
alb -->|/api/*| backend[Backend ECS Fargate<br/>FastAPI]
backend -->|PostgreSQL 5432| rds[Private RDS PostgreSQL]
frontend -. logs .-> logs[CloudWatch Logs]
backend -. logs .-> logs
The diagram shows DNS delegation and high-level request routing. Cloudflare remains the parent DNS provider for asksafe.ai and delegates happy-post.asksafe.ai to the Route 53 hosted zone. Route 53 resolves the application domain to the internet-facing ALB; ACM terminates HTTPS at that ALB.
The maintainable logical source is solution architecture. The focused runtime diagram and delivery/control-plane diagram are explained in Architecture.
- Architecture
- Networking
- CI/CD and control plane
- Requirements traceability
- Implementation backlog
- Security decisions
- Deployment and rollback
- Operations
- Git and pull-request conventions
- Diagram sources
CloudFormation bootstrap created the private state bucket happy-post-tfstate-893794041695-ap-southeast-2 and lock table happy-post-sandbox-terraform-lock, using logical state prefix sandbox/. Its version-controlled source is infra/bootstrap/happy-post-terraform-bootstrap.yaml. The state bucket is versioned and retained; the lock table is deletion-protected and retained on bootstrap stack delete or replacement. Sandbox has no required reviewers. A deliberate bootstrap teardown requires documented approval, safe removal of dependent Terraform state, disabling DynamoDB deletion protection, then explicit deletion of the retained lock table. Do not place credentials, tokens, or other secret values in this repository.