Skip to main content

Infrastructure

All SA3 infrastructure runs on AWS eu-west-3 (Paris) and is provisioned via Terraform at infrastructure/terraform/sa3/.

AWS Resources

Terraform Files

FileResources
main.tfProvider config, Terraform backend
vpc.tfVPC, subnets (public + private), NAT Gateway, Internet Gateway, route tables
rds.tfRDS PostgreSQL 15 instance, subnet group, parameter group, security group
s3.tfS3 bucket (sa3-files), versioning, lifecycle rules, CORS
cloudfront.tfCloudFront distribution for S3 origin (public assets, signed PDFs)
apprunner.tfApp Runner service, VPC connector, auto-scaling config, custom domain
lambda.tfPDF Lambda function, SQS event source mapping (batch_size=1), DLQ, reserved concurrency
iam.tfIAM roles for App Runner, Lambda; S3, RDS, SQS, KMS, SES permissions
kms.tfKMS keys: sa3-general-encryption-key, sa3-student-pii-key
secrets.tfSecrets Manager for database credentials
ses.tfSES domain identity, DKIM
cloudwatch.tfCloudWatch log groups, alarms
variables.tfInput variables
outputs.tfOutput values (App Runner URL, RDS endpoint, S3 bucket name)

Key Configuration

ResourceValue
RDS instancedb.t3.small (~$0.034/hr)
RDS storage20 GB gp3, encrypted via sa3-general-encryption-key
RDS backups7-day retention, automated snapshots
App Runner1 vCPU / 2 GB, ECR source
App Runner scalingMin 1 instance, max 4
Lambda memory512 MB
Lambda timeout300 seconds
Lambda concurrency10 reserved
SQS visibility timeout360 seconds
SQS DLQmax receive count = 3
CloudFrontS3 origin only (not App Runner)
KMS PII keyRestricted to App Runner + Lambda roles

Hard Constraints

  1. HOSTNAME=0.0.0.0 must be set in App Runner environment variables and Dockerfile. Without it, Next.js binds to localhost and health probes fail.
  2. CloudFront on S3 only. Do not add App Runner as a CloudFront origin -- it breaks Next.js 15 streaming and RSC Vary header routing.
  3. SQS visibility timeout > Lambda timeout. The 360s visibility timeout must exceed the 300s Lambda timeout to prevent duplicate processing.