Lesson 0002 · ~15 minutes
Computers route traffic by IP addresses (numbers like 13.224.10.5), not names. DNS (Domain Name System) is the global lookup system that translates portal.caseai.com into the IP address to actually connect to. That's the whole job (Route 53 docs).
Route 53 is just AWS's DNS service — a place where you create records for your domain:
| Record | Means | Example |
|---|---|---|
| A | "this name → this IP address" | caseai.com → 13.224.10.5 |
| CNAME | "this name → that other name" | portal.caseai.com → d1234.cloudfront.net |
You have already used DNS — every domain you've pointed at Cloudflare, every custom-domain CNAME in the Cloudflare dashboard, was you editing DNS records. Route 53 is the same dashboard page, different vendor.
A CDN (Content Delivery Network) is a fleet of cache servers in hundreds of cities. An edge server is whichever one sits closest to the user — at the "edge" of the network, as opposed to the origin, your actual application server (Cloudflare Learning Center — yes, your own vendor explains this best).
When a lawyer in Hong Kong opens the Case AI portal: the JS bundle, CSS, and logo come from an edge server in Hong Kong, not from a datacenter in Virginia. If the edge has the file cached → instant. If not → it fetches from the origin once, caches it, and serves the next thousand users locally.
The reason this feels new: on Cloudflare, the CDN is the platform — every Worker and Pages site you've shipped already ran on edge servers (this very lesson page is being served to your phone from a Cloudflare edge near you right now). AWS unbundles it: CloudFront is an explicit "distribution" you configure in front of an origin (an S3 bucket, or the ALB). Route 53 answers "what IP?", CloudFront answers from the nearest cache, and only dynamic requests travel on to your VPC.
The confusion is two words being used as one:
Lambda IS a backend — without a dedicated server. AWS keeps your function on disk and spins it up only when an event arrives (an HTTP request via API Gateway, an S3 upload, an SQS message). API Gateway + Lambda + DynamoDB is a complete production backend; thousands of companies run exactly that. You've built this pattern yourself — Buddy Ride's backend on Workers + Convex was serverless end-to-end. So no: if you use Lambda, you do not need another backend. The real question is different — when is a dedicated, always-on server (an ECS Fargate container) worth it? Five workload shapes:
| Driver | Why Lambda struggles | Case AI example |
|---|---|---|
| Long jobs | Hard 15-minute timeout | OCR + embed a 500-page filing |
| Persistent connections | Built per-event; WebSockets/streaming are awkward | Streaming an AI draft token-by-token to the portal |
| Latency floor | Cold starts add first-request delay | A lawyer-facing API that must feel instant |
| Steady high traffic | Per-invocation billing beats always-on only when traffic is spiky | The portal at constant weekday load |
| In-memory state | No durable process → no connection pools or warm caches (the classic Postgres-from-Lambda pain) | Pooled Aurora connections, cached prompts |
Interview sound bite: "Serverless doesn't delete the server's job — it slices it per event. I'd run the portal and API as Fargate services because they're steady, streaming, and DB-heavy, and use Lambda for event-driven glue: an S3 upload trigger, an SQS consumer. Any job that could exceed 15 minutes is automatically container work." (That's also AWS's own framing — decision guide.)
Abstract doctrine ("least privilege") becomes real like this. Your API container needs to read case documents from S3. In the real world you:
1. Create a role, e.g. case-api-task-role, that ECS tasks are allowed to assume (ECS task IAM role docs).
2. Attach a policy — a JSON allow-list of exactly what this service may do:
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::caseai-documents/*"
}
3. That's it. At runtime ECS injects short-lived credentials for that role into the container; the AWS SDK finds them automatically. Your code just calls s3.getObject(...) — no keys in env vars, no keys in code, nothing to leak or rotate by hand.
The daily texture of "using IAM" as an engineer: every new service gets its own role; every "can service X read bucket Y?" is a policy edit reviewed in a PR (IAM is code, via Terraform/CDK); and AccessDenied errors are a rite of passage — the fix is adding the one missing action, never reaching for a wildcard *. Humans, meanwhile, log in through SSO and assume roles too — nobody in a well-run shop holds permanent keys (IAM best practices).
Read Cloudflare's "What is a CDN?" (~10 min) — the clearest vendor-neutral explanation, and it doubles as an interview answer bank for latency/caching vocabulary. Skim "What is a CDN edge server?" after it.