Add frontend phase 15 updates: complete MVP for admin backoffice and partner-center consoles, including new services and endpoints; document requests for backend enhancements.
This commit is contained in:
@@ -12,6 +12,44 @@ for awareness.
|
||||
- **Requests filed:** frontend/requests/for-backend.md (yes/no)
|
||||
-->
|
||||
|
||||
## frontend-phase-15-b15 — Admin backoffice & partner-center consoles — 2026-07-10 — **MVP COMPLETE**
|
||||
- **Shipped:** the internal **operational cockpit** — the role-gated admin backoffice (desktop sidebar shell) +
|
||||
the separately-scoped **partner-center portal**. Two new domains: **`services/admin`** (config / holidays /
|
||||
audit / support-alerts / RBAC — `usePlatformConfigs`/`useUpdatePlatformConfig`/`useConfigChangeHistory`/
|
||||
`useHolidays`/`useUpsertHoliday`/`useAuditLogs`/`useSupportAlerts`/`useAssignSupportAlert`/
|
||||
`useResolveSupportAlert`/`useAdminRoles`/`useGrantRole`/`useRevokeRole`) and **`services/partnerCenter`** (admin
|
||||
management + `useMyPartnerCenter`/`useMySponsoredNurses`/`useMySponsoredBookings`/`useMySettlement` portal reads).
|
||||
**Admin-endpoint additions to 5 existing domains** (the staff lens, not new domains): verification
|
||||
(`useVerificationQueue`/`useVerificationCase`/`useVerificationDocumentUrl`/`useDecideStep`/`useApproveVerification`/
|
||||
`useRejectVerification`), refunds (`useRefundPreview`/`useInitiateRefund`/`useApproveRefund`/`useRejectRefund`),
|
||||
payouts (`usePayoutBatches`/`usePayoutBatchDetail`/`usePreviewPayoutBatch`/`useRunPayoutBatch`/`useRetryPayout`/
|
||||
`useRecordTransferReference`), reviews (`useModerationQueue`/`useModerateReview`), tickets (`useAdminTickets`/
|
||||
`useAdminTicket`/`useAdminTicketThread`/`usePostAdminMessage` — the admin types carry `isInternal`, the user types
|
||||
never do). **Screens:** `/admin` overview + verification (queue + `[nurseId]` case w/ signed-URL `DocumentViewer`,
|
||||
structured credential entry, Approve-only-when-all-passed), tickets (queue + `[id]` thread w/ internal-note
|
||||
composer + ticket-linked **RefundPanel**), payouts (dashboard + preview → **idempotency-keyed run** + `[batchId]`
|
||||
detail w/ retry + transfer-ref reconcile), reviews (moderation publish/hide/reject), config (typed inputs + 0–1
|
||||
validation + audited-save + history drawer), holidays (`is_bank_closed`), alerts (internal triage assign/resolve),
|
||||
audit (read-only filtered diff), partners (list/create + `[id]` verify/activate/edit + roster/assign, IBAN
|
||||
write-then-masked), roles (**DEFERRED-IF-MISSING**, mock-backed). **Partner portal** (`/partner` scope): home
|
||||
(onboarding state + license + MoR), nurses, bookings, and settlement (**MoR-gated** commission/VAT invoices via
|
||||
`PartnerSettlementRow` + signed-URL PDF; non-MoR → "via Balinyaar" state). New shared/tested `@/components/admin`:
|
||||
`AdminPageHeader`/`AdminEmptyState`/`AdminErrorState`/`AdminPager`/`ConfirmDialog`/`AdminDataTable`/`ConfigRow`/
|
||||
`AuditLogRow`/`SupportAlertCard`/`PartnerSettlementRow`/`DocumentViewer`/`RefundPanel`/`AdminMessageBubble` (13,
|
||||
36 tests). Role-gating via **`useAdminCapabilities()`** (fine-grained `roleCodes` off `AuthContext`); `admin` +
|
||||
`partner` i18n namespaces (both locales, incl. پروانه تأسیس / مسئول فنی / نماد اعتماد الکترونیکی / سامانه مودیان).
|
||||
- **Consumes:** dev/contracts/domains/messaging-notifications-admin.md (b15) + verification.md (b6) + refunds-invoices.md
|
||||
(b11) + payouts.md (b13) + reviews-records.md (b14) + config-reference.md (b1).
|
||||
- **Mocked client-side:** `services/admin` (`USE_ADMIN_MOCK`), `services/partnerCenter` (`USE_PARTNER_MOCK`), and the
|
||||
admin methods of verification/refunds/payouts/reviews/tickets — all mock-primary (their real `clientApi` maps the
|
||||
live routes and targets proposed slugs for the gaps). See mocks-registry.
|
||||
- **Gate:** npm run check green (0/0) · npm run test:ci green (325 tests, +36) · npm run build green with
|
||||
NEXT_PUBLIC_API_URL set · i18n admin+partner in sync.
|
||||
- **Requests filed:** frontend/requests/for-backend.md — yes (REQ-029…037: config audit columns, rich audit
|
||||
filters, RBAC endpoints, partner portal split reads + activate/suspend, invoice total, verification nurse-queue
|
||||
+ on-demand doc URL + whole-verification approve/reject, refund preview + approve/reject, payout single-preview +
|
||||
holidayShifted + record-transfer-reference, moderation `tagCodes`).
|
||||
|
||||
## frontend-phase-14-b15 — Messaging (tickets) & notifications — 2026-07-10
|
||||
- **Shipped:** the social/communication layer for the customer **and** nurse apps (role decides chrome, not
|
||||
the components; admin lens DEFERRED to f15). Two new domains — **`services/tickets`** (`useMyTickets` /
|
||||
|
||||
@@ -488,3 +488,95 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
linked bookings are themselves mock-primary. When they land the swap is a single `USE_TICKETS_MOCK = false` flip
|
||||
(no hook/component change) — `ticketsClientApi` already maps the live routes.
|
||||
- **Status:** open
|
||||
|
||||
## REQ-029 — Config `updatedAt`/`updatedBy` on `PlatformConfigDto` — filed by frontend-phase-15-b15 — 2026-07-10
|
||||
- **Need:** the f15 config editor shows each row's last-changed meta ("updated {date} by {actor}"), but the b1
|
||||
`PlatformConfigDto` carries only `{ key, value, dataType, description }`. Proposed: add `updatedAt` (UTC) +
|
||||
`updatedBy` (actor id or display) to the DTO (the audit trail already records the change; this surfaces the
|
||||
latest on the row without opening the drawer). Mock supplies both; the real row degrades gracefully without.
|
||||
- **Why:** finance needs the effective value + who last touched it at a glance. `services/admin` is mock-primary
|
||||
(`USE_ADMIN_MOCK = true`); `adminClientApi.listConfigs` maps the live route 1:1 and leaves these undefined.
|
||||
- **Status:** open
|
||||
|
||||
## REQ-030 — Audit-trail filters: actor / action / date-range — filed by frontend-phase-15-b15 — 2026-07-10
|
||||
- **Need:** `GET audit/get_audit_trail` filters only by `entity_type` + `entity_id`. The f15 audit viewer offers
|
||||
actor, action, and from/to date filters. Proposed: add `actor_id`, `action`, `from`, `to` query params (the mock
|
||||
honours all four). Until then the real client passes only the supported two and the rest degrade.
|
||||
- **Why:** ops audits by actor and by time window, not only by a single entity. Mock-primary.
|
||||
- **Status:** open
|
||||
|
||||
## REQ-031 — RBAC role grant/revoke/list endpoints — filed by frontend-phase-15-b15 — 2026-07-10
|
||||
- **Need:** the b15 contract exposes no role-management endpoints. The (optional, **DEFERRED-IF-MISSING**) admin
|
||||
roles console needs: `GET admin_roles/list_roles[?user_id=]` returning `RoleGrant[]` (`{ userId, role, grantedBy,
|
||||
grantedAt, revokedAt }`), `POST admin_roles/grant_role { userId, role }`, `POST admin_roles/revoke_role
|
||||
{ userId, role }`, where `role` is one of `super_admin|admin|support|finance|moderation`. The screen is built
|
||||
against the mock and flagged DEFERRED-IF-MISSING; swap `USE_ADMIN_MOCK=false` once the routes land.
|
||||
- **Why:** to manage which users hold which admin scopes. Not on the testable acceptance path.
|
||||
- **Status:** open
|
||||
|
||||
## REQ-032 — Partner-portal split reads + activate/suspend + IBAN write-then-masked — filed by frontend-phase-15-b15 — 2026-07-10
|
||||
- **Need:** the b15 contract has admin partner-center CRUD/verify/sponsor + a single `GET /centers/{id}/dashboard`
|
||||
portal endpoint. The f15 partner portal + admin management need: (1) a **center-scoped "my center"** resolution
|
||||
(`GET centers/me` or `/centers/me/dashboard`) so a center admin never passes a raw id; (2) split portal reads
|
||||
`GET centers/me/nurses`, `GET centers/me/bookings?status=&page=`, `GET centers/me/settlement?page=` (or these as
|
||||
fields on the dashboard); (3) an **activate/suspend** toggle (`POST admin/partner-centers/{id}/set-active
|
||||
{ isActive }`) — verify only activates; (4) confirm the **write-then-masked** IBAN contract (PATCH accepts a
|
||||
full `settlementIban`, GET returns only `settlementIbanMasked` last-4). Also the admin **roster read**
|
||||
(`GET admin/partner-centers/{id}/nurses`). `services/partnerCenter` is mock-primary (`USE_PARTNER_MOCK`).
|
||||
- **Why:** the portal (separate authz scope, own-center tenancy) + the admin management screens render these.
|
||||
- **Status:** open
|
||||
|
||||
## REQ-033 — Partner settlement: per-booking commission invoices + invoice `total` — filed by frontend-phase-15-b15 — 2026-07-10
|
||||
- **Need:** the merchant-of-record settlement view lists per-booking **commission invoices** (b11 `Invoice`
|
||||
shape) filtered to the center, but there's no center-scoped invoice-list route (see REQ-032). Also the b11
|
||||
`Invoice` DTO has no `total` — the settlement row shows `platform commission + BNPL commission + VAT = total`;
|
||||
the client currently **sums the served legs** for the total (a display sum, not a load-bearing re-derivation).
|
||||
Proposed: serve `totalIrr` on the invoice (= commission + bnplCommission + vat), plus a center-scoped list.
|
||||
- **Why:** the settlement/invoice view (rendered only when `is_merchant_of_record`) needs a reconciling total.
|
||||
VAT stays on the commission line only; the rate is config-driven (`vat_rate`), never hardcoded.
|
||||
- **Status:** open
|
||||
|
||||
## REQ-034 — Verification admin: nurse-level queue + on-demand document URL + whole-verification approve/reject — filed by frontend-phase-15-b15 — 2026-07-10
|
||||
- **Need:** three gaps in the b6 admin surface for the f15 review queue: (1) `GET admin_verifications` returns
|
||||
**one row per pending step**; the queue UI is **nurse-level** (progress "X of Y", next step, expiring flag) — a
|
||||
nurse-grouped list (or a `group_by=nurse` param) would avoid a lossy client fold. (2) A **per-document on-demand
|
||||
signed-URL** route (`GET admin_verifications/documents/{documentId}/url`) — signed URLs are short-lived and must
|
||||
be fetched on demand / re-requested on expiry, not read from the long-lived case payload. (3) **whole-
|
||||
verification** approve/reject (`POST admin_verifications/{id}/approve` and `/reject`) — today the aggregate flips
|
||||
implicitly when the last step is decided; the UI wants an explicit Approve (enabled only when all steps pass) /
|
||||
Reject action. `services/verification` is mock-primary.
|
||||
- **Why:** the queue + per-nurse case + signed-URL document viewer render these. The client never writes
|
||||
`is_verified` — the server flips it transactionally (§5).
|
||||
- **Status:** open
|
||||
|
||||
## REQ-035 — Refund preview + explicit approve/reject — filed by frontend-phase-15-b15 — 2026-07-10
|
||||
- **Need:** b11 `POST admin_refunds` **creates and executes** in one call, so there is no way to render a
|
||||
**preview** (tiered percentage + fee/payout decomposition + channel + BNPL ETA + will-create-clawback) before
|
||||
initiating. Proposed: `GET admin_refunds/preview?booking_id=&ticket_id=` returning the server-computed
|
||||
decomposition (the client renders it, never recomputes the split/percentage). Also explicit
|
||||
`POST admin_refunds/{id}/approve` and `/reject` for the provider-revert-failure → retry and the decline paths
|
||||
(today the single POST both creates + executes). `services/refunds` admin methods are mock-primary;
|
||||
`initiateRefund` maps the live `POST admin_refunds`.
|
||||
- **Why:** the ticket-linked refund panel shows the preview, then initiate → (retry on provider failure) / reject.
|
||||
- **Status:** open
|
||||
|
||||
## REQ-036 — Payout single preview endpoint + `holidayShifted` flag + record-transfer-reference — filed by frontend-phase-15-b15 — 2026-07-10
|
||||
- **Need:** the f15 payout dashboard wants (1) a **single preview** call returning eligible + skipped + the
|
||||
holiday-shifted processing date together (b13 `GET admin_payouts/eligible` is paged and returns only the eligible
|
||||
page — skipped nurses come back on the batch `POST`); a `GET admin_payouts/preview?periodStart=&periodEnd=`
|
||||
returning `{ eligible[], skipped[], processingDate, holidayShifted, totalNet }` would drive the dry-run cleanly.
|
||||
(2) A `holidayShifted` boolean on `PayoutBatchDto` / the preview so the UI can badge a batch whose processing
|
||||
date moved off a bank-closed day (currently not on the DTO). (3) A **record-transfer-reference** route
|
||||
(`POST admin_payouts/{payoutId}/transfer_reference { reference }`) for finance to attach the real bank reference
|
||||
(b13 has `mark_failed` but no reconcile-reference write). `services/payouts` admin methods are mock-primary; the
|
||||
run/retry map the live routes with the `Idempotency-Key` header.
|
||||
- **Why:** preview → run (idempotency-keyed, no double-pay) → detail with per-nurse retry + transfer-ref reconcile.
|
||||
- **Status:** open
|
||||
|
||||
## REQ-037 — Moderation queue `tagCodes` on `ModerationQueueItemDto` — filed by frontend-phase-15-b15 — 2026-07-10
|
||||
- **Need:** the f15 moderation queue renders each review's tag chips, but `ModerationQueueItemDto` (b14) doesn't
|
||||
list `tagCodes` (only the public `ReviewListItemDto` does). Proposed: add `tagCodes: string[]` to the moderation
|
||||
DTO. The client defaults to `[]` meanwhile. `services/reviews` moderation methods are mock-primary; `moderateReview`
|
||||
maps the live `PATCH reviews/{id}/status` and the queue maps `GET admin/reviews/moderation_queue`.
|
||||
- **Why:** moderators see the tags a review carries before publishing/hiding.
|
||||
- **Status:** open
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
# Frontend Phase 15 (b15) — Admin backoffice & partner-center consoles — report
|
||||
|
||||
**Date:** 2026-07-10 · **Track:** frontend · **Status:** ✅ complete — **this is the final frontend phase; MVP is complete.**
|
||||
**Gate:** `npm run check` green (0 errors / 0 warnings) · `npm run test:ci` green (**325 tests, +36**) · `npm run build` green (all 18 new routes compile) · `admin`/`partner` i18n in sync · i18n key audit clean.
|
||||
|
||||
---
|
||||
|
||||
## 1. What was built
|
||||
|
||||
The internal **operational cockpit** that runs the marketplace: a role-gated **admin backoffice** in the f0 desktop
|
||||
sidebar shell, plus a separately-scoped **partner-center portal**. All of it is a *read-and-act* surface over data
|
||||
other domains own — the client renders the contract's values and issues the sanctioned commands; it **never**
|
||||
computes eligibility, money decomposition, holiday shifts, the `is_verified` flip, or the review aggregate (§5).
|
||||
|
||||
### Two new domain services (the `auth`-service shape)
|
||||
- **`services/admin`** — config, holidays, audit, support-alerts, RBAC. 12 hooks; filters + page in every key so
|
||||
each worklist filter/page caches independently. Mock-primary.
|
||||
- **`services/partnerCenter`** — admin-side center management + the center-scoped portal reads. 12 hooks. Mock-primary.
|
||||
|
||||
### Admin-endpoint additions to 5 existing domains (the staff lens — *not* new domains)
|
||||
- **verification** (b6): `useVerificationQueue` / `useVerificationCase` / `useVerificationDocumentUrl` (on-demand
|
||||
signed URL) / `useDecideStep` / `useApproveVerification` / `useRejectVerification`.
|
||||
- **refunds** (b11): `useRefundPreview` / `useInitiateRefund` / `useApproveRefund` / `useRejectRefund` (ticket-linked).
|
||||
- **payouts** (b13): `usePayoutBatches` / `usePayoutBatchDetail` / `usePreviewPayoutBatch` / `useRunPayoutBatch`
|
||||
(idempotency-keyed) / `useRetryPayout` / `useRecordTransferReference`.
|
||||
- **reviews** (b14): `useModerationQueue` / `useModerateReview`.
|
||||
- **tickets** (b15): `useAdminTickets` / `useAdminTicket` / `useAdminTicketThread` / `usePostAdminMessage`. The **admin**
|
||||
ticket types carry `isInternal`; the **user-app** types deliberately do not — the two surfaces stay distinct so an
|
||||
internal note can never bleed into a user view (§5).
|
||||
|
||||
### Shared composites — `@/components/admin` (13, each with a co-located `*.test.tsx`; 36 tests)
|
||||
`AdminPageHeader`, `AdminEmptyState`, `AdminErrorState`, `AdminPager`, `ConfirmDialog` (optional required-reason),
|
||||
`AdminDataTable` (generic dense worklist table, horizontal-scroll-contained), `ConfigRow`, `AuditLogRow` (expandable
|
||||
diff), `SupportAlertCard`, `PartnerSettlementRow` (reconciling commission/VAT breakdown via the f0 `PriceBreakdown`),
|
||||
`DocumentViewer` (signed-URL on-demand + expired→re-request), `RefundPanel` (server-computed preview → initiate →
|
||||
provider-failure retry / reject), `AdminMessageBubble` (internal-note styled distinctly).
|
||||
|
||||
### Screens (18 new routes)
|
||||
- **Admin** (`/admin/*`, role-gated): overview landing · verification (queue + `[nurseId]` case) · tickets (queue +
|
||||
`[id]` thread w/ internal-note composer + RefundPanel) · payouts (dashboard + `[batchId]` detail) · reviews
|
||||
(moderation) · config · holidays · alerts · audit · partners (list + `[id]` detail) · roles (**DEFERRED-IF-MISSING**).
|
||||
- **Partner portal** (`/partner/*`, separate scope): home · nurses · bookings · settlement (MoR-gated).
|
||||
|
||||
### Foundation
|
||||
- **`useAdminCapabilities()`** (`@/hooks`) — a memoized selector over the session's fine-grained `roleCodes`
|
||||
(added to `SessionUser`, hydrated from `/me` by `useSessionRoleSync`). Drives per-console `can*` booleans that
|
||||
hide/disable controls a role can't use (server still authorizes every command).
|
||||
- **`PartnerLayout`** + the `(private-routes)/partner/` route group (a separate authz scope).
|
||||
- The `admin` + `partner` i18n namespaces in both locales (incl. پروانه تأسیس / مسئول فنی / نماد اعتماد الکترونیکی /
|
||||
سامانه مودیان and the enum-label prefixes keyed off stable codes).
|
||||
- New `AppIcon` registry entries; new `ROUTES.ADMIN_*` / `ROUTES.PARTNER_*` + path helpers.
|
||||
|
||||
---
|
||||
|
||||
## 2. What is now testable, and exactly how
|
||||
|
||||
Run `npm run dev`, sign in as an **admin** (mock-primary, so no live backend needed). The §7 acceptance steps:
|
||||
|
||||
1. **Verify a nurse.** `/admin/verification` → pick a pending nurse → the case loads each document via a **signed URL**
|
||||
(`DocumentViewer`; sentinel `documentId 9999` exercises the error→re-request path). Pass the steps (reject one with a
|
||||
required reason), enter a **structured credential** on a credential-bearing step; **Approve** is disabled until every
|
||||
step is `passed` → confirm → the nurse leaves the queue. The client never wrote `is_verified`.
|
||||
2. **Process a refund.** `/admin/tickets` → open the **refund** ticket (bookingId + refundId seeded) → **RefundPanel**
|
||||
shows the **server-computed** tiered % + fee/payout decomposition (reconciles to the rial) + channel + BNPL ETA;
|
||||
the post-payout booking shows the read-only **clawback notice**; the decline **sentinel** shows **retry**.
|
||||
3. **Preview + run a payout batch.** `/admin/payouts` → **preview next batch** → eligibility breakdown (eligible +
|
||||
no-IBAN-skipped + clawback line + **holiday-shifted** processing date) → **run batch** (confirm requires an
|
||||
**idempotency key** — a double-click can't double-pay) → `processing`. `[batchId]` detail → a **failed** payout →
|
||||
**retry**; reconcile a `transfer_reference`.
|
||||
4. **Moderate a review.** `/admin/reviews` → a `pending_moderation` review (low-rating flag) → **publish/hide/reject**
|
||||
(reject/hide require a reason) → it leaves the queue; the client never computed the aggregate.
|
||||
5. **Edit a config value.** `/admin/config` → edit `vat_rate` → the input validates **0–1** (`1.5` blocked) → save →
|
||||
the dialog states it is **audited, immediate, non-retroactive** → the **history drawer** shows old→new + actor + Shamsi time.
|
||||
6. **Resolve a support alert.** `/admin/alerts` → filter to **open** → **assign to me** → **resolve** with a note.
|
||||
It appears in **no** customer/nurse/partner view.
|
||||
7. **Holiday manager.** `/admin/holidays` → add a holiday with **`is_bank_closed` on** → listed (the client never
|
||||
computes the shift; the payout preview in step 3 shows the server-shifted date).
|
||||
8. **Audit viewer.** `/admin/audit` → filter by entity/actor/date → paginated; expand a row for the `changedFields`
|
||||
diff. **No** edit/delete control exists.
|
||||
9. **Partner portal.** Sign in mapping to a center admin → `/partner` shows onboarding state + license + MoR;
|
||||
`/partner/nurses` + `/partner/bookings` show only that center's data; `/partner/settlement` renders the commission/VAT
|
||||
invoices + signed-URL PDF + **masked IBAN** **only when merchant-of-record** (a non-MoR center shows the "via
|
||||
Balinyaar" state). Back as an admin → `/admin/partners` → create/verify/activate + assign a nurse; IBAN is
|
||||
write-then-masked (submit full, only last-4 ever shows).
|
||||
10. **RBAC + i18n + RTL + caching.** A `support` role sees no payout/refund controls; a `moderation` role sees only
|
||||
moderation (drive via `useAdminCapabilities`). `fa`↔`en` translates every label (incl. the Persian legal terms) and
|
||||
the sidebar mirrors. Switching worklist filters/pages caches separately (filters+page in the key) — no refetch of
|
||||
loaded data.
|
||||
|
||||
---
|
||||
|
||||
## 3. What is mocked, and how to make it real
|
||||
|
||||
All f15 data is **mock-primary** (the real `clientApi` in each domain maps the live routes and targets proposed slugs
|
||||
for the gaps; the swap is a one-line flag flip per domain — no hook/component change). Full detail in
|
||||
`reports/mocks-registry.md` (three new/updated rows). Seams + flags:
|
||||
- `services/admin` — `USE_ADMIN_MOCK` (config/holidays/audit/support-alerts live at b1; RBAC + config audit columns +
|
||||
rich audit filters are gaps → REQ-029/030/031).
|
||||
- `services/partnerCenter` — `USE_PARTNER_MOCK` (admin CRUD/verify/sponsor live at b15; portal split reads +
|
||||
activate/suspend + invoice total are gaps → REQ-032/033).
|
||||
- verification/refunds/payouts/reviews/tickets admin methods — the owning domain's flag (REQ-034/035/036/037).
|
||||
|
||||
**No backend seams were introduced** — `IObjectStorage`/`IBankTransferProvider`/`IBnplProvider`/`IMoadianClient`/
|
||||
`ILicenseVerificationService`/the audit interceptor/the notification dispatcher are all server-side (b1/b6/b11/b13/b14/b15);
|
||||
the frontend never touches them.
|
||||
|
||||
---
|
||||
|
||||
## 4. Contracts consumed
|
||||
`messaging-notifications-admin.md` (b15, primary) + `verification.md` (b6) + `refunds-invoices.md` (b11) +
|
||||
`payouts.md` (b13) + `reviews-records.md` (b14) + `config-reference.md` (b1). All types derived from these — none guessed.
|
||||
|
||||
## 5. Requests filed (`frontend/requests/for-backend.md`)
|
||||
**REQ-029** config `updatedAt`/`updatedBy` · **REQ-030** audit actor/action/date filters · **REQ-031** RBAC role endpoints ·
|
||||
**REQ-032** partner-portal split reads + activate/suspend + IBAN write-then-masked · **REQ-033** center-scoped invoice list
|
||||
+ invoice `totalIrr` · **REQ-034** verification nurse-level queue + on-demand doc URL + whole-verification approve/reject ·
|
||||
**REQ-035** refund preview + explicit approve/reject · **REQ-036** payout single-preview + `holidayShifted` +
|
||||
record-transfer-reference · **REQ-037** moderation `tagCodes`.
|
||||
|
||||
---
|
||||
|
||||
## 6. MVP-complete closeout
|
||||
This is the **final frontend phase** — every customer, nurse, admin, and partner surface in the build plan now exists.
|
||||
|
||||
- **Deferred-if-missing:** the **RBAC roles console** (`/admin/roles`) is built against the mock and tagged
|
||||
DEFERRED-IF-MISSING; it activates when the b15 role endpoints land (REQ-031). It is not on the testable acceptance path.
|
||||
- **Modeled-but-inactive, no UI (as specified):** `organizations` / `organization_nurses` (employer model),
|
||||
`fraud_flags` (ML console), `recurring_booking_schedules` (recurrence) — data-model/13. Also **no UI** for: full
|
||||
سامانه مودیان e-invoice automation / digital-signature (the portal only *views* the issued invoice ref + PDF),
|
||||
push/SMS channels, an analytics-warehouse dashboard, on-demand/instant payout, per-nurse payout-frequency settings.
|
||||
- **Minor i18n substitutions the screen agents flagged** (all use existing keys; cosmetic, non-blocking): the payout
|
||||
retry-success toast reuses `admin.saved`; the partner nurse verified/unverified column borrows `center_state_*`
|
||||
labels; partner booking-status renders the raw stable status code. Add dedicated keys later if desired.
|
||||
@@ -82,3 +82,6 @@ the frontend can build before the backend phase merges, and swap to the real HTT
|
||||
| f8 bookings mock — completed-booking seed 5005 + f13 cross-mock reads | `client/src/services/bookings/apis/mockApi.ts` | **Non-seam additions (mirrors the f10 refunds precedent).** The f8 seeds had **no `completed` booking** (only `confirmed`/`in_progress`/`cancelled`), so f13's review flow needs one: added **booking 5005** (`status: 'completed'`, nurse 1, patient 905, one completed EVV session) so the customer can open a completed booking and leave a review. Also added a **cross-mock read helper** — `mockGetBookingForReview(id)` (single booking, clone) — imported by the reviews mock to gate eligibility and read the patient/nurse snapshot for a submission (the `listBookings` seam row omits `patientId`/`nurseId`). One-way edge INTO bookings (the bookings mock never imports f13), so no cycle | — (part of `USE_BOOKINGS_MOCK`) | When the bookings flow goes real (b9/b10 conversion live), 5005 stops being a static seed and the cross-mock helpers retire with the reviews/records mocks | 🟡 |
|
||||
| `TicketsApi` | `client/src/services/tickets/apis/mockApi.ts` | **The f14 ticket channel (b15).** b15 serves open/list/thread/message and `ticketsClientApi` maps them 1:1 — but the linked bookings are themselves mock-primary and the wire summary lacks `unreadCount`/`lastMessageAt` (**REQ-028**), so the mock is primary. It seeds 3 tickets (a booking-5001 **coordination** ticket with a **stored internal admin note the user view NEVER returns** — the no-leak demo — plus a support + a closed refund ticket), returns them newest-activity first with a per-ticket unread count that **clears on open**; `openTicket` is **idempotent for `coordination + bookingId`** (so "Get support" from a booking jumps to the existing thread) and prepends a new ticket to the inbox; `postMessage` appends as the current viewer (tracked from the last `getTicket` so an optimistic message reconciles as **mine** in whichever app is open), throws `403` on a **closed** ticket, and throws `500` on the dev sentinel body `'/fail'` (the optimistic failure→retry path). `MOCK_VIEWER_USER_ID` (per-role "me") drives `isMine`; **`isInternal` is never modelled in the user-app types** | `USE_TICKETS_MOCK` (`services/tickets/constants.ts`, default `true`) | Deliver **REQ-028** (`unreadCount`/`lastMessageAt` on the summary + a by-booking user lookup + optional author name + optional `clientMessageId` idempotency) and make the upstream bookings flow real, then set flag `false` — `ticketsClientApi` already maps the live b15 routes 1:1 (drops any leaked internal message defensively). No hook/component change | 🟡 |
|
||||
| `NotificationsApi` | `client/src/services/notifications/apis/mockApi.ts` | **The f14 notification center + polled bell (b1).** The b1 endpoints are live and `notificationsClientApi` maps them 1:1, but a notification only exists once some other backend domain **dispatches** one (`INotificationDispatcher`) — none run client-side while the upstream flows are mock-primary — so there'd be nothing to show. The mock seeds a realistic **unread-first** feed spanning **every deep-link class** (ticket_message/booking_confirmed/refund_processed/payment_captured/payout_paid/review_published + one unknown-type/no-payload row that degrades to no deep-link), each with a snake_case `dataJson` string the list maps through the **real** `parseNotificationData`; `getUnreadCount`/`markRead`/`markAllRead` mutate the in-memory feed. **Dev-only `__mockPushNotification(type,title,dataJson?,body?)`** prepends a fresh **unread** row so a human can watch the bell badge increment within the poll interval (phase §7 step 4). Ids align with the f8 bookings + tickets mocks so a deep-link lands on a real screen | `USE_NOTIFICATIONS_MOCK` (`services/notifications/constants.ts`, default `true`) | When the upstream domains dispatch real notifications, set flag `false` — `notificationsClientApi` already maps the live b1 `notifications/*` routes 1:1 (`page`/`pageSize`, `{count}`, `{notificationId}`). No hook/component change | 🟡 |
|
||||
| `AdminApi` | `client/src/services/admin/apis/mockApi.ts` | **The f15 backoffice-owned data (b1 + b15).** Fixtures engineered to exercise every console state: **one config per `data_type`** (decimal/int/bool/json/string — so the typed inputs + the 0–1 rate validation are all reachable) with a **change-history** trail; **holidays** with bank-closed days; a **paged audit log** with `changedFields` diffs (one row `<redacted>` for a PII field); a **support-alert** list spanning **every** `type` (`low_rating`/`evv_no_show`/`evv_location_mismatch`/`verification_expired`/`shared_sim`/`payment_anomaly`/`fraud_signal`/`nurse_clawback`/`emergency`) and all three statuses so the worklist filters are testable; and **RBAC** grants. Mutations mutate the in-memory arrays (a config save writes a history row; assign/resolve advance an alert; grant/revoke flip a role). Timestamps relative to `now` | `USE_ADMIN_MOCK` (`services/admin/constants.ts`, default `true`) | b1 config/holiday/audit/support-alert routes are live and `adminClientApi` maps them 1:1 — deliver **REQ-029** (config `updatedAt`/`updatedBy`) + **REQ-030** (audit actor/action/date filters) + **REQ-031** (the RBAC `admin_roles/*` endpoints, which don't exist yet), then set flag `false`. No hook/component change | 🟡 |
|
||||
| `PartnerCenterApi` | `client/src/services/partnerCenter/apis/mockApi.ts` | **The f15 partner centers (b15) — admin management + the center-scoped portal.** Returns **center #1 = merchant-of-record** (the settlement/invoice view renders) **and** #2 = non-MoR (the "settlement runs through Balinyaar" state) **and** a **draft** #3 (unverified banner); sponsored nurses (verified + unverified), sponsored bookings, and commission invoices whose **platform commission + BNPL commission + VAT = total** (VAT on the commission line only) with a fake 22-digit `moadianReferenceNumber` + a stub PDF url. `settlementIbanMasked` is **last-4 only** (write-then-masked: create/edit submit a full IBAN, only last-4 ever returns). Admin CRUD/verify/set-active/assign-nurse + the portal "my center" reads all mutate/read the in-memory world; "my center" resolves to `MOCK_MY_CENTER_ID` (=1, MoR) | `USE_PARTNER_MOCK` (`services/partnerCenter/constants.ts`, default `true`) + `MOCK_MY_CENTER_ID` | b15 admin partner-center CRUD/verify/sponsor are live; deliver **REQ-032** (portal split reads `centers/me[/nurses|/bookings|/settlement]` + the activate/suspend toggle + confirm the write-then-masked IBAN) + **REQ-033** (center-scoped invoice list + invoice `totalIrr`), then set flag `false` — `partnerCenterClientApi` maps the live admin routes and targets the proposed portal slugs. No hook/component change | 🟡 |
|
||||
| Admin-endpoint additions to existing domain mocks (`verification`/`refunds`/`payouts`/`reviews`/`tickets`) | the same `apis/mockApi.ts` files (+ their `clientApi.ts`) | **The f15 staff lens over prior domains** — new admin methods added behind the existing seams (no new seam, no hook/component change on swap). **verification:** a nurse-level review queue (`pending`/`in_review`, one with an expiring credential) + a per-nurse case whose manual credential steps carry a document, and `getDocumentSignedUrl` that returns a **fresh short-lived URL each call** (sentinel `documentId 9999` throws → viewer error/re-request path); `decideStep`/`approve`/`reject` re-aggregate. **refunds:** a `getRefundPreview` with the fee/payout split reconciling to the rial per booking (a normal card, a BNPL w/ ETA, a post-payout w/ clawback notice, and a provider-decline **sentinel that fails then retries succeeds**). **payouts:** batches spanning `completed`/`partially_failed`/`processing` (one holiday-shifted), a preview w/ eligible + skipped(no-IBAN) + clawback line + holiday-shifted date, an **idempotency-keyed** run/retry (same key → same result, never double-pays), a `failed` payout to retry, and record-transfer-reference. **reviews:** a moderation queue incl. a low-rating flagged review; `moderateReview` returns a plausible recomputed aggregate. **tickets:** a global admin queue + a thread that **includes** the seeded internal note (the no-leak *inverse* demo) + `postAdminMessage` w/ `isInternal`; a refund-linked ticket (bookingId+refundId) so the RefundPanel opens from it | the owning domain's flag (`USE_VERIFICATION_MOCK` / `USE_REFUNDS_MOCK` / `USE_PAYOUTS_MOCK` / `USE_REVIEWS_MOCK` / `USE_TICKETS_MOCK`, all default `true`) | Deliver the per-domain admin gaps — **REQ-034** (verification nurse-queue + on-demand doc URL + whole-verification approve/reject), **REQ-035** (refund preview + explicit approve/reject), **REQ-036** (payout single-preview + `holidayShifted` + record-transfer-reference), **REQ-037** (moderation `tagCodes`) — then flip the owning domain's flag. The real `clientApi` methods already map the live admin routes 1:1 and target the proposed slugs for the gaps | 🟡 |
|
||||
|
||||
Reference in New Issue
Block a user