Files
baya-monorepo/dev/post-phase/hardening/hardening-phase-2-mock-integrity.md
T
2026-07-17 13:22:04 +03:30

115 lines
7.7 KiB
Markdown

# Hardening Phase 2 — Money-path mock integrity (no fake success on real data)
> Sever the dangling cross-imports the phase-4 de-mock left behind — the refunds and BNPL mocks still
> read retired in-memory stores keyed by REAL server ids — split the seams whose real halves are
> already live (verification nurse flow, nurse earnings), and stop discarding the delivered
> `bookingId`. After this phase, nothing in the money path can show a fake success against real data.
> **Track:** frontend · **Depends on:** Phase 0 · **Unlocks:** Phase 5
> **Before you start, read [_shared/agent-operating-rules.md](../../phases/_shared/agent-operating-rules.md).**
## 1. Context — where this sits
Fixes **H-06 … H-10** from [issues.md](issues.md). Refinement-phase-4 flipped 14 domains to real but
left 7 mocked; two of the mocked ones (`refunds`, `bnpl`) still hard-import the **mock modules** of
now-real sibling domains (`bookings`, `bookingRequests`), whose fixture stores no longer correspond to
anything — so a real customer's cancel 404s and the BNPL wizard either 404s or fabricates a client-side
"booking" while the real request expires unpaid. Meanwhile two seams hold real, shipped backend halves
hostage to a single flag (`verification` nurse flow — which silently breaks nurse discoverability
because the real search gate needs the real `is_verified`; `payouts` nurse reads — REQ-025 is live).
**What already exists (do not rebuild):** the per-domain seam pattern (`apis/index.ts` selects
mock/real), all the real `clientApi.ts` implementations named below, the b6 verification endpoints, the
REQ-025 nurse payout endpoints (`NursePayoutsController.cs:33-48`), and the REQ-017 `bookingId` on
`BookingRequestDto`.
## 2. Required reading (do this first)
- [issues.md](issues.md) H-06/H-07/H-08/H-09/H-10 — full evidence; don't re-audit.
- `client/CLAUDE.md` → "The services/{domain} reference pattern" + the de-mock status block.
- The files cited per finding (refunds/bnpl/bookings/bookingRequests mockApis + constants, checkout
pages, `PublishGate.tsx`, `MyServicesList.tsx`, payment `clientApi.ts`/`invalidations.ts`,
payouts/verification services).
- `dev/shared-working-context/reports/mocks-registry.md` — you will update the affected rows.
## 3. Scope — build this
1. **H-06 — refunds mock must see real bookings.** While `USE_REFUNDS_MOCK=true` (its REQs land in
Phase 4), rewire `services/refunds/apis/mockApi.ts` to resolve the booking through the **selected**
`bookingsApi` (the seam, real today) instead of importing `mockGetBookingForRefund` from the
bookings mock module. The mock computes the policy preview locally off the real booking's
status/sessions/amounts and simulates the cancel/refund state machine on top. A real booking id
must produce a coherent preview + cancel flow (mock-side state), never a 404.
2. **H-07 — BNPL must not fake success.** Two parts:
- Derive the checkout BNPL CTA visibility instead of the bare `BNPL_ENABLED=true`
(`services/payment/constants.ts:23`, used at `checkout/page.tsx:214`): hide the branch whenever
`USE_BNPL_MOCK` is true while `bookingRequests`/`payment` are real (mixed state = the dangerous
combination). An honest absent button beats a fabricated booking.
- For the dev/demo path that remains reachable (both mocked, e.g. Testing), rewire
`services/bnpl/apis/mockApi.ts:5-8` to go through the **selected** `bookingRequestsApi`/
`bookingsApi` seams, never the raw mock modules.
3. **H-08 — split the verification seam; make the nurse trust flow real.**
- Split `VerificationApi` selection per half: nurse-facing methods (status, start, identity,
Shahkar, bank, document upload, credentials, trust badge) go **real** now — the clientApi is
already 1:1 per the mocks registry; admin-facing methods (queue, case, decideStep, signed doc
URL) stay mocked until REQ-034 (Phase 4). Follow whatever per-method selection shape is cleanest
under the existing seam pattern (two flags, or a composed api object) and record it in the
registry.
- Wire `PublishGate.tsx` to the real status (its CTA currently calls nothing — `:59-68`), and gate
the variant-activation affordance in `MyServicesList.tsx` on real verification status with an
honest explainer, so a nurse can no longer "publish" into invisibility. Remove/dev-gate the
`__mockApproveAll` simulator button accordingly.
4. **H-09 — split the payouts seam.** Nurse reads (`earnings_balance`, `earnings`, `{id}` detail,
history) go real (`payouts/apis/clientApi.ts:163-187` already implements them); admin batch methods
stay mocked until REQ-036. Same split mechanics as verification.
5. **H-10 — stop nulling `bookingId`.** `services/payment/apis/clientApi.ts:55-75`: read `bookingId`
off the wire (drop the `Omit`/`bookingId: null` and the stale REQ-017-pending comments in
`clientApi.ts` and `types.ts:98-110`); confirm `invalidations.ts` now receives it and the
confirmation page renders the booking + invoice deep links.
## 4. Mocks & seams in this phase
Touches the `refunds`, `bnpl`, `verification`, `payouts` seams (splits/rewires; flags flipped only for
the halves whose backend is live). Update each row in
`dev/shared-working-context/reports/mocks-registry.md` — including correcting the stale "reads the
shared f7 store" descriptions.
## 5. Critical rules you must not get wrong
- **A mock may only reach sibling data through the selected seam** (`services/{domain}/apis/index.ts`),
never by importing a sibling's `mockApi.ts` — that's the root cause you're eradicating. Grep for
remaining cross-mock imports before finishing.
- Money is served IRR digit-strings, BigInt-safe — the refunds mock's local preview must reuse the
existing money utils and reconcile (refund + fee = captured), never float math.
- Verified-only search, two-stage disclosure, and "client never computes what the server owns"
invariants all still hold; the verification split must not let the client write `is_verified`.
- A 409 on the money path is benign convergence, never a toast (existing rule).
- Keep i18n complete for any new copy (both message files); `npm run check` owns the gate.
## 6. Definition of Done
- Real journey (seeded world, real server): create booking request → accept → pay → **cancel**
policy preview renders with reconciling numbers (no 404).
- BNPL CTA absent on real checkout while the domain is mocked; the D1-D5 wizard is unreachable with a
real request id (and works fully in the all-mock dev mode).
- Fresh nurse: real verification wizard drives the real b6 endpoints; variant activation is gated
until the real status approves; after approval + activation the nurse appears in real search.
- Nurse earnings screen shows real amounts from the live endpoints.
- Payment confirmation shows working "view booking" + "download invoice" deep links after a real
capture.
- `npm run check` + `npm run test:ci` green; no `services/*/apis/mockApi` imports across domain
boundaries (grep-proof in the report).
## 7. How to test (human)
1. Full customer journey per §6 against the RUNBOOK setup; screenshot the cancel preview.
2. `grep -r "apis/mockApi" client/src/services --include=*.ts | grep -v "own domain"` → empty.
3. Nurse persona 09120000003 (unverified): services page shows the gated state; run the real
verification flow; confirm search visibility flips after approval.
## 8. Hand off & document
- Tick H-06…H-10 in [issues.md](issues.md) with commit hashes.
- Update `client/CLAUDE.md` de-mock status block + `mocks-registry.md` rows.
- Write `dev/shared-working-context/reports/hardening-phase-2-report.md`; file new REQs if a split
exposed a missing server read (append to `for-backend.md`, Phase 4 picks them up).