7.7 KiB
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.
1. Context — where this sits
Fixes H-06 … H-10 from 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 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, paymentclientApi.ts/invalidations.ts, payouts/verification services). dev/shared-working-context/reports/mocks-registry.md— you will update the affected rows.
3. Scope — build this
- H-06 — refunds mock must see real bookings. While
USE_REFUNDS_MOCK=true(its REQs land in Phase 4), rewireservices/refunds/apis/mockApi.tsto resolve the booking through the selectedbookingsApi(the seam, real today) instead of importingmockGetBookingForRefundfrom 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. - 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 atcheckout/page.tsx:214): hide the branch wheneverUSE_BNPL_MOCKis true whilebookingRequests/paymentare 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-8to go through the selectedbookingRequestsApi/bookingsApiseams, never the raw mock modules.
- Derive the checkout BNPL CTA visibility instead of the bare
- H-08 — split the verification seam; make the nurse trust flow real.
- Split
VerificationApiselection 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.tsxto the real status (its CTA currently calls nothing —:59-68), and gate the variant-activation affordance inMyServicesList.tsxon real verification status with an honest explainer, so a nurse can no longer "publish" into invisibility. Remove/dev-gate the__mockApproveAllsimulator button accordingly.
- Split
- H-09 — split the payouts seam. Nurse reads (
earnings_balance,earnings,{id}detail, history) go real (payouts/apis/clientApi.ts:163-187already implements them); admin batch methods stay mocked until REQ-036. Same split mechanics as verification. - H-10 — stop nulling
bookingId.services/payment/apis/clientApi.ts:55-75: readbookingIdoff the wire (drop theOmit/bookingId: nulland the stale REQ-017-pending comments inclientApi.tsandtypes.ts:98-110); confirminvalidations.tsnow 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'smockApi.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 checkowns 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:cigreen; noservices/*/apis/mockApiimports across domain boundaries (grep-proof in the report).
7. How to test (human)
- Full customer journey per §6 against the RUNBOOK setup; screenshot the cancel preview.
grep -r "apis/mockApi" client/src/services --include=*.ts | grep -v "own domain"→ empty.- 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 with commit hashes.
- Update
client/CLAUDE.mdde-mock status block +mocks-registry.mdrows. - Write
dev/shared-working-context/reports/hardening-phase-2-report.md; file new REQs if a split exposed a missing server read (append tofor-backend.md, Phase 4 picks them up).