# Refinement phases — making Balinyaar work as one integrated app

**Created:** 2026-07-10 · **Scope:** the whole repo (client + server) after the 16+16 phase chain completed ·
**Method:** a read-only audit of the live code (three parallel exploration passes over the frontend wiring, the
backend runnability/infra, and the frontend↔backend contract), cross-checked against `dev/` docs.

This directory is a **runnable chain of 10 refinement phases** that takes the repo from *"both projects build
and each runs on its own, but they aren't actually integrated"* to *"one working app where the logic takes
effect."* Run them **in order, one at a time**, pointing a fresh agent at one phase file
(*"Execute `dev/post-phase/refinement/refinement-phase-0-bring-up.md` end to end"*).

> **Why this exists alongside [`../server/`](../server/README.md).** The existing
> [server post-phase audit](../server/post-phase-backend-plan.md) is excellent — but it audits the **backend in
> isolation**. It never covers the thing you actually hit when you ran the app: the two projects were built in
> **parallel, decoupled lanes and never run against each other**. This chain adds the missing **integration +
> frontend track** (phases 0–4) and folds the server audit's 8 buckets into the back half (phases 5–9) in the
> right order.

---

## Two things that are NOT wrong (correcting the brief)

You suspected these; the audit found they're actually fine — which is good news:

1. **"Database migrations are behind" — they're not.** There are **17 EF migrations** tracking every backend
   phase b0→b15; the model snapshot is in sync and the working tree is clean. `Program.cs` applies them on every
   boot. If it *felt* like migrations were behind, it's because your **target database was never migrated** (you
   were running the frontend on mocks, so nothing ever touched a real DB) — not because migration files are
   missing. The real DB gap is **no local-dev database story + no demo seed data** (Phases 0–1), not drift.
2. **"Missing services like Redis / Elasticsearch" — not needed for the MVP.** The **only external service the
   backend requires today is SQL Server.** All 18 vendor/infra dependencies (cache, lock, jobs, storage, SMS,
   payments, KYC, geocoding, search, moderation) are **in-process mocks behind DI seams — by design.** Redis
   becomes necessary only when you run a **second API instance** (Phase 7); Elasticsearch is **never MVP** (the
   SQL search is real and correct). You didn't miss configuring them.

---

## What's actually wrong (the problem inventory)

Every item below is verified in the live code (file/line evidence is in the phase files).

### A. The frontend barely talks to the backend
- **21 of 22 client service domains default to an in-browser mock** (`USE_*_MOCK = true`, hard-coded literals in
  each `services/{domain}/constants.ts`). **Only `auth` is real by default.** So a running app shows fake
  in-memory data everywhere except login. → **Phase 4** (flip them, in dependency order).
- **The backend has no CORS at all** (zero `AddCors`/`UseCors` in `server/`). Even the calls the frontend *does*
  make would be blocked by the browser once the two run on different origins. **This is the #1 hard blocker.**
  → **Phase 0**.
- The client is correct and ready (`clientFetch` reads `NEXT_PUBLIC_API_URL`, unwraps the `ApiResult` envelope,
  does silent 401 refresh); each domain's real `clientApi` already maps the live routes 1:1. The swap is a
  **one-line flag flip per domain** — *once the backend serves what that domain needs* (see C).

### B. "No auth / only the customer side shows"
- Auth **is** real and works — but a fresh phone login holds only the `customer` role, so `resolveRoleDestination`
  sends everyone to the customer app (which lives at the root `/`). Nurse/admin shells are never auto-reached.
- A hard-coded `DEFAULT_ROLE = customer` fallback means **un-hydrated or failed `/me` role state silently renders
  the customer shell** — a nurse can be shown the customer app. There are no client-side role guards.
- OTP delivery is a **log statement** (`LoggingSmsSender`), so "logging in" requires reading the code from the
  server console — fine for dev, but there's no real SMS yet. → **Phase 2** (role reachability + robust
  hydration + guards) and **Phase 0/8** (the dev OTP bridge, then real SMS).

### C. Frontend ↔ backend contract mismatches (the real "mismatch" you sensed)
- The frontend filed **37 contract requests (REQ-001…037) — all still `Status: open`.** They're why 21 domains
  are mock-primary: a DTO missing a field, or a customer read that only exists as an admin route. Almost all are
  **additive** (nullable fields, new read endpoints). → **Phase 3**.
- Three concrete shape mismatches to reconcile before flipping the matching mock: partner-center **kebab-case**
  routes that violate the snake_case convention; the BNPL **`balinyaar`** provider not in the wire enum; the
  **client-invented cancellation-policy codes**. → **Phase 3**, verified in **Phase 4**.

### D. It can't start cleanly / shows nothing
- The backend only boots against a **committed remote SQL Server** (leaked `sa` credentials); no local default,
  no SQLite fallback for `dotnet run`. → **Phase 0/1** (local DB) and **Phase 5** (rotate the leak).
- A fresh DB seeds only lookup tables + one admin + one gateway — **no nurses, variants, or search rows** — so
  search/discovery/booking are empty even on the real path. → **Phase 1** (demo seed).

### E. Production-readiness gaps (from the server audit — real, but after "make it work")
- Committed secrets & dev-grade defaults (Phase 5); one genuine money hole — the **unreachable BNPL/manual refund
  clearing** (Phase 6); **no unattended operation** — nurses aren't paid unless an admin clicks (Phase 7); every
  vendor rail is mocked — **SMS is launch-critical** (Phase 8); metrics-only observability + doc drift (Phase 9).

---

## The 10 refinement phases

Run top to bottom. Phases 0–4 make the app **work as an integrated whole**; phases 5–9 make it
**production-ready** (and largely re-sequence the [server audit](../server/post-phase-backend-plan.md)).

| # | Phase | Track | Fixes (from above) | Depends on |
| --- | --- | --- | --- | --- |
| **0** | [Local end-to-end bring-up & the integration seam](refinement-phase-0-bring-up.md) | both | CORS · local DB · dev OTP · one real round-trip | — |
| **1** | [Database: local-dev story, demo seed & migration hygiene](refinement-phase-1-database-and-seed.md) | backend | empty marketplace · local DB · (migration myth) | 0 |
| **2** | [Auth & role-aware navigation](refinement-phase-2-auth-and-role-nav.md) | frontend (+bit of backend) | "only customer side shows" | 0, 1 |
| **3** | [Backend contract batch (close the 37 REQ gaps)](refinement-phase-3-contract-batch.md) | backend | the mismatch — REQ-001…037 | 0 |
| **4** | [Frontend de-mock (flip every domain to real)](refinement-phase-4-frontend-de-mock.md) | frontend | "no API calls to backend" | 1, 2, 3 |
| **5** | [Security & config hygiene](refinement-phase-5-security-hygiene.md) | backend | leaked `sa` creds, keys, seeds | — (5.1 now) |
| **6** | [Money-path correctness completion](refinement-phase-6-money-correctness.md) | backend | unreachable refund clearing + FKs | before 8 |
| **7** | [Unattended ops: scheduler, locking & multi-instance](refinement-phase-7-unattended-ops.md) | backend | nurses not paid unattended · Redis gate | 6 |
| **8** | [External rails go real (SMS → trust → money)](refinement-phase-8-external-rails.md) | backend | mocks → real vendors (SMS launch-critical) | 6, 7 |
| **9** | [Observability, ops hardening & scale-later](refinement-phase-9-observability-and-scale.md) | backend | tracing/health/logs · doc honesty · ES/analytics deferred | — |

### Dependency & sequencing

```
Make it work (integration):
  0 bring-up ──► 1 database/seed ──► 2 auth & role nav ─┐
       └────────► 3 contract batch ────────────────────┴──► 4 frontend de-mock
                                                              (app now integrated)
Make it production-ready (server audit, re-sequenced):
  5 security (5.1 rotate creds = TODAY)
  6 money correctness ──► 8 money rails
  7 scheduler/Redis ─────► (weekly payout trigger, Moadian poll for 8)
  8 external rails (5.1 SMS = launch-critical, do first in the phase)
  9 observability & scale-later (start anytime, finish before launch)
```

**Two items that jump their slot:** **Phase 5 §5.1** (rotate the committed `sa` credentials — the leak is live
*today*) and **Phase 8 §5.1** (real SMS — no real user can log in without it, sequence it first inside Phase 8).

**Minimum path to "a working demo on real data":** Phases **0 → 1 → 2 → 3 → 4**. After those, the whole
customer/nurse/admin funnel runs against the real backend with seeded data (payments still use the dev
conversion path until Phase 8 swaps a real PSP).

---

## How the phase files are written

Each file follows the repo's [phase template](../../phases/_shared/phase-template.md): a one-paragraph mission,
context (what already exists — don't rebuild), required reading, enumerated scope, the seams/mocks it touches,
the invariants it must not break, a Definition of Done, concrete how-to-test steps, and a close-out (docs +
memory). Phases 0–4 are written in full; phases 5–9 are concise and **point into the already-detailed
[server audit](../server/post-phase-backend-plan.md)** (which has file/line evidence for every item) rather than
restating it.

## Related documents

- [../server/post-phase-backend-plan.md](../server/post-phase-backend-plan.md) — the backend-only audit's 8
  buckets (folded into Phases 5–9), with file/line evidence.
- [../server/frontend-backend-gaps.md](../server/frontend-backend-gaps.md) — REQ-001…015 reconciled against
  shipped code (Phase 3 extends this through REQ-037).
- [../server/runtime-services.md](../server/runtime-services.md) — the 17-service deployment topology.
- [../../shared-working-context/frontend/requests/for-backend.md](../../shared-working-context/frontend/requests/for-backend.md)
  — the canonical REQ-001…037 tracker (Phase 3's spec).
- [../../shared-working-context/reports/mocks-registry.md](../../shared-working-context/reports/mocks-registry.md)
  — every seam + its make-it-real steps (backend seams + frontend mock flags), the checklist for Phases 4 & 8.
