apps/web and apps/admin to AWS Lambda + CloudFront through
SST, and decouples deploy from release using PostHog feature flags.
Deploy ≠ release. Code reaches production on Lambda + CloudFront after a
successful
prod deployment; a feature only becomes visible when its PostHog
flag is turned on. A bug may be contained by flipping a flag off without a
deployment rollback.Branch strategy
Four persistent branches, each mapped to an environment and a Neon DB branch. Work flows in one direction:dev → test → pprd → prod. There are no direct
pushes to prod.
The
pprd branch is reset from prod every 24h via the Neon Branch Reset
API (a near-instant copy-on-write operation), then a PII-anonymisation script
scrubs names, phones, and emails so UAT has realistic data without real customer
PII. QStash scheduled jobs target prod only.
Hosting topology
- Web + admin:
apps/webandapps/adminrun on AWS Lambda (ARM64) behind separate CloudFront distributions inap-southeast-1. SST declares both withsst.aws.Nextjs; AWS packaging uses OpenNext. - DNS: Cloudflare remains authoritative DNS only. SST uses the Cloudflare provider for ACM validation and the web/admin aliases; application compute is on AWS.
- CMS: Render (Singapore) continues to host Payload CMS (
rgss-cms,cms.theroyalglow.in). - PDF render: Cloud Run continues to host the invoice PDF service (
@rgss/invoicing). - Database: one Neon PostgreSQL 16 project with four branches.
- Media: Cloudflare R2 remains the S3-compatible object store. Rate limiting + queue: Upstash Redis + QStash. Realtime: Ably.
GitHub Actions workflows
These workflows enforce the gates above and handle production deploys.apps/web and apps/admin are live on AWS through deploy-aws.yml. Payload CMS remains on Render and the invoicing service remains on Cloud Run. Cloudflare hosts authoritative DNS and R2 storage only; earlier Worker deployment workflows and adapters are retired.
Lighthouse gates require performance ≥ 95 and accessibility, best-practices, and
SEO = 100.
Feature-flag release strategy
Every feature ships to prod behind a PostHog flag and is exposed gradually.1
Deploy with the flag OFF
A successful
prod deployment places code on Lambda + CloudFront, invisible to everyone.2
Flag ON for role = developer
Self-test directly in production.
3
Flag ON for role = owner | manager
Stakeholder preview.
4
Flag ON for 10% of customers
Watch Sentry for new errors.
5
Flag ON for 100%
Full release to all customers.
6
Remove flag + dead code
After 2 weeks stable, clean up the flag and dead code.
Rollback tiers
When something goes wrong, escalate from the cheapest, fastest lever upward.Flag — UI bug after deploy · < 10 sec
Flag — UI bug after deploy · < 10 sec
Turn the PostHog flag OFF. No deploy, no rollback — the feature simply disappears.
Tier 1 — Successful but bad app release · 3–5 min
Tier 1 — Successful but bad app release · 3–5 min
Run the Deploy AWS workflow with
git_ref set to the last known-good tag or SHA. SST redeploys both sst.aws.Nextjs applications to Lambda + CloudFront. If an SST/Pulumi update fails, inspect the deployment logs and stack state, verify both health endpoints, and redeploy the known-good ref when resources are unhealthy or partially updated.Tier 2 — Bad migration, data corrupted · < 5 min
Tier 2 — Bad migration, data corrupted · < 5 min
Neon PITR to a pre-migration point-in-time branch.
Tier 3 — Neon outage · < 30 min
Tier 3 — Neon outage · < 30 min
Emergency DB restored from the weekly R2 backup.
Health check
GET /api/health probes the database, Redis, and R2 in parallel and returns a
HealthStatus contract: healthy / degraded / unhealthy. It responds 200
for healthy or degraded and 503 for unhealthy, always with
Cache-Control: no-store. BetterStack polls it every ~3 minutes and opens an
incident on status.theroyalglow.in if it fails.
Backups
Related pages
Architecture
Hosting topology and observability layers
Background Jobs
Scheduled work and heartbeat monitoring
Data Model
What the migrations and backups protect
