ui phase 11
This commit is contained in:
@@ -978,3 +978,80 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
URL), and `TicketMessageDto` gains `attachments: { id: string, url: string, contentType: string }[]`.
|
||||
- **Status:** deferred — the affordance is designed and gated off; nothing renders until this lands and the
|
||||
capability flag flips.
|
||||
|
||||
## REQ-062 — Verification queue enrichment: name/phone search + per-status counts — filed by ui-phase-11 — 2026-07-19
|
||||
- **Need:** Two additions to `GET admin_verifications` (the b6 admin review-queue list, folded client-side to
|
||||
one row per nurse — see REQ-034):
|
||||
1. A **name/phone search** query param (proposed `q`) that filters the queue to nurses whose name or phone
|
||||
matches (case-insensitive substring), combinable with the existing `status` filter.
|
||||
2. **Whole-desk per-status counts** in the response envelope — `pending`/`in_review` totals across the
|
||||
**entire** queue (not the current page or the applied filters), so the status-tab badges never drift
|
||||
from the true queue size. Optionally also a `submittedAt` sort param (`sort=submittedAt&dir=asc|desc`)
|
||||
for the new waiting-time column.
|
||||
- **Why:** The review queue (phase §3.3, the flagship trust-desk screen) previously offered only a 3-value
|
||||
status filter and no way to find a specific nurse or see how much work is queued per status — the audit's
|
||||
headline finding. The client's `AdminVerificationQueueFilters` now carries an optional `search` field and
|
||||
`AdminVerificationQueuePage` an optional `counts: { pending, in_review }` (both in
|
||||
`client/src/services/verification/types.ts`); the mock (`apis/mockApi.ts`) computes real counts over its
|
||||
whole unfiltered fixture set and matches `search` against the seeded `nurseName`. The real
|
||||
`verificationClientApi.listVerificationQueue` (`apis/clientApi.ts`) already sends `search` as `q` on the
|
||||
query string (a no-op today — the server currently ignores unknown query params rather than 400ing) and
|
||||
leaves `counts` `undefined`; the queue screen renders the status tabs **without** badge counts until this
|
||||
lands (mock-tolerant, never a fake count).
|
||||
- **Proposed shape:** `GET admin_verifications?status=&q=&page=&pageSize=&sort=&dir=` →
|
||||
`{ items: AdminPendingStepDto[], total, page, pageSize, counts: { pending: number, in_review: number } }`
|
||||
(`counts` computed over the whole queue, ignoring `status`/`q`/`page`).
|
||||
- **Status:** open
|
||||
|
||||
## REQ-063 — Ticket lifecycle mutations (close/reopen/assign) — filed by ui-phase-11 — 2026-07-19
|
||||
- **Need:** Close/reopen/assign endpoints for a ticket, plus an `assigneeUserId` field on the admin ticket
|
||||
DTOs (`AdminTicketSummary`/`AdminTicketDetail`) so the queue and thread can show and change who owns a
|
||||
case.
|
||||
- **Why:** Today a ticket has no lifecycle command at all — a resolved ticket can never leave the admin
|
||||
queue, and there is no way to hand a case to a specific staff member. The ops desk (f15 admin console)
|
||||
needs both for a working worklist. The client-side controls (`services/tickets` `useCloseTicket`/
|
||||
`useReopenTicket`/`useAssignTicket`, and the admin thread's close/reopen/"assign to me" affordances) are
|
||||
built against the mock and gated behind `TICKET_LIFECYCLE_ENABLED` (`services/tickets/constants.ts`,
|
||||
default `false`) so nothing points at a 404'ing route in production.
|
||||
- **Proposed shape:** `POST tickets/{id}/close` (no body) → ticket `status: 'closed'`, sets `closedAt`.
|
||||
`POST tickets/{id}/reopen` (no body) → `status: 'open'`, clears `closedAt`. `POST tickets/{id}/assign`
|
||||
with `{ ownerUserId: number }` → sets the ticket's assignee. `AdminTicketSummary`/`AdminTicketDetail` gain
|
||||
`assigneeUserId: number | null`.
|
||||
- **Status:** open
|
||||
|
||||
## REQ-064 — Partner scoped booking detail (read-only summary) — filed by ui-phase-11 — 2026-07-19
|
||||
- **Need:** A single-sponsored-booking read for the partner portal (`GET centers/me/bookings/{bookingId}`,
|
||||
sibling of the existing `GET centers/me/bookings` list route), returning everything the list row already
|
||||
has plus a status timeline for that booking.
|
||||
- **Why:** §3.7 — the partner portal's sponsored-bookings list (`/partner/bookings`) needs to link each row
|
||||
to a detail view so a center admin can confirm what happened on a booking without leaving the portal. The
|
||||
portal is explicitly scoped to read-only, non-clinical data (portal scope boundary, product/business) —
|
||||
patient display name + dates + status only, never clinical content, address, or money.
|
||||
- **Proposed shape:** `GET centers/me/bookings/{bookingId}` → `SponsoredBookingDetailDto` = the existing
|
||||
`SponsoredBookingDto` (`bookingId`, `patientName`, `scheduledDate`, `status`) plus
|
||||
`timeline: { status: string, occurredAt: string }[]` (server-truth status history, dates only — no
|
||||
clinical content). The client-side seam (`services/partnerCenter`) is built against this shape (mock
|
||||
primary, `USE_PARTNER_MOCK`); the real client call is written but unreachable until this route exists.
|
||||
- **Status:** open
|
||||
|
||||
## REQ-061 — Admin user lookup: name/phone search + batch id→label resolve — filed by ui-phase-11 — 2026-07-19
|
||||
- **Need:** Two endpoints backing a directory of platform users for admin use:
|
||||
1. `GET admin_users/search?q=&role=` — search by name/phone (min 2 chars), optionally narrowed to one
|
||||
coarse role (`customer`/`nurse`/`admin`/`partner`), returning up to ~10 matches: `{ id, displayName,
|
||||
maskedPhone, roles: string[], nurseProfileId?: number }` (`nurseProfileId` set only when `roles`
|
||||
includes `nurse` — the id `NursePicker` needs, a different id space than the user id).
|
||||
2. `POST admin_users/lookup` with `{ userIds: number[] }` — batch id→label resolve, returning the same
|
||||
shape for each found id, so a page with N actor ids (an audit log, a role grid) makes one request
|
||||
instead of N.
|
||||
- **Why:** The single scariest wrong-target failure mode in the backoffice — every audited action (role
|
||||
grants, partner-center admin assignment, sponsored-nurse assignment) previously targeted a hand-typed
|
||||
raw numeric id with no lookup or name echo-back (phase §3.2, the audit's flagship "high" finding), and
|
||||
every actor/owner id across the console (audit log, role grid) rendered as a bare `#42` with no way to
|
||||
find out who that is (§3.6, `AuditLogRow`). `UserPicker`/`NursePicker` (`client/src/components/admin/`)
|
||||
and the new read-first `/admin/users` directory console (§3.8) are both built against this shape,
|
||||
mock-primary behind `services/admin`'s existing `USE_ADMIN_MOCK` seam (`searchUsers`/`lookupUsers` on
|
||||
`AdminApi`) — no page points at a 404'ing route; the mock seeds a small but representative directory
|
||||
(admin/support/finance staff, nurses, customers, one partner-center contact) across both endpoints.
|
||||
- **Proposed shape:** see **Need** above; masked phone follows the existing `maskIranMobile` convention
|
||||
(`"0912•••1234"`, first-4/last-4) — never the full number.
|
||||
- **Status:** open
|
||||
|
||||
Reference in New Issue
Block a user