The central architectural bet: two completely different infrastructure stacks for two completely different load profiles.
IDLE MODE — ~$35/MONTH
A single EC2 instance (t3.small) runs everything: Next.js frontend, Express backend, BullMQ worker, and a local Docker Redis container. Handles admin work, registration, payment webhooks, and result pages between contests.
LIVE MODE — +$14–30/CONTEST DAY
Terraform spins up an ALB, an ElastiCache Redis replication group (primary + replica, HA), and an Auto Scaling Group of quiz-serving EC2 instances (2–10, sized by expected participant count). Route53 switches from an A record to an ALB ALIAS record.
Mode switching is orchestrated by two scripts: go-live.sh (Terraform apply → DNS propagation wait → health-check polling → smoke tests) and go-idle.sh (drain BullMQ queues → Terraform destroy live resources → verify DNS reverted).
The backend enforces strict module boundaries: every domain (contest, participant, quiz, payment, proctoring) has its own routes/controller/service/repository layer. Only primitive identifiers cross module boundaries — no cross-domain joins.