# Handoff — after backend phase 15 (Messaging, partner centers & admin backoffice)

**This is the final backend phase. The backend chain is complete.** Every domain the admin backoffice acts on
now exists and is wired together.

## What is now live (frontend can build against it)

### Tickets — the post-booking channel (f14 messaging)
- `POST /api/v1/tickets` — open a ticket (`category` ∈ `support|coordination|refund|emergency`; optional
  `bookingId`/`refundId`; body optional). Opener is auto-added as the first participant. Returns
  `{ ticketId, referenceCode, status, category }`.
- `POST /api/v1/tickets/{id}/messages` — post a message. **`isInternal` is staff-only**; a non-staff caller
  sending `true` → `403`; posting to a closed ticket as non-staff → `403`.
- `POST /api/v1/tickets/{id}/participants` (add) / `DELETE …/participants/{userId}` (soft-remove) — staff or
  ticket owner. A **duplicate add is `409`** (backed by `UNIQUE(ticket_id, user_id)`), never a 500.
- `POST /api/v1/tickets/{id}/close` · `/reopen` — participant or staff (idempotent).
- `POST /api/v1/tickets/emergency` — assigned nurse (or staff) logs an emergency (+ optional support alert).
- `GET /api/v1/tickets` — my tickets (paginated, filter `status`, search `referenceCode`).
- `GET /api/v1/tickets/{id}` — **user thread view: internal notes are stripped** in the projection.
- `GET /api/v1/admin/tickets` + `GET /api/v1/admin/tickets/{id}` — admin queue + **admin thread view: internal
  notes included** (`support`/`admin`).

**The rule f14 must respect:** never build a direct nurse↔customer channel, never surface a phone number, and
never rely on the UI to hide internal notes — the backend already strips them from the user payload. The
coordination ticket for a booking is auto-created on confirmation (you don't create it).

### Partner centers + merchant-of-record (f15 admin + partner consoles)
- `POST /api/v1/admin/partner-centers` (create, inactive) · `PATCH …/{id}` (update) ·
  `POST …/{id}/verify` (activate) · `POST …/{id}/sponsor-nurse` · `GET …` (list) · `GET …/{id}` (detail) —
  `admin`/`super_admin`. **`settlementIbanMasked` (last 4) is the only IBAN ever returned** — never plaintext.
  `commissionRate ∈ [0,1)`; a merchant-of-record center requires a `settlementIban`.
- `GET /api/v1/centers/{id}/dashboard` — the center's own account (or staff): sponsored nurses + booking/invoice
  counts + masked settlement summary.
- `GET /api/v1/internal/bookings/{bookingId}/center` — the issuer/settlement resolver
  (`platform` | `partner_center`).

### Admin backoffice (surfaced, not rebuilt)
- Support-alert worklist: `GET support_alerts/get_support_alerts`, `POST …/assign_support_alert`,
  `POST …/resolve_support_alert` (built b1). Audit viewer: `GET audit/get_audit_trail` (built b1). Both
  `DynamicPermission`. Verification queue / refunds / payout dashboard / moderation queue are their own phases'
  routes — surface them under the admin console with the right RBAC scope.

## RBAC the frontend must respect (per route)
- Authenticated (own) ticket routes: any logged-in user; participation is enforced server-side.
- Admin ticket queue + admin thread: `support`/`admin`. Partner centers: `admin`/`super_admin`. Center
  dashboard: the center's `adminUserId` (or staff). Support alerts: `support`/`admin`. Audit: `super_admin`/`admin`.
- The admin role passes every `DynamicPermission` check; narrower staff scopes (`support`/`finance`/`moderation`)
  are granted via seeded role claims.

## What's mocked
- **`ILicenseVerificationService`** (eNamad / MoH establishment-permit) — `MockLicenseVerificationService`,
  manual-approve at MVP (`NeedsManualReview`); `VerifyPartnerCenter` records the human decision. Config
  `Seams:LicenseVerification:AutoApprove` forces `Valid`. See the mock registry (🟡). There is **no** telephony
  seam — the emergency call is an out-of-platform `tel:` link by design.

## Contracts
- `dev/contracts/domains/messaging-notifications-admin.md` (this phase). `swagger.v1.json` refreshed (now includes
  `/tickets`, `/admin/tickets`, `/admin/partner-centers`, `/centers`, `/internal/bookings/{id}/center`).

## Types / wire notes
- Envelope unchanged (camelCase body, snake_case URL tokens where `[action]`-based; the new controllers use
  explicit REST routes). Pagination `page`/`pageSize` (default 50, max 100). `sentAt`/`closedAt`/`verifiedAt` are
  UTC ISO-8601; ids are numbers; the settlement IBAN is a masked string (`"••••0001"`).
