Files
baya-monorepo/archive/build-chain/working-context/backend/handoff/after-backend-phase-8.md
T
2026-08-02 18:48:32 +03:30

4.9 KiB

Handoff — after backend-phase-8 (Booking requests · pre-payment intent)

The booking-request lifecycle is live end-to-end. A customer can request a nurse; the nurse accepts (opening a config-driven 30-minute payment window) or rejects; both sides read their role-scoped inbox and a single request; unanswered/unpaid requests auto-expire on a recurring sweep (also an admin manual trigger). No money and no bookings row exist yet — that conversion is b9/b10.

What b9 must consume (the next backend phase)

  • Convert an accepted_awaiting_payment request → a bookings row once payment is captured (b10), then set the request to converted through the BookingRequestTransitions guard (request.MarkConverted() already exists and is the only sanctioned path; b8 never writes this edge itself). The request↔booking link is 1:1 and b9-owned.
  • b8 deliberately exposes only customer_notes (stage 1). The full encrypted clinical/care instructions are b9's stage 2 (booking_care_instructions, readable only post-confirmation by the assigned nurse + admin). Do not add an encrypted clinical field to booking_requests.
  • The money split, snapshots, sessions, EVV, dispute window are all b9/b10 — b8 persists no variant_snapshot_json/address_snapshot_json, no price, no ledger entry. The b5 IVariantSnapshotSerializer is still the tool for the booking snapshot at conversion time.
  • Reuse the forward-only status-machine pattern for the bookings state machine (see CONVENTIONS §6 — "Forward-only status machine"). Same shape: const codes + a static CanTransition edge table + entity-owned transitions + handler pre-check → 409.

What f7-b8 can now build (frontend)

All routes are action-style ([controller]/[action], snake_case) with the standard { succeeded, statusCode, data } envelope. Full shapes in dev/contracts/domains/booking-requests.md; types come from the refreshed swagger.v1.jsondo not guess.

  • Request form (C4)POST api/v1/booking_requests/create (customer). Body: nurseId, variantId, patientId, customerAddressId, requestedDate (YYYY-MM-DD), requestedTimeStart/requestedTimeEnd (HH:mm:ss), requiredCaregiverGender (male|female|any, required), customerNotes (≤ 1000, the only clinical text the nurse sees). Inputs come from search (nurse+variant), patients (b3), addresses (b4).
  • Awaiting-acceptance / status tracker (C5)GET api/v1/booking_requests/get/{id} + the customer inbox GET api/v1/booking_requests/list?role=customer. Show two countdowns: to nurseResponseDeadlineAt (pending) and to paymentDeadlineAt (accepted — the 30-min window). Customer can POST …/cancel/{id} while pending or accepted-awaiting-payment.
  • Nurse incoming-requests inboxGET api/v1/booking_requests/list?role=nurse (+ status= filter) with POST …/accept/{id} and POST …/reject/{id} (reason required). The nurse row shows counterpartyName = patient name + customerNotes only, plus the response countdown — never a full address or any clinical field beyond customerNotes.

Rules the UI must respect

  • Same-gender is first-class and required. Send requiredCaregiverGender explicitly (never default it); male/female must match the nurse's gender or the create is a 400. any matches either.
  • Deadlines are server-frozen absolute UTC timestamps. Render countdowns from them; never recompute a deadline client-side. paymentDeadlineAt is null until the nurse accepts.
  • Two-stage disclosure. The nurse detail view returns a masked address (city/district only, addressLine/postalCode/recipient are null); the customer/admin view returns the full address. Do not expect (or request) clinical instructions here — they don't exist until b9.
  • Status drives the UI. Terminal states (converted/rejected_by_nurse/expired_no_response/ payment_deadline_expired/cancelled_by_customer) allow no further actions; a stale action returns 409.
  • get/{id} is party-scoped. A non-party caller gets 404 (existence not leaked).

Contracts

  • New: dev/contracts/domains/booking-requests.md.
  • swagger.v1.json refreshed (adds booking_requests/{create,accept,reject,cancel,list,get} + admin_booking_requests/expire + BookingRequestDto/BookingRequestListItemDto/ExpireBookingRequestsResult).

Nothing new is mocked

b8 introduces no external seam and adds no new mocks-registry.md row. It reuses IPlatformConfig, INotificationDispatcher, IJobScheduler/BackgroundService, IDateTimeProvider, ICurrentUser. The expiry sweep is an internal hosted service (the registry's IJobScheduler row was updated to note the second job), not an external integration.