115 lines
7.7 KiB
Markdown
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).
|