# plan-prod — designing production environments

Audience: AI coding agents first. Scope: BEFORE prod exists — architecture/sequencing decisions. Setting it up → `setup-prod.md`.

## When prod gets created — the rule

**Create prod when the first end-to-end slice is deployable — typically week 1, never at "feature-complete".** The deploy path is product code: unexercised = broken. Every capability that only works "for real" in prod (live payment webhooks, real OTP/SMS, email deliverability, DNS/TLS, cron at scale, real-latency DB) stays UNVERIFIED until prod exists — and those are exactly the launch-blocking ones. Measured cost of deferring (owner's own repos, 2026): two apps at ~75% product surface, 0% production layer, both unlaunchable.

Launch is a separate, later act: waitlist/flag off. NEVER conflate.

## Decisions that MUST be made before build tasks are written

One-way-door or rewrite-priced decisions. Each unmade decision here has a measured multi-week rewrite cost (owner switched payment providers twice: ~6 weeks lost).

- [ ] **Host + plan tier** — write the quota inventory NOW: cron count, CPU/exec-time ceiling, queue availability, bundle size, egress. Check the app's heaviest job against the ceiling (a settlement job doing 1,000 SQL round-trips does not fit a 10ms-CPU free tier). NEVER claim a limit from memory — read the plan tier first. When a limit bites, evaluate the ARCHITECTURE remedy before the paid-tier remedy: often a primitive on the same plan has a higher ceiling (e.g. CF: cron-count/CPU gaps solved by moving scheduled work into a DO `alarm()` dispatcher — 30s DO CPU vs 10ms worker, zero native crons), and the architectural fix is the durable one.
- [ ] **Payment provider** — ONE. Selection inputs: which approves this business fastest, local invoice/receipt/tax law, webhook + refund + test-mode quality. Multiple provider adapters "to decide later" = the anti-pattern that cost 6 weeks; carry exactly one.
- [ ] **DB topology** — prod branch/instance separate from dev/preview; who may hold prod credentials (CI + break-glass only); pooled vs unpooled connections for jobs vs requests.
- [ ] **Domain + email sender** — apex vs www, who owns DNS; sender domain warms reputation slowly and blacklists fast → decide sending domain + provider early, never re-point casually.
- [ ] **Secrets store** — one source of truth (host secret store via CI), with a manifest (name, scope, required-by) checked into the repo. Values NEVER in repo.
- [ ] **Environment set** — standard: `dev` (local) / `preview` (per-PR or staging) / `production`. Same code, same config *mechanism*, different values (12-factor). Prod-only code paths = untestable paths; allow only env-gated toggles, never divergent logic.

## Sequencing — walking skeleton

1. Thinnest end-to-end slice deployable (one page, one health endpoint).
2. Prod env + pipeline + smoke (see `setup-prod.md`) — NOW, behind a flag/waitlist.
3. Every subsequent feature merges → auto-deploys → smoke-verified in prod, dark.
4. Real-money/real-auth verification (one live transaction, one real login) as soon as the money path exists — NOT at the end.
5. Launch = flip the flag.

Dependency direction: features depend on prod for verification. Building 100% of features then prod = 100% of launch-critical paths unverified at maximum sunk cost.

## Budget prod like a feature

Prod work gets GOLIVE.md acceptance criteria like everything else (env exists, deploy fires on tag, health 200, smoke green, live ₪1 transaction observed). If the project tracks % done, the prod layer is IN the denominator from day 1.

## Blast-radius register (write it during planning)

List what is irreversible or slow-reversible for THIS app: domain cutover, email sender reputation, webhook URLs registered with providers, app-store/OAuth review cycles, data residency. Each gets a "decide early / change never casually" tag. Everything else is two-way-door — decide fast, don't over-deliberate.
