personal-lifecycle-tracker / terraform / aws-serverless / README.md
README.md
Raw

Option C: Zero-Cost Serverless AWS Deployment (Lambda + Neon + CloudFront)

This directory contains the complete Infrastructure as Code (Terraform) to deploy the Personal Lifecycle Tracker as a $0.00 / month forever, zero-server-maintenance serverless application on AWS with all traditional serverless downsides completely eliminated.


Architecture & Downside Mitigations

                      GLOBAL PUBLIC TRAFFIC
                                │
                                ▼
                   AWS CloudFront (CDN Edge)
          [Free: 1 TB/mo transfer + 10M requests forever]
                 │                             │
    /* (Static React UI)                /api/* & /health
                 │                             │
                 ▼                             ▼
           AWS S3 Bucket             AWS Lambda Function URL
        [Free: 5 GB storage]         (or HTTP API Gateway)
                                 [Free: 1M reqs + 3.2M sec compute]
                                               │
                                               ▼
                                  Containerized FastAPI Backend
                                  with AWS Lambda Web Adapter
                                     (0 lines code changed)
                                               │
                                               ▼
                               Neon Serverless PostgreSQL (Pooled)
                                [-pooler PgBouncer connection]
                                 [Free: 0.5 GB storage + 0.5 CU]
                                               ▲
                                               │
                                 Ping every 4 minutes (SELECT 1)
                                               │
                                  AWS EventBridge Scheduler
                                  [Free: 14M triggers/mo forever]

How the 5 Downsides Are Fixed:

  1. Cold Starts Eliminated (0s delay): EventBridge pings /health every 4 minutes. Both Lambda and Neon remain warm in memory 24/7 for $0.
  2. 100% Dev/Prod Parity: Uses AWS Lambda Web Adapter (aws-lambda-adapter) in backend/Dockerfile. The exact same container runs locally in Docker Compose and in AWS Lambda with zero code rewrites.
  3. Zero Connection Storms: Routes queries through Neon's built-in PgBouncer pooler (-pooler connection URI), multiplexing hundreds of concurrent Lambda requests.
  4. Reliable Morning Email Digest: EventBridge scheduler triggers POST /api/v1/reminders/digest/send at 08:00 AM UTC with dedicated invocation time.
  5. No 15-Minute Migration Lock: Database migrations execute in GitHub Actions CI prior to container swapping.

Step-by-Step Deployment Instructions

Prerequisites

  1. AWS CLI Credentials: Configured with IAM permissions for Lambda, S3, CloudFront, ECR, and EventBridge.
  2. Neon PostgreSQL Free Tier Account: Sign up at https://neon.tech, create a free database, and copy the pooled connection string (...-pooler.us-east-2.aws.neon.tech/lifecycle?sslmode=require).

Step 1: Initialize & Validate Terraform (In Docker)

Validate configuration without host dependencies:

make tf-validate-serverless

Or manually:

docker run --rm -v $(pwd)/terraform/aws-serverless:/workspace -w /workspace hashicorp/terraform:1.7 init
docker run --rm -v $(pwd)/terraform/aws-serverless:/workspace -w /workspace hashicorp/terraform:1.7 validate

Step 2: Configure Variables

Copy the example configuration:

cp terraform/aws-serverless/terraform.tfvars.example terraform/aws-serverless/terraform.tfvars

Edit terraform/aws-serverless/terraform.tfvars with:

  • database_url: Your Neon pooled connection string.
  • secret_key: Random 32-byte hex string (openssl rand -hex 32).

Step 3: Provision Serverless Infrastructure

docker run --rm -v $(pwd)/terraform/aws-serverless:/workspace -v $HOME/.aws:/root/.aws:ro \
  -w /workspace -e AWS_DEFAULT_REGION=us-east-1 hashicorp/terraform:1.7 apply -auto-approve

Note the outputs:

  • ecr_repository_url
  • s3_bucket_name
  • cloudfront_domain_name
  • lambda_function_url

Step 4: Build & Push Backend Container to ECR

# Authenticate Docker with Amazon ECR
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $(terraform -chdir=terraform/aws-serverless output -raw ecr_repository_url)

# Build and tag backend image with Lambda Web Adapter
docker build -t $(terraform -chdir=terraform/aws-serverless output -raw ecr_repository_url):latest ./backend

# Push to Amazon ECR
docker push $(terraform -chdir=terraform/aws-serverless output -raw ecr_repository_url):latest

# Update Lambda function code
aws lambda update-function-code \
  --function-name personal-lifecycle-tracker-api-production \
  --image-uri $(terraform -chdir=terraform/aws-serverless output -raw ecr_repository_url):latest

Step 5: Build & Upload Frontend to S3

# Build static React 19 bundle
docker run --rm -v $(pwd)/frontend:/app -w /app node:20-alpine sh -c "npm install && npm run build"

# Sync build to S3
aws s3 sync frontend/dist s3://$(terraform -chdir=terraform/aws-serverless output -raw s3_bucket_name)/ --delete

Step 6: Verify Live Deployment

Open your production CloudFront and Lambda endpoints:

# Verify Backend Health via Lambda Function URL
curl -s https://7ksomsylvke2uawuhhccbfr6hy0agzyb.lambda-url.ap-south-1.on.aws/health
# Expected Output: {"status":"healthy","database":"connected","version":"1.0.0"}

# Verify CloudFront CDN distribution
curl -sI https://d1ca9upoitnq9b.cloudfront.net/ | grep -E "HTTP|server|via"
# Expected Output: HTTP/2 200

Access the full web application at https://d1ca9upoitnq9b.cloudfront.net/. Pre-seeded demo credentials: alex@example.com / password123.