How This Was Built
The portfolio itself is a working demonstration of platform engineering — IaC-provisioned CDN, CI/CD-automated deployments, and a Next.js SSR app wired together with Terraform and AWS Amplify.
DEPLOYMENT PIPELINE
GitHub
Source Control
Main branch — push triggers Amplify CI
Amplify CI
Build Pipeline
npm ci → npm run build (Next.js 16 + Turbopack)
Next.js 16
SSR Build
App Router, TypeScript, Tailwind CSS v4
CloudFront
Amplify Hosting CDN
Global CDN — serves the Next.js app
PHOTO CDN PIPELINE (TERRAFORM)
S3 Bucket
private
OAC
sigv4 signing
CloudFront
PriceClass_100
Browser
immutable cache
Bucket policy scoped to CloudFront ARN via AWS:SourceArn — S3 is never publicly accessible
INFRASTRUCTURE BREAKDOWN
AWS Amplify
Hosting + CI/CDAmplify detects every push to main and triggers a full build. The build spec (amplify.yml) runs npm ci and npm run build, then Amplify deploys the Next.js output behind CloudFront automatically. No manual deploy steps.
- Auto-deploy on push to main
- Build spec: amplify.yml
- Next.js SSR support via Amplify Hosting
- Environment variables for CDN URL injection
Terraform
Infrastructure as CodeThe photo CDN infrastructure is provisioned with Terraform: a private S3 bucket and a CloudFront distribution connected via Origin Access Control (OAC). The bucket is never publicly accessible — CloudFront is the only allowed reader, scoped by AWS:SourceArn in the bucket policy.
- S3 bucket: private, public access fully blocked
- CloudFront OAC: sigv4 signing, replaces legacy OAI
- Bucket policy: scoped to CloudFront distribution ARN
- 1-year immutable cache TTL, brotli + gzip compression
- PriceClass_100: US, Canada, Europe
S3 + CloudFront CDN
Photo DeliveryPortfolio photos are stored in S3 and served via a dedicated CloudFront distribution, separate from the app hosting. This keeps large binary assets out of the deployment pipeline while giving photos their own long-lived cache headers (max-age=31536000, immutable).
- Photos uploaded via scripts/upload-photos.sh
- Cache-Control: public, max-age=31536000, immutable
- CloudFront invalidation on re-upload
- NEXT_PUBLIC_PHOTO_CDN_URL injected at build time
Next.js 16
FrameworkApp Router with per-route server and client components. Dynamic case study routes (/projects/[id] and /experience/[slug]) are server components that resolve params and pass them to client content components. Turbopack handles local development. Rajdhani + Geist fonts via next/font.
- App Router: server components by default
- Dynamic routes: instant = false for params resolution
- Turbopack: local dev HMR
- next/font: Rajdhani (headings), Geist Sans/Mono
- TypeScript strict mode throughout
FULL STACK
AWS Amplify
Hosting
CloudFront
CDN
S3
Storage
Terraform
IaC
Next.js 16
Framework
TypeScript
Language
Tailwind CSS v4
Styling
Turbopack
Bundler
GitHub
Source Control
Rajdhani
Typography
Framer Motion
Animation
react-type-animation
UI