Thnkrr — Why These AWS Services, and What We'd Switch To
Companion to 18-aws-services-and-costs.md. One section per service: why it's the right pick for this pilot, and the pre-planned exit if we ever want to change it.
The standing rule (docs/04 §11): AWS is certain for the pilot, but nothing may
depend on AWS to exist. Every AWS touchpoint sits behind a small adapter interface in
our code (storage, mailer, imageScreen), and the non-AWS side of each adapter runs
every day in development. Switching vendors is a config change plus a data copy — never a
rewrite. That rule is why the alternatives below are real options, not wishful thinking.
S3 — file storage
Why it's the best fit here:
- It is the industry-standard way to store files, and — crucially — its protocol is a de-facto standard that many vendors implement. Our code speaks "the S3 protocol," not "Amazon."
- Presigned uploads let the browser send image bytes straight to the bucket, so our one API server never carries file traffic — fewer moving parts, the pilot's core criterion.
- Eleven-nines durability for user photos and backups with zero operational work from us.
- At our volume it costs cents; there is no cheaper managed option worth an extra vendor.
Alternatives (in order we'd consider them):
| Alternative | Trade-off |
|---|---|
| Cloudflare R2 | Same S3 protocol (config-change switch). Free egress — becomes attractive only if delivery traffic ever outgrows CloudFront's free tier. |
| Backblaze B2 | Same S3 protocol, cheapest storage per GB. Slightly less ecosystem polish. |
| Google Cloud Storage | S3-compatible mode exists; only sensible if we moved everything to GCP. |
Proof the exit works: development runs on MinIO (an S3-compatible server in Docker) every day. The database stores file keys, never URLs, and images are served from our own domain — so the bucket vendor can change without touching data or links.
CloudFront — image delivery (CDN)
Why it's the best fit here:
- The permanent free tier (1 TB + 10M requests every month) means the pilot pays $0 for all image delivery. No alternative beats free.
- It sits natively in front of S3 (S3→CloudFront transfer is free) with no extra account, billing relationship, or integration work.
Alternatives:
| Alternative | Trade-off |
|---|---|
| Cloudflare CDN | Also effectively free; the natural pair if storage moved to R2. |
| Fastly / bunny.net | Fine products; another vendor for no benefit at this scale. |
Exit cost: near zero. A CDN is a DNS-level layer; media URLs are on our own domain, so swapping CDNs is a DNS change and a cache warm-up, invisible to users and to the database.
SES — transactional email
Why it's the best fit here:
- Cheapest option in the market at $0.10 per 1,000 emails, pay-as-you-go, no monthly fee. (SES also sells tiered "plans" — Essentials at $0.16/1,000 and up; irrelevant at our volume, we stay pay-as-you-go.)
- We send only three plain, low-volume emails (verify, reset, consent). We need deliverability and a price near zero — not templates, campaigns, or analytics.
- Our mailer speaks generic SMTP, and SES has an SMTP endpoint — so SES is just configuration, not integration.
Alternatives:
| Alternative | Trade-off |
|---|---|
| Postmark | Best-in-class transactional deliverability; ~$15/month minimum. The first switch we'd make if consent emails ever showed spam-folder problems — the guardian email is the legal consent instrument (docs/14 §3: the link expires in 7 days, resends are capped, and a never-arriving email pushes the school to the paper form), so its deliverability is worth paying for. |
| Resend | Modern, generous free tier (3,000 emails/month), developer-friendly. |
| Any SMTP provider | The adapter is literally an SMTP URL in an environment variable. |
Proof the exit works: development and tests run against Mailpit (a local SMTP inbox). Switching providers is changing one environment variable.
Rekognition — automated image screening (deferred)
Why it's the (future) pick:
- The one genuinely AWS-proprietary service in the stack — used only because it's the turnkey option already inside our AWS account, priced per image with no minimum.
- Not enabled in the pilot (decision D-9): at pilot volume, human review of every image is safer than a half-tuned automated path, and this is a child-safety surface — fail-closed beats convenient.
Alternatives:
| Alternative | Trade-off |
|---|---|
| Google Cloud Vision SafeSearch | Equivalent capability and price shape; a second cloud account. |
| Hive Moderation | Moderation specialist, finer-grained categories; separate vendor and contract. |
| Claude (vision) | We already have the Anthropic relationship and the moderation prompt/taxonomy; one vendor for all moderation. Likely the actual choice when this turns on. |
Proof the exit works: the imageScreen adapter seam exists in the pipeline today;
the pilot's implementation of it is "send to human queue," which is also the permanent
fallback for any vendor's uncertain verdicts.
Text moderation and AWS — evaluated, not used
Text moderation runs on Anthropic's Claude API (not AWS), and the moderation research (docs/15 §2.4) compared the field before the §3a bake-off. Two Amazon options were on the table, for the record:
| Amazon option | Verdict |
|---|---|
| Amazon Comprehend (toxicity detection) | Rejected: English only, 7 fixed classes, and none of the categories that matter most here — grooming, contact-details exchange, spam. No known platform uses it for member content. |
Amazon Bedrock (hosting gpt-oss-safeguard, an open policy-following model, at $0.07/$0.20 per MTok, no retention for open models) | Possible future touchpoint: one of the shortlisted zero-retention hosts if the docs/15 §3a golden-set bake-off picks that model over the incumbent Claude connector. Not a commitment — Groq offers the same model on the same terms. |
If Bedrock is ever chosen, it enters through the same rule as everything else: behind the existing moderation connector seam, swappable, with the human queue as the fail-closed default.
Backend hosting & the database — why Render today, and the AWS path later
The API and Postgres deliberately do not run on AWS today (docs/04 §11). Since "should we?" keeps coming up, here is the full reasoning. Costs for every path are in docs/18's last section.
The constraint that decides everything: the backend is one always-on Node process with the job workers (pg-boss) running inside it, polling Postgres every few seconds. That shape is a safety feature — moderation jobs enqueue in the same database transaction as the content they screen. It rules out, on architecture alone:
- Lambda / anything serverless — there is no long-running process to host the workers.
- App Runner (AWS's closest thing to Render) — it throttles CPU to near-zero between web requests and scales on request traffic only. A background worker with no incoming requests is exactly what it starves. The moderation queue stalling silently is the worst failure mode this platform can have.
- Aurora Serverless v2 as a money-saver — its pitch is "pause when idle," and our job queue guarantees the database is never idle. We'd pay ~3× RDS for nothing.
Why Render wins the pilot on merit, not inertia:
- Zero-downtime deploys on git push, TLS, health checks, restart-on-crash, staging → promote — all included, all things we'd assemble by hand on AWS.
- Managed Postgres with automated backups and point-in-time recovery in the same dashboard as the app.
- Comparable or cheaper in dollars ($13–45/month) and much cheaper in attention — and attention is the scarce resource in a pilot run by a tiny team.
- Nothing about it is load-bearing lock-in: the app is a container, the DB is plain
Postgres.
pg_dumpout, restore anywhere.
The AWS paths, ranked for when we do move:
| Path | When it's right | Why not now |
|---|---|---|
| ECS Fargate (ARM) + ALB + RDS Postgres | The designated landing zone: real deploy pipeline, Multi-AZ database, room to split the worker into its own service later. | ~$60–77/month and a genuine ops surface (IAM, task definitions, security groups, alarms) — paying more to babysit more, at 10k users. |
| Lightsail VPS + Lightsail Postgres | If the only goal were "everything on one AWS bill" at minimum cost (~$27/month). | It's a VM: we become the deploy pipeline, the TLS renewal, and the 3am restart. Violates the foolproof rule. |
| EC2 + RDS | Same as Lightsail with more knobs. | Same babysitting, more console. |
| App Runner / Lambda / Aurora Serverless | Never for this architecture (see above). | — |
Non-AWS alternatives to Render (same managed-PaaS shape, if Render itself disappoints): Railway (usage-based, ~$5 base), Fly.io (containers near users), Heroku (the original, pricier). For the database alone: Neon and Supabase are excellent managed Postgres, but their serverless/auto-suspend economics are wasted on a database our job queue never lets sleep — a plain always-on Postgres is the honest fit.
The exit, proven: everything runs in Docker locally every day; the database is
vanilla Postgres 16 with plain SQL migrations. Moving Render → AWS (or anywhere) is:
build the container, restore a pg_dump, repoint DNS. Days, not months — by design.
What we deliberately do NOT use AWS for
| Not used | Why |
|---|---|
| Cognito (auth) | Auth is fully internal — for a minors' platform, no third party should hold children's credentials, and a ban must not depend on someone else's API (docs/04 §6). |
| RDS / DynamoDB (database) | Postgres lives with the app on Render — one dashboard, backups included (full comparison in the hosting section above; RDS is the later landing zone). DynamoDB is proprietary lock-in with no benefit at 10k users. |
| Lambda / ECS / EC2 (compute) | One boring Node process on a PaaS is the foolproof shape (see the hosting section above; Fargate is the later landing zone). Serverless is architecturally incompatible with our in-process job workers. |
| SQS / EventBridge (queues) | pg-boss rides the existing Postgres and makes job enqueue transactional with the data change — a safety property SQS can't give us. |
The pattern: AWS is used where it's a commodity behind a standard protocol (files, email, CDN), and avoided everywhere it would become architecture. That's what keeps the exit cheap and the pilot bill at a few dollars.