# 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](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: ```bash make tf-validate-serverless ``` Or manually: ```bash 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: ```bash 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 ```bash 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 ```bash # 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 ```bash # 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: - **Live Web Application (CloudFront)**: [https://d1ca9upoitnq9b.cloudfront.net/](https://d1ca9upoitnq9b.cloudfront.net/) - **Live Backend API Health**: [https://7ksomsylvke2uawuhhccbfr6hy0agzyb.lambda-url.ap-south-1.on.aws/health](https://7ksomsylvke2uawuhhccbfr6hy0agzyb.lambda-url.ap-south-1.on.aws/health) - **Interactive Swagger Docs**: [https://7ksomsylvke2uawuhhccbfr6hy0agzyb.lambda-url.ap-south-1.on.aws/docs](https://7ksomsylvke2uawuhhccbfr6hy0agzyb.lambda-url.ap-south-1.on.aws/docs) ```bash # 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/](https://d1ca9upoitnq9b.cloudfront.net/). Pre-seeded demo credentials: `alex@example.com` / `password123`.