211 lines
14 KiB
Markdown
211 lines
14 KiB
Markdown
# Next up — the opinionated part
|
|
|
|
> Last verified: 2026-08-02 against commit `cd8144e`. Populated by phase 5 of the
|
|
> [documentation clean-up chain](../../archive/clarify-chain/README.md).
|
|
|
|
Five units, each spec'd enough that a fresh agent session could start one without re-deriving context. The
|
|
order applies the sequencing principle from [index.md](index.md#the-sequencing-principle): (1) stop a money
|
|
or trust flow from lying to a user, (2) fix a built flow that's unusable, (3) make a mocked flow real, (4) new
|
|
surface area. Nothing here conflicts with any `product/` business rule — every unit below is closing an
|
|
implementation gap against a rule the business docs already decided, not proposing new behavior.
|
|
|
|
---
|
|
|
|
## Unit 1 — Nurse verification stops lying about verification status
|
|
|
|
**Goal.** Flip the `verification` client domain's mock off for the nurse-facing and public/search-visibility
|
|
surfaces, so the app renders the server's real, already-correct status everywhere it matters: the nurse's own
|
|
verification screen, the activation checklist's "go live" gate, search's `is_searchable` filter, and the
|
|
public trust badge.
|
|
|
|
**Why now.** Verification *is* the platform's trust promise. Today the mock doesn't show stale data — it
|
|
actively contradicts a real, server-computed truth: a server-verified nurse renders as unverified everywhere
|
|
the client reads her status ([BL-010](../status/backlog.md#blockers-18)). Under the sequencing principle this
|
|
is a category-1 item: a trust flow lying to a user, ranked above anything merely unbuilt.
|
|
|
|
**What it unblocks.** A trustworthy "go live" CTA; the real search-visibility gate becomes observable instead
|
|
of hidden behind fabricated client state; closes the one confirmed production-seam breach
|
|
(`nurse/verification/page.tsx` unconditionally imports the mock module regardless of its render gate —
|
|
[BL-080](../status/backlog.md#major-86)); establishes the de-mock pattern units 4 and 5 reuse.
|
|
|
|
**Technical prerequisites.** None blocking. Scope this unit to the nurse-facing and public halves only — the
|
|
admin approve/reject/suspend actions stay behind
|
|
[BL-082](../status/backlog.md#major-86) (the routes don't exist yet, independent of RBAC), and are naturally
|
|
picked up alongside unit 3 once both the routes and RBAC exist.
|
|
|
|
**Affected flows.** [nurse-verification](../flows/nurse-verification.md) (mocked → partial),
|
|
[onboarding-nurse](../flows/onboarding-nurse.md), [search-and-discovery](../flows/search-and-discovery.md)
|
|
(real gate becomes visible), [public-front-door](../flows/public-front-door.md) (trust badge becomes real).
|
|
|
|
**Rough size:** L — a 100%-mocked, 14-operation domain with real DTO reconciliation.
|
|
|
|
**Backlog ids closed:** [BL-010](../status/backlog.md#blockers-18) (blocker), BL-080, BL-081, BL-084, BL-190,
|
|
BL-191, BL-192, BL-214. Worth fixing in the same pass, same trust-truth theme, different root cause:
|
|
[BL-098](../status/backlog.md#major-86) (an unverified nurse's profile is still readable and asserts
|
|
"verified" anonymously by id). BL-083 (admin catalog UI for suspend/scan-expiring) is explicitly out of scope
|
|
— it's an admin surface, deferred with unit 3.
|
|
|
|
---
|
|
|
|
## Unit 2 — Checkout and the payment window stop lying about money and time
|
|
|
|
**Goal.** Fix the cluster of checkout-and-payment defects that tell a customer or nurse something false: the
|
|
timezone-less deadline that can render a 30-minute window as ~4 hours and expire silently
|
|
([BL-006](../status/backlog.md#blockers-18)), the checkout summary's missing `nurseVerified` field
|
|
(BL-058), the payment confirmation that can't deep-link to its booking and hides the tracking code
|
|
(BL-059), and the invoice screen's client-computed row that's wrong by exactly the VAT amount instead of
|
|
showing the server's real total (BL-060). Close the two related blind spots while in the same code: no
|
|
payment-history read (BL-061) and no escrow-ledger read surface at all (BL-062).
|
|
|
|
**Why now.** Category-1 by the letter of the sequencing principle: a countdown that shows hours when minutes
|
|
remain, and an invoice wrong by a fixed, known amount, are exactly "a money/trust flow lying to a user" —
|
|
not a missing feature, a false one.
|
|
|
|
**What it unblocks.** The one flow every paying customer touches becomes honest; removes a standing violation
|
|
of the repo's "client never computes money" rule ([BL-060](../status/backlog.md#major-86), called out
|
|
directly in [decisions.md](../status/decisions.md)); a trustworthy countdown is also a quiet prerequisite for
|
|
ever safely flipping [BL-005](../status/backlog.md#blockers-18) (the dead card-payment rail) to a real PSP —
|
|
no reason to give a real gateway a lying clock.
|
|
|
|
**Technical prerequisites.** None. Every item here is a DTO addition or a client display fix; nothing depends
|
|
on RBAC or a mock flip elsewhere.
|
|
|
|
**Affected flows.** [checkout-and-payment](../flows/checkout-and-payment.md),
|
|
[booking-request](../flows/booking-request.md) (shares the deadline field).
|
|
|
|
**Rough size:** M. Mostly additive DTO fields plus client display fixes; budget extra time for BL-006 since
|
|
`DateTime` → `DateTimeOffset` touches a shared type used beyond this one screen.
|
|
|
|
**Backlog ids closed:** [BL-006](../status/backlog.md#blockers-18) (blocker), BL-042, BL-058, BL-059, BL-060,
|
|
BL-061, BL-062.
|
|
|
|
---
|
|
|
|
## Unit 3 — Give the seeded admins the claim the code already checks for
|
|
|
|
**Goal.** `DynamicPermissionService.CanAccess` grants only the literal role `admin`; no seeded account holds
|
|
it, so every seeded admin 403s on every `DynamicPermission`-gated controller
|
|
([BL-001](../status/backlog.md#blockers-18)). Either broaden the check to also honor the roles actually
|
|
seeded (`super_admin`/`finance`), or add the missing step that writes a `DynamicPermission` claim when those
|
|
roles are granted — and seed at least one account holding the literal role so the fix is testable out of the
|
|
box ([BL-002](../status/backlog.md#blockers-18)).
|
|
|
|
**Why now.** Category-2 under the stated principle (it makes a built, real, already-coded admin backoffice
|
|
completely unusable, rather than lying about anything) — but it is the single highest-leverage fix in the
|
|
whole backlog: one root cause independently degrades **11 of 14 business areas**
|
|
([implemented.md](../status/implemented.md#cross-cutting-the-rbac-finding)). Worth naming the tension
|
|
directly: nothing stops this from running before units 1-2 except the sequencing principle's letter — it has
|
|
zero prerequisites of its own, same as they do. It's ranked third here because the principle is applied
|
|
literally; a reader who weighs "unlocks the most downstream work" more heavily than the letter of the
|
|
principle would be right to run this first, and that's exactly the kind of overrule this document exists to
|
|
make easy.
|
|
|
|
**What it unblocks.** Admin verification review (once BL-082's routes exist), refund preview/approve/reject
|
|
(unit 4), payout `mark_failed` and batch processing (unit 5), reviews ever leaving moderation
|
|
([BL-017](../status/backlog.md#blockers-18)), ticket assignment, cancellation-policy admin edits, the admin
|
|
user/role directory ([BL-029](../status/backlog.md#major-86)) — essentially every admin-side item in units
|
|
4-5 and in [deferred.md](deferred.md#deferred-at-the-item-level--gated-behind-a-console-that-isnt-prioritized-yet).
|
|
|
|
**Technical prerequisites.** None.
|
|
|
|
**Affected flows.** [admin-backoffice](../flows/admin-backoffice.md) (mocked → real), plus the admin half of
|
|
nurse-verification, cancellation-and-refunds, messaging-tickets, nurse-earnings-and-payouts, partner-center,
|
|
reviews, booking-request, booking-lifecycle-evv, and nurse-catalog-and-pricing — the 11 areas
|
|
[implemented.md](../status/implemented.md#cross-cutting-the-rbac-finding) names.
|
|
|
|
**Rough size:** M. The fix itself is small and surgical; the size is in re-verifying admin surfaces across 11
|
|
areas afterward, since several have never been reachable long enough to know what else breaks once they 200.
|
|
|
|
**Backlog ids closed:** [BL-001](../status/backlog.md#blockers-18), BL-002 (both blockers). Directly unblocks
|
|
without itself closing: BL-017, BL-029, BL-050, BL-082, BL-116, BL-117, BL-125, BL-163.
|
|
|
|
---
|
|
|
|
## Unit 4 — De-mock refunds and BNPL onto the server that's already built
|
|
|
|
**Goal.** Flip the `refunds` and `bnpl` client domains off their mocks. Both currently read a retired/wrong
|
|
bookings-mock store that would break, not just look stale, on a naive flip: refunds would render a
|
|
10000%-scale refund amount ([BL-009](../status/backlog.md#blockers-18)); the BNPL wizard 404s for every real
|
|
booking id ([BL-008](../status/backlog.md#blockers-18)). Seed a real `Bnpl` payment-gateway row so BNPL calls
|
|
stop 400ing ([BL-007](../status/backlog.md#blockers-18)). Fix the DTO drift the flow atlas already catalogued
|
|
— BL-047 (refund channel pinned to a fixture id), BL-048 (client discards six real fee-split fields), BL-049
|
|
(three enum mismatches) — *before* flipping, not after, exactly the order phase 3/4's analysis already sets up.
|
|
|
|
**Why now.** Both are money flows. Both are among the five domains
|
|
[implemented.md](../status/implemented.md) flags as most at risk of breaking, not just showing stale data, on
|
|
a flip — the reconciliation work is already scoped by the flow docs, so this is executing a known plan, not
|
|
discovering one.
|
|
|
|
**What it unblocks.** A customer sees a real cancellation/refund preview instead of a fabricated one; the
|
|
platform's second payment rail (BNPL) becomes exercisable end-to-end locally for the first time.
|
|
|
|
**Technical prerequisites.** None to start the customer-facing halves. The admin sides —
|
|
[BL-050](../status/backlog.md#major-86) (refund preview/approve/reject route doesn't exist) and the
|
|
BNPL-adjacent admin surfaces — stay deferred regardless of this unit, consistent with their own
|
|
already-recorded "gated on a console" status in [deferred.md](deferred.md).
|
|
|
|
**Affected flows.** [cancellation-and-refunds](../flows/cancellation-and-refunds.md) (mocked → partial),
|
|
[bnpl-installments](../flows/bnpl-installments.md) (mocked → partial).
|
|
|
|
**Rough size:** L. Two domains, DTO reconciliation on both, a gateway-seeding change. Worth solving
|
|
[BL-131](../status/backlog.md#deferred-43) (nothing fires the BNPL webhook locally) in the same pass — without
|
|
it, a real BNPL order can be initiated but never observed reaching `settled` in dev.
|
|
|
|
**Backlog ids closed:** [BL-007](../status/backlog.md#blockers-18), BL-008, BL-009 (all three blockers),
|
|
BL-047, BL-048, BL-049, BL-052, BL-053, BL-054, BL-126, BL-127, BL-128, BL-129, BL-130.
|
|
|
|
---
|
|
|
|
## Unit 5 — De-mock nurse payouts, including the one action with no UI at all
|
|
|
|
**Goal.** Flip the `payouts` client domain to real. Build the client UI for `process` — the irreversible step
|
|
that actually executes a payout batch, which currently has **zero client caller anywhere in the app**. Fix
|
|
`DeriveEarningsState`'s wrong "paid" logic, which marks a booking paid whenever it merely has a payout *link*,
|
|
regardless of that payout's actual status, and reconcile the four earnings buckets against the ledger
|
|
([BL-012](../status/backlog.md#blockers-18)).
|
|
|
|
**Why now.** This is the flow where a nurse's trust in ever actually getting paid lives, and it currently
|
|
tells her she's been paid when the payout may not have succeeded — a money lie hiding inside a mocked flow.
|
|
It's category-3 (de-mock) and category-1 (stop a lie) at the same time, which is why it's grouped with the
|
|
other de-mock units rather than ranked above unit 3 on category-1 grounds alone: fixing the lie and fixing the
|
|
mock are the same commit here, unlike units 1-2 where the lie could be fixed without a mock flip.
|
|
|
|
**What it unblocks.** A truthful earnings/payout history for nurses; the one missing admin action (batch
|
|
processing); [BL-076](../status/backlog.md#major-86) (`mark_failed` has no client op) becomes reachable once
|
|
this unit and unit 3 (RBAC) have both landed.
|
|
|
|
**Technical prerequisites.** Unit 3 (RBAC), for the admin-side `process`/`mark_failed` actions specifically —
|
|
the nurse-facing earnings/history half has no such dependency and can proceed independently. This is the one
|
|
unit in this list with a real cross-unit dependency; sequence its admin half after unit 3 regardless of where
|
|
the two land in a sprint.
|
|
|
|
**Affected flows.** [nurse-earnings-and-payouts](../flows/nurse-earnings-and-payouts.md) (mocked → partial).
|
|
Worth fixing [BL-016](../status/backlog.md#blockers-18) in the same pass — a booking swept to `missed` never
|
|
reaches a payable state today, so it can never enter a payout batch regardless of this unit's other fixes.
|
|
|
|
**Rough size:** L. Mock removal, a wholly new admin-action UI, a state-derivation bug fix, and a
|
|
ledger-reconciliation check.
|
|
|
|
**Backlog ids closed:** [BL-012](../status/backlog.md#blockers-18), BL-016 (both blockers), BL-073, BL-074,
|
|
BL-076, BL-179, BL-180, BL-181, BL-182, BL-183, BL-184. Unblocks without closing: BL-075.
|
|
|
|
---
|
|
|
|
## Considered, and deliberately not in this list
|
|
|
|
- **[BL-013](../status/backlog.md#blockers-18) — partner-center (100% mocked, zero tenancy).** Just as mocked
|
|
as the four domains above, but structurally different: 5 core routes
|
|
(`centers/me`, `/me/nurses`, `/me/bookings`, `/me/bookings/{id}`, `/me/settlement`) **don't exist
|
|
server-side at all**. This isn't a de-mock, it's a small backend phase followed by a de-mock — a bigger unit
|
|
than the others, and one where the "flip the mock" playbook from units 1/4/5 doesn't directly apply. Next
|
|
in line after these five.
|
|
- **[BL-011](../status/backlog.md#blockers-18) — patient/care records (100% mocked, server real).** Same
|
|
shape as units 1, 4, and 5 (server real, client mocked, DTO drift already catalogued) and just as legitimate
|
|
a candidate — it didn't fit this document's 3-5 cap, not a judgment that it matters less. Directly next in
|
|
line if a sixth unit is wanted.
|
|
- **[BL-096](../status/backlog.md#major-86) — tier (c) of the public front door (guest search + public nurse
|
|
profiles).** New surface area (category 4), and explicitly named in the phase brief as ranking below making
|
|
the authenticated flows honest regardless of visibility. Also blocked on a decision this document can't
|
|
make: an explicit privacy sign-off on the nurse-profile field list, plus REQ-066/067 delivered. Stays in
|
|
[deferred.md](deferred.md), not here.
|