Behind the Build

Technical decisions, patterns learned, and the evolution across 19 projects

19
Projects Shipped
9
AI Projects (Bedrock)
20+
AWS Services Used
2
Live Sites (CI/CD)

Architecture Patterns That Stuck

Serverless Everything

Every project runs on Lambda. No EC2, no containers, no idle costs. Function URLs for simple APIs, API Gateway when CORS or routing gets complex, SAM when the stack has multiple resources.

LambdaAPI GatewayFunction URLs

AI as a Decision Layer

Bedrock Nova Lite isn't just for chatbots. Used it as a reasoning engine inside Step Functions (Failover Orchestrator), a code reviewer (Architecture Reviewer), and a document analyzer (Resume Radar, Cost Optimizer).

BedrockNova LiteStructured JSON

Event-Driven Pipelines

S3 events trigger Lambda, SQS buffers async work, EventBridge schedules recurring jobs, Step Functions orchestrate multi-step workflows with conditional branching. No polling, no cron servers.

EventBridgeSQSStep FunctionsS3 Events

Single-Table DynamoDB

Failover Orchestrator uses one table with pk/sk pattern: HEALTHCHECK|timestamp, INCIDENT|timestamp, CONFIG|status. TTL handles cleanup. On-demand billing keeps costs at pennies.

DynamoDBpk/sk PatternTTL

Infrastructure as Code Evolution

# Phase 1: Manual AWS CLI (Projects 1-5, 8) aws lambda create-function --function-name MyFunc ... aws lambda create-function-url-config ... aws iam create-role ... # Phase 2: SAM/CloudFormation (Projects 6, 7, 9) AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 sam build && sam deploy # One command deploys everything # Phase 3: CI/CD (Both repos) git push origin main # GitHub Actions → S3 sync → CloudFront invalidation # OIDC federation — no stored AWS credentials

Hard Lessons

S3 --delete Flag

CI/CD workflow with --delete wiped S3 files that didn't exist locally. Now: always verify S3 contents before sync. Safety rule added to project rules.

Bedrock IAM Scope

Foundation model ARNs don't work for inference profiles. Learned to use Resource: "*" for bedrock:InvokeModel. Scoping down requires knowing the exact inference profile ARN.

CSP Headers

CloudFront security headers block everything not whitelisted. Every new Lambda URL or external font needs to be added to the Content-Security-Policy. Switched to wildcards.

CORS Double Headers

Lambda Function URL CORS config + Lambda response CORS headers = browser rejection. Pick one. Function URL config handles it — don't duplicate in code.

SAM Config Gotcha

samconfig.toml requires version = 0.1 at the top. Missing it causes cryptic errors. PC Matic blocks SAM and Python — must whitelist both.

CloudFront Cache

Deployed code but saw old page. Always invalidate CloudFront after deploy. CI/CD now does this automatically. Hard refresh (Cmd+Shift+R) for local browser cache.

Security Posture

# What's enforced across both sites: Content-Security-Policy: default-src 'self'; connect-src 'self' https://*.lambda-url... Strict-Transport-Security: max-age=31536000; includeSubdomains X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff # Authentication: OIDC Federation — GitHub Actions authenticates to AWS without stored credentials IAM Least Privilege — Each Lambda gets only the permissions it needs TLS 1.2+ — Enforced on both CloudFront distributions

Cost Reality

~$100/mo → ~$20/mo

Replaced RDS, ALB, ASG, and VPC infrastructure with serverless equivalents. HA Web App became Resume Radar (single Lambda). Six old CloudFront distributions and three S3 buckets removed. Same functionality, 80% cost reduction.

What Drives the $20

Amazon Q IDE subscription is the largest line item. After that: Route 53 (~$0.50), Bedrock Nova Lite (~$0.15), DynamoDB on-demand (pennies), S3 + CloudFront (pennies). Nine AI projects, two live sites, CI/CD pipelines — all within free tier or near-zero cost.