backend phase 9
This commit is contained in:
@@ -12,6 +12,25 @@ One block per completed backend phase. Newest at the top. Backend lane writes he
|
||||
- **Notes for frontend:** <anything load-bearing>
|
||||
-->
|
||||
|
||||
## backend-phase-9 — Bookings, sessions, care instructions & EVV — 2026-07-06
|
||||
- **Shipped:** the post-payment engine via one additive migration in the **`booking`** schema — **5 tables**
|
||||
`Bookings` / `BookingSessions` / `BookingCareInstructions` / `VisitVerifications` / `CancellationPolicies`
|
||||
(seeded 4 tiers) + 2 config rows (`no_show_threshold_minutes`, `no_show_scan_cadence_hours`). `Convert`
|
||||
(mock-capture → booking 1:1, three-amount split, snapshots, N sessions), care-instructions submit + **gated**
|
||||
read, EVV `check_in`/`check_out` (advisory address match, dispute window on completion), `transition`,
|
||||
`cancel` booking/session (policy snapshot + un-started refund), `detect_no_shows`, cancellation-policy CRUD.
|
||||
Controllers: `Bookings` / `BookingSessions` / `AdminEvv` / `AdminCancellationPolicies`.
|
||||
- **Contracts:** dev/contracts/domains/bookings-evv.md + openapi snapshot refreshed (yes).
|
||||
- **Mocked:** **`IPaymentCaptureSimulator`** introduced (🟡) — the temporary conversion trigger; reuses
|
||||
`IGeocoder`/`IFieldEncryptor`/`INotificationDispatcher`/`ISupportAlertService`. Real capture trigger = b10.
|
||||
- **Gate:** build clean (0 new code warnings) / tests green (269: 186 foundation + 4 identity + 79 API).
|
||||
- **Handoff:** backend/handoff/after-backend-phase-9.md
|
||||
- **Notes for frontend (f8-b9):** money is an **IRR digit-string** (three amounts reconcile). The nurse view
|
||||
omits `addressSnapshotJson`; care-instruction clinical fields are **assigned-nurse/admin only, post-confirmation**
|
||||
(`GET bookings/care_instructions/{id}`); raw EVV GPS is gated to owning nurse + admin. Routes are action-style
|
||||
(`bookings/get/{id}`, `booking_sessions/check_in/{id}`, `booking_sessions/today`, `admin_evv/list`). Payout
|
||||
eligibility comes from `disputeWindowEndsAt`/`payoutEligibleAt`, never `completed` alone.
|
||||
|
||||
## backend-phase-8 — Booking requests (pre-payment intent) — 2026-07-06
|
||||
- **Shipped:** the money-free request lifecycle via one additive migration — new **`booking`** schema,
|
||||
**1 table** `BookingRequests`. The customer-side (`CreateBookingRequest` — tenancy invariant
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Handoff — after backend phase 9 (Bookings, sessions, care instructions & EVV)
|
||||
|
||||
**The booking engine is live.** A paid request now becomes a real engagement: `bookings` + N `booking_sessions`,
|
||||
encrypted `booking_care_instructions`, per-session `visit_verifications` (EVV), and the dispute-window gate.
|
||||
Capture is **mocked** behind `IPaymentCaptureSimulator`; the real conversion trigger arrives with **b10 payments**.
|
||||
|
||||
## What f8-b9 can now build
|
||||
- **Booking detail & "My bookings"** — `GET bookings/get/{id}`, `GET bookings/list?role=customer|nurse|all&status=`.
|
||||
Header + money summary (three amounts as **digit-strings**, `platformFeeRate`, `pspFeeAmount`) + sessions +
|
||||
status timeline. The **nurse view omits `addressSnapshotJson`**.
|
||||
- **Nurse EVV** — `GET booking_sessions/today?date=` (today's visits + CTA state), `POST booking_sessions/check_in/{id}`
|
||||
and `POST booking_sessions/check_out/{id}` (send `{latitude, longitude}`; both nullable if GPS denied),
|
||||
`GET booking_sessions/evv/{id}` (raw GPS, owning nurse + admin only).
|
||||
- **Care instructions** — `POST bookings/submit_care_instructions/{id}` (customer/admin, booking must be confirmed+),
|
||||
`GET bookings/care_instructions/{id}` (**assigned nurse + admin only, post-confirmation** — the two-stage
|
||||
disclosure boundary; everyone else gets 404).
|
||||
- **Status timeline & cancel** — `POST bookings/cancel/{id}` (customer/nurse/admin; returns the policy snapshot +
|
||||
refundable amount), `POST booking_sessions/cancel/{id}` (single un-started session).
|
||||
- **Admin** — `GET admin_evv/list?type=mismatch|no_show`, `POST admin_evv/detect_no_shows`,
|
||||
`POST admin_cancellation_policies/upsert` + `GET admin_cancellation_policies/list`, `POST bookings/transition/{id}`.
|
||||
|
||||
## Live endpoints / contracts
|
||||
- Contract: [`dev/contracts/domains/bookings-evv.md`](../../contracts/domains/bookings-evv.md); machine schema in
|
||||
the refreshed [`swagger.v1.json`](../../contracts/openapi/swagger.v1.json).
|
||||
- Enums: `BookingStatus`, `BookingSessionStatus`, `VisitVerificationStatus`, `CancellationActor`.
|
||||
|
||||
## Load-bearing rules the client must honour
|
||||
- **Money is IRR integer, on the wire as a digit-string.** `grossPriceIrr = balinyaarCommissionIrr + nursePayoutAmount`.
|
||||
Never coerce to a JS number for math.
|
||||
- **Payout eligibility is derived from `disputeWindowEndsAt` / per-session `payoutEligibleAt`, not from `completed`.**
|
||||
- **EVV address mismatch is advisory** — a flagged check-in still succeeds; surface it, don't block.
|
||||
- **Care-instruction clinical fields never appear in a list or the booking detail** — only via the gated read.
|
||||
|
||||
## Mocked here → make real later
|
||||
- **`IPaymentCaptureSimulator`** (🟡) — the temporary conversion trigger. In **b10**, the real card capture calls
|
||||
`ConvertRequestToBooking` directly on a `payment_transactions.succeeded`; this seam is then removed. A config
|
||||
switch (`Seams:PaymentCapture:ForceFailure`) exercises the "capture failed → no booking" path today.
|
||||
- The **no-show cron** is DEFERRED — `POST admin_evv/detect_no_shows` runs the same idempotent command a scheduler
|
||||
will later call (config `no_show_scan_cadence_hours`).
|
||||
|
||||
## Consumed by later backend phases
|
||||
- **b10** — real capture posts the ledger and calls the conversion; sets the real `psp_fee_amount`.
|
||||
- **b11** — refund execution consumes the frozen `cancellationPolicyCode` + `refundableAmountIrr` (no ledger posted here).
|
||||
- **b13** — payout batching consumes `disputeWindowEndsAt` / `payoutEligibleAt`.
|
||||
- **b14** — reviews on a completed booking.
|
||||
- **b15** — `partner_centers` wires the nullable `partner_center_id`.
|
||||
Reference in New Issue
Block a user