Files
baya-monorepo/mvp/blocker-phases/15-debug-mode-production.md
T
2026-08-02 20:37:14 +03:30

55 lines
3.8 KiB
Markdown

# Phase 15 — Turn off developer/debug mode on the live site
**Blocker:** blockers.md §B.2. Do this deliberately, on its own, right before any real stranger is let near
the site — it touches deploy config and secrets handling, not app logic, and has real prerequisites.
**Depends on:** nothing code-wise, but bundle with credential rotation (blockers.md §B.1) when you do it —
currently deferred per your own call, revisit before real users arrive.
---
**Root cause.** The exposure (`GET api/v1/dev/last_otp/{phone}`,
unauthenticated by design, guarded only by `environment.IsDevelopment()`) is correctly implemented in code
— the entire gap is that the deployed `docker-compose.yml` sets `ASPNETCORE_ENVIRONMENT: Development`,
**deliberately and already documented** (a comment in the compose file and a full section in `DEPLOY.md`
spell out why and what depends on it).
This is **not** a one-line flip — five real prerequisites, already documented in `DEPLOY.md`, need to land
together:
1. Create `server/src/API/Baya.Web.Api/appsettings.Production.json` with real (non-`not-for-production`
sentinel) `IdentitySettings:SecretKey`/`Encryptkey``StartupSecretsGuard` rejects the sentinel outside
Development, so a bare env-var flip with the current file would refuse to boot.
**`Seams:FieldEncryption:Key`/`:HashKey` must be copied byte-identical** from the current Development
value — never regenerated (root `CLAUDE.md` rule 6 — this key decrypts all existing PII).
2. Set `ASPNETCORE_ENVIRONMENT: Production` in `docker-compose.yml`.
3. Switch migrations from boot-time auto-apply (Development-only branch) to the documented one-shot
(`... migrate`) deploy step — and confirm the demo/lifecycle seed data the shared DB currently relies on
survives the transition, since those seeders stop running automatically post-flip.
4. Swap `Seams:Sms:Provider` from `telegram` (a broadcast-to-a-fixed-chat-list relay, fine for trusted
internal testers, not for strangers) to `kavenegar` with a real API key — flipping only the environment
variable closes the `/dev/last_otp` leak but leaves OTPs going out over the Telegram relay instead of to
the real phone.
5. Bundle with credential rotation (blockers.md §B.1) when you do it — the same config file carries the DB
password alongside the encryption keys.
**Flag:** whether to keep the Telegram relay live in parallel with `kavenegar` for internal/test accounts
post-launch, or retire it entirely, is a product/ops call, not answered by the code.
---
## Not phases — noted here so they aren't lost, but no code to write
- **§B.1 (rotate committed credentials)** — per your call, skipped for now (private repo, single developer).
Revisit before any real user touches the deployed site; bundle with step 5 above when you do.
- **§B.3 (legal review of Terms/Privacy)** — not a code task; needs an actual legal review.
- **§B.4 (مودیان e-invoicing)** — per your call, not built now. When you pick it up: the invoice data and tax
math are already correct; the only missing piece is the actual government-facing registration call, and it
needs a chosen provider/gateway before any adapter code makes sense. Add a note to forgotten-features.md
saying exactly that, rather than building a speculative seam with nothing real to point it at.
- **§B.5 (e-namad certification)** — a business/paperwork step, not a code change; also gates the real
ZarinPal card-payment path ([07-card-payment-redirect.md](07-card-payment-redirect.md)) from ever going
fully live, independent of any code fix.
- **§B.6 (real bank-transfer payout rail)** — per your call, stays mocked. Resolved by
[11-nurse-payouts.md](11-nurse-payouts.md) — the seam already exists server-side; only the client UI in
front of it was missing.