145 lines
10 KiB
Markdown
145 lines
10 KiB
Markdown
# 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.
|