A serverless resume website that runs the same FastAPI code locally (Docker) and in production (AWS Lambda). Includes a floating AI chat widget powered by Bot Factory. Update your resume via Excel, deploy with Terraform.
Live: robrose.info
git clone https://github.com/mr-flowjangles/aws-serverless-resume.git
cd aws-serverless-resume
cp .env.example .env
mkdir -p _scratchEdit .env with your reCAPTCHA secret key and SES email addresses. See Configuration below for details.
Open scripts/resume-data-template.xlsx in Excel or Google Sheets and fill in your profile, work experience, education, and skills.
make upOpen http://localhost:8080. API docs at http://localhost:8080/api/docs.
See README_DEPLOY.md for complete deployment instructions.
Browser → Nginx → FastAPI (uvicorn) → LocalStack DynamoDB
Browser → CloudFront → Lambda Function URL (FastAPI + Mangum) → DynamoDB
→ Chat Widget → Bot Factory Lambda (SSE streaming) → Bedrock Claude
Same Python code, different wrapper. Mangum adapts FastAPI to Lambda's event format. The RobbAI chat widget connects client-side directly to Bot Factory's streaming endpoint.
aws-serverless-resume/
├── api/ # Backend (runs in Lambda)
│ ├── handlers/ # Business logic (environment-agnostic)
│ │ ├── contact.py # Contact form + reCAPTCHA + SES
│ │ ├── db.py # DynamoDB connection
│ │ ├── health.py # Health check
│ │ └── resume_all.py # Resume data (cached)
│ ├── routers/ # FastAPI route definitions
│ ├── tests/ # pytest suite
│ ├── main.py # FastAPI app setup
│ ├── lambda_handler.py # Mangum wrapper (Lambda entry point)
│ ├── seed.py # Auto-seeds DynamoDB locally
│ ├── requirements.txt # Full dependencies (local dev)
│ ├── requirements-lambda.txt # Slim dependencies (Lambda only)
│ ├── Dockerfile # Local dev container
│ └── Dockerfile.lambda # Lambda build container
├── app/ # Frontend (served by CloudFront)
│ ├── index.html # Single-page app (Welcome, About, Projects, etc.)
│ ├── scripts/
│ │ ├── api.js # API client
│ │ ├── navigation.js # Tab navigation and section loading
│ │ ├── architecture.js # Architecture diagrams
│ │ ├── projects.config.js # Project card definitions
│ │ ├── loaders.js # Section data loaders
│ │ ├── contact.js # Contact form handler
│ │ └── chat-widget.js # RobbAI floating chat (connects to Bot Factory)
│ └── assets/
│ ├── main.css # Core styles
│ ├── mobile.css # Mobile responsive styles
│ ├── architecture.css # Architecture section styles
│ └── chat-widget.css # Chat widget styles
├── scripts/
│ ├── resume-data-template.xlsx # Resume data (single source of truth)
│ ├── load_resume.py # Excel → DynamoDB loader
│ ├── build-lambda.sh # Lambda package builder
│ └── init-dynamodb.sh # LocalStack table setup
├── terraform/ # Infrastructure as Code
├── docker-compose.yml # Local development setup
├── Makefile # Convenience commands
└── README_DEPLOY.md # Deployment guide
- Get keys at https://www.google.com/recaptcha/admin (v2, "I'm not a robot")
- Add domains:
localhost(dev) and your production domain - Put the secret key in
.envasRECAPTCHA_SECRET_KEY - Put the site key in
app/index.htmlin thedata-sitekeyattribute
aws ses verify-email-identity --email-address your@email.com --region us-east-1Add to .env:
SES_FROM_EMAIL=your@email.com
SES_TO_EMAIL=your@email.comaws configureRegister in Route 53 and update terraform/variables.tf. Terraform handles SSL and DNS.
# Local
docker compose exec api python /app/scripts/load_resume.py /app/scripts/resume-data-template.xlsx
# Production
AWS_ENDPOINT_URL="" AWS_REGION="us-east-1" python3 scripts/load_resume.py path/to/your-resume-data.xlsxBackend: Python 3.12, FastAPI, Mangum, boto3 Database: DynamoDB (LocalStack locally, AWS in production) Frontend: HTML, CSS, vanilla JavaScript AI Chat: RobbAI widget powered by Bot Factory (SSE streaming) Email: AWS SES Security: Google reCAPTCHA v2 Local Dev: Docker, Docker Compose, Nginx, LocalStack AWS: Lambda (Function URL + streaming), API Gateway, S3, CloudFront, Route 53, ACM, DynamoDB, SES Infrastructure: Terraform (100% IaC) Testing: pytest, pre-commit hooks
docker compose exec api pytest tests/ -vPre-commit hooks run tests automatically before every commit:
pre-commit installFor a personal resume site (<1,000 visitors/month): ~$3-10/month. Route 53 ($0.50), CloudFront ($1-2), Lambda/API Gateway/DynamoDB/SES (free tier), S3 ($0.50), ACM (free).
© 2026 Rob Rose. All rights reserved.
This project is provided for personal and educational use. If you fork or reuse, please provide attribution and link back to the original repository.
Built with FastAPI, Mangum, Terraform, LocalStack, and Claude as a development partner.