# 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.
