refinement phase 3
This commit is contained in:
@@ -29,7 +29,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
pattern every later frontend phase inherits.
|
||||
- **Proposed shape:** `{ isSuccess: boolean, statusCode: number, message?: string, requestId?: string, data?: T }`
|
||||
and `data: { items: T[], total: number, page: number, pageSize: number }` for lists.
|
||||
- **Status:** open
|
||||
- **Status:** confirmed in refinement-phase-3 — the `ApiResult` envelope (payload under `data`, camelCase body, integer `statusCode`) and `PagedResult` `{ items, total, page, pageSize }` are the intended shapes for all endpoints. **Note:** the list query param binds camelCase **`pageSize`** (case-insensitive); the `page_size` doc occurrences were swept (REQ-010).
|
||||
|
||||
## REQ-002 — OTP length + expiry in RequestOtpResult — filed by frontend-phase-1-b2 — 2026-07-02
|
||||
- **Need:** Add `codeLength` (int) and `expiresInSeconds` (int) to `RequestOtpResult`.
|
||||
@@ -38,7 +38,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
(`OTP_CODE_LENGTH = 6`, inferred from the live 6-digit verify example, not the 4-box wireframe). Surfacing
|
||||
the length makes the box count contract-driven; the expiry lets us show "code expires in …".
|
||||
- **Proposed shape:** `{ otpSent: boolean, resendAvailableInSeconds: number, codeLength: number, expiresInSeconds: number }`
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-003 — Machine-readable error codes for verify_otp failures — filed by frontend-phase-1-b2 — 2026-07-02
|
||||
- **Need:** A stable `code` on the 400 envelope for verify_otp that distinguishes wrong code vs expired code
|
||||
@@ -50,7 +50,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
otherwise degrades to a generic "incorrect or expired" message. A stable machine code (kept generic enough
|
||||
to avoid account enumeration) would let the UI render the precise state + the unlock countdown.
|
||||
- **Proposed shape:** `{ isSuccess: false, statusCode: 400, message: "…", code: "otp_locked", data: { retryAfterSeconds: 60 } }`
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-005 — Patient `relation` + `conditions` fields — filed by frontend-phase-2-b3 — 2026-07-02
|
||||
- **Need:** Add two fields to `PatientDto` and the `patients/create` + `patients/update` bodies:
|
||||
@@ -62,7 +62,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
and drops them on the real path. Adding the columns lets the client flip the flag to the live endpoints.
|
||||
- **Proposed shape:** `PatientDto { …, relation: string|null, conditions: string[] }`; same fields accepted on
|
||||
create/update. Enum for `relation`; `conditions` a stable code list (could also be a normalized child table).
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-006 — Avatar / object-storage upload route (nurse & customer) — filed by frontend-phase-2-b3 — 2026-07-02
|
||||
- **Need:** A multipart image-upload endpoint backed by `IObjectStorage` that returns a stored URL, plus an
|
||||
@@ -72,7 +72,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
has no avatar field or upload route, and the client fetch layer is JSON-only (can't send multipart). The
|
||||
client mocks this behind the `services/profiles` seam (`uploadAvatar` returns an object URL). The real
|
||||
`profilesClientApi.uploadAvatar` throws `501` until this lands.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-007 — Customer name + preferred-language update — filed by frontend-phase-2-b3 — 2026-07-02
|
||||
- **Need:** Either add `firstName`/`lastName`/`preferredLanguage` to the `customer_profiles/upsert` body +
|
||||
@@ -83,7 +83,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
contact. Absent a wire field/endpoint, the client augments name/language behind the `services/profiles` seam
|
||||
(mock-persisted; the real upsert sends only the emergency contact). Confirm the intended home for these so the
|
||||
client stops augmenting.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-004 — Confirm multi-role disambiguation (activeRole?) — filed by frontend-phase-1-b2 — 2026-07-02
|
||||
- **Need:** Confirm whether `MeResult` will gain an `activeRole` (the user's currently-selected actor) for a
|
||||
@@ -112,7 +112,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
- **Proposed shape:** create/update body gains `latitude?: number, longitude?: number`; when both present, store
|
||||
them (and mark the geocode source as "user-pin"); when absent, geocode as today. `CustomerAddressDto` already
|
||||
returns `latitude`/`longitude`.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-009 — Add `provinceId` to `CustomerAddressDto` — filed by frontend-phase-3-b4 — 2026-07-02
|
||||
- **Need:** Add `provinceId` (long) to `CustomerAddressDto` (the province that owns the address's `cityId`).
|
||||
@@ -124,7 +124,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
the server** can't prefill the province until this lands. `cityId` still implies the province server-side —
|
||||
this is purely to prefill the client cascade.
|
||||
- **Proposed shape:** `CustomerAddressDto { …, provinceId: long }` (join from `cities.province_id`).
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-010 — Confirm/align the list pagination query-param name (catalog + all lists) — filed by frontend-phase-4-b5 — 2026-07-05
|
||||
- **Need:** Confirm the exact query-param name the paginated list endpoints bind for page size. The
|
||||
@@ -136,7 +136,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
the server truly binds `pageSize`, please update the `page_size` occurrences in the contract docs to match;
|
||||
if it binds `page_size`, tell us and we'll switch the client (one line per list call).
|
||||
- **Proposed shape:** list query = `?page={1-based}&pageSize={≤100}`; response `data` = `{ items, total, page, pageSize }`.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3 — server binds **`pageSize`**; the `page_size` occurrences in `dev/contracts/domains/*.md` + `conventions/api-conventions.md` were swept to `pageSize`. (One generated swagger endpoint still shows a `page_size` query name with `x-originalName: pageSize`; it binds `pageSize` case-insensitively.)
|
||||
|
||||
## REQ-011 — Nurse-facing endpoint for structured professional-credential details — filed by frontend-phase-5-b6 — 2026-07-09
|
||||
- **Need:** A nurse-facing command to submit the **structured** credential fields B5 collects alongside the
|
||||
@@ -154,7 +154,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
→ `VerificationStatusDto`. Alternatively, extend the manual-step `documents` confirm body with these fields.
|
||||
- **Also (minor):** the contract's `VerificationStepDto` has no `isRequired` — the client treats **every**
|
||||
seeded step as required (the "X از Y" meter Y = `steps.length`). Confirm that holds, or add `isRequired`.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-012 — Search result + nurse-profile enrichment for discovery (C2/C3) — filed by frontend-phase-6-b7 — 2026-07-09
|
||||
- **Need:** Two extra read surfaces the discovery UI renders but b7/b6/b5 don't yet expose:
|
||||
@@ -175,7 +175,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
When both land, the swap is a single config flip (no hook/component change).
|
||||
- **Proposed shape:** enrich `NurseSearchResultDto` with `{ nurseName, avatarUrl, distanceKm? }`; add
|
||||
`GET api/v1/nurses/{id}/profile` returning the object above. `price`/`priceIrr` stay IRR digit-strings.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-013 — Variant price on `BookingRequestDto` — filed by frontend-phase-7-b8 — 2026-07-09
|
||||
- **Need:** Add the variant's **price** (IRR digit-string) to `BookingRequestDto` (and ideally the nurse's
|
||||
@@ -188,7 +188,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
lets the summary price the service once the domain flips to the real endpoint.
|
||||
- **Proposed shape:** `BookingRequestDto { …, variantPrice: string (IRR digits), nurseAvatarUrl?: string }`.
|
||||
(Money-free rule intact — this is the *rate* of the chosen variant for display, not an engagement total.)
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-014 — Enrich the nurse-inbox list item (variant label + patient age) — filed by frontend-phase-7-b8 — 2026-07-09
|
||||
- **Need:** Add `variantLabel` (and optionally the patient's **age/age-band**) to
|
||||
@@ -199,7 +199,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
the nurse must open the detail (`get/{id}`, which *does* carry `variantLabel`) to see the service. Surfacing
|
||||
`variantLabel` on the row makes the inbox self-describing; a coarse age is a nice-to-have for triage.
|
||||
- **Proposed shape:** `BookingRequestListItemDto { …, variantLabel: string, patientAge?: int }`.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-015 — Confirm the booking/session/EVV enum codes + `checkInAddressMatch` tri-state — filed by frontend-phase-8-b9 — 2026-07-10
|
||||
- **Need:** Two confirmations so the f8 `services/bookings/types.ts` client unions stay wire-accurate:
|
||||
@@ -218,7 +218,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
- **Why:** f8 renders the status timeline, per-session chips, and the EVV banner strictly off these codes;
|
||||
a casing/int drift or a `false`-vs-`null` conflation would mislabel a visit. Low-risk (mock-primary now),
|
||||
but worth locking before f9/f13 consume the same shapes.
|
||||
- **Status:** open
|
||||
- **Status:** confirmed in refinement-phase-3 — booking/session/EVV statuses serialize as the exact snake_case string codes the client unions expect (verified in code); `checkInAddressMatch` is `bool?` = `null` when GPS was absent **or** the frozen address has no resolvable coordinate, `false` = advisory out-of-range (never a block), `true` = in range.
|
||||
|
||||
## REQ-016 — Checkout summary for C6 (served gross/commission/VAT breakdown) — filed by frontend-phase-9-b10 — 2026-07-10
|
||||
- **Need:** A customer-facing read that serves the C6 «خلاصه و پرداخت» money rows for an
|
||||
@@ -237,7 +237,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
serviceCostIrr, commissionIrr, vatIrr, vatRate, totalIrr, grossPriceIrr, balinyaarCommissionIrr,
|
||||
nursePayoutAmount }` — the client's real `paymentClientApi.getCheckoutSummary` already targets this
|
||||
slug and unwraps this exact shape (`client/src/services/payment/types.ts: CheckoutSummaryDto`).
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-017 — Client-readable payment outcome + `bookingId` on a converted request — filed by frontend-phase-9-b10 — 2026-07-10
|
||||
- **Need:** After the gateway redirect returns, the client needs to learn (a) the payment transaction's
|
||||
@@ -256,7 +256,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
- **Proposed shape:** add `bookingId: long?` to `BookingRequestDto` (null until converted) **and/or**
|
||||
`GET api/v1/bookings/{bookingRequestId}/payments/latest` → `{ transactionId, status,
|
||||
gatewayReferenceCode, bookingId? }`.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-018 — Customer invoice availability after capture (auto-issue or owner-issue) — filed by frontend-phase-9-b10 — 2026-07-10
|
||||
- **Need:** Make the b11 invoice reachable by the paying customer right after capture: auto-issue the
|
||||
@@ -267,7 +267,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
admin acts. The UI handles the 404 as a "فاکتور هنوز صادر نشده است" state (and the mock auto-issues at
|
||||
capture to demo the full flow), but on the real rails every fresh payment would land on that empty
|
||||
state.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-019 — Customer-initiated booking cancellation command — filed by frontend-phase-10-b11 — 2026-07-10
|
||||
- **Need:** A **customer-facing** command to cancel a booking (post-payment) and open its refund, e.g.
|
||||
@@ -286,7 +286,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
server resolves the snapshotted policy, enforces the outside-policy/state rules (`409`), posts the
|
||||
balanced reversal, and (per the admin-only rule) may route the refund through an admin/ticket step — the
|
||||
customer surface just needs to *create* the cancellation request and read the resulting refund.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-020 — Cancellation-policy preview (pre-cancel, per-session) — filed by frontend-phase-10-b11 — 2026-07-10
|
||||
- **Need:** A read that **resolves the applicable cancellation policy by current lead time** *before* the
|
||||
@@ -308,7 +308,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
set so the client maps the real codes.
|
||||
- **Proposed shape:** as above. The `cancellationPolicyCode` set + the per-session `reasonCode` set
|
||||
(`un_started` / the blocking session status) should be documented as stable enum codes → i18n keys.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-021 — Customer refund lookup-by-booking + fee-leg decomposition on the customer status — filed by frontend-phase-10-b11 — 2026-07-10
|
||||
- **Need:** Two additions to the customer refund surface:
|
||||
@@ -327,7 +327,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
commission on a revert) is **nullable** on the refund shape and reconciled from the provider response —
|
||||
the b12 `IBnplProvider` mock echoes it as nullable and the client treats any provider-commission figure
|
||||
as opaque/never customer-facing.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-022 — BNPL provider/plan options + repayment schedule (D1/D2/D4) — filed by frontend-phase-11-b12 — 2026-07-10
|
||||
- **Need:** Two customer-facing reads the installment checkout renders that b12 serves **nothing** for:
|
||||
@@ -349,7 +349,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
- **Note on provider set:** the wireframe includes an **in-house `balinyaar`** plan not in the b12
|
||||
`provider_code` enum (`snapppay|digipay|tara|torobpay`). Please add `balinyaar` (or state how the in-house
|
||||
plan is modelled) so `providerCode` stays a closed set.
|
||||
- **Status:** open
|
||||
- **Status:** partially delivered in refinement-phase-3 — `balinyaar` added to the `provider_code` enum. **DEFERRED:** `checkout_bnpl/options/{id}` + `schedule` (per-plan monthly/down-payment split + due-dated repayment table) — b12 deliberately does not model the customer repayment schedule and there is no installment ledger to serve it from; keep D1/D2/D4 mocked until a provider-schedule integration or schedule table lands.
|
||||
|
||||
## REQ-023 — BNPL eligibility should accept the D3 credit-check inputs (national ID / mobile / consent) — filed by frontend-phase-11-b12 — 2026-07-10
|
||||
- **Need:** Either extend `POST api/v1/checkout_bnpl/eligibility` to accept `{ nationalId, mobile, consent }`
|
||||
@@ -359,7 +359,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
the extra fields today (ignored server-side until the KYC step exists) and the mock uses them for the
|
||||
deterministic declined-path demo. The response already carries `eligibilityStatus` + `creditCeilingIrr`,
|
||||
which D3 renders — only the request inputs are the gap.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3 — `checkout_bnpl/eligibility` now accepts `{ nationalId, mobile, consent }` (consent required when the KYC inputs are present; supplied mobile drives the inquiry, else the account mobile). Mock still uses only the mobile until the real KYC step exists.
|
||||
|
||||
## REQ-024 — BNPL provider-reported installment status for the Wallet (D5) + customer bookingId link — filed by frontend-phase-11-b12 — 2026-07-10
|
||||
- **Need:** Two additions for the Wallet installment view and the confirmation deep-link:
|
||||
@@ -383,7 +383,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
surface, and b12 models none of the per-installment schedule/status. The client mocks the whole D5 read
|
||||
behind the `services/bnpl` seam (seeded plan + a plan pushed on each settled checkout). When it lands the
|
||||
swap is one config flip.
|
||||
- **Status:** open
|
||||
- **Status:** partially delivered in refinement-phase-3 — (2) `bookingId` on the settled order **already present** on `BnplOrderStatusDto` (confirmed); (3) `GET checkout_bnpl/by_request/{bookingRequestId}` added (owner-scoped). **DEFERRED:** (1) `checkout_bnpl/wallet_installments` — per-installment provider-reported status Balinyaar does not own/track (no installment ledger in b12); needs provider integration. Keep D5 mocked.
|
||||
|
||||
## REQ-025 — Nurse-read earnings surface: four-bucket balance + per-booking earnings list + nurse payout detail — filed by frontend-phase-12-b13 — 2026-07-10
|
||||
- **Need:** b13 serves the nurse exactly one endpoint (`GET api/v1/nurse_payouts/history` → `NursePayoutHistoryDto`).
|
||||
@@ -417,7 +417,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
- **Note (money invariants the server owns):** `gross_price_irr = balinyaar_commission_irr + nurse_payout_amount`;
|
||||
`net_amount = gross_earnings − clawback_applied`; a payout's booking-link `payout_amount_irr` sum = its
|
||||
`gross_earnings_irr`; the nurse amount is **payment-method-invariant** (BNPL provider commission never deducted).
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-026 — Review eligibility + my-review-for-booking reads (+ masked author confirmation) — filed by frontend-phase-13-b14 — 2026-07-10
|
||||
- **Need:** Three customer-facing additions the leave-a-review flow renders that b14 does not serve:
|
||||
@@ -437,7 +437,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
reads the shared f8 bookings store for completed-booking eligibility, tracks the submission for the under-review
|
||||
state, and seeds a published list per nurse. The real `reviewsClientApi` maps `getNurseReviews`/`createReview`
|
||||
1:1 and targets the two proposed slugs for the gaps — one config flip when they land.
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-027 — Family-owned care record (medications/routine/tasks) + record access + structured task results — filed by frontend-phase-13-b14 — 2026-07-10
|
||||
- **Need:** The b14 `care_records` GET/POST serve the **nurse-authored visit-note history** (سوابق) — that half
|
||||
@@ -460,7 +460,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
methods target the proposed slugs (REQ-027) and the domain is **mock-primary** (`USE_PATIENT_RECORDS_MOCK = true`)
|
||||
until they land. **Note:** the wireframe's four-tab E2 record is not in the data model — please confirm whether
|
||||
the family-owned record is a real MVP entity or a future addition (the client treats it as forward-looking).
|
||||
- **Status:** open
|
||||
- **Status:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-028 — Ticket inbox enrichment (unread + last-activity), message author name, by-booking lookup, optimistic idempotency — filed by frontend-phase-14-b15 — 2026-07-10
|
||||
- **Need:** Four additions the f14 messaging UI renders that the b15 `TicketSummaryDto`/`TicketThreadDto`/message
|
||||
@@ -492,7 +492,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
optimistic composer render these; the domain is mock-primary precisely because (1)/(3) aren't served and the
|
||||
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
|
||||
- **Status:** delivered in refinement-phase-3 — (1) `unreadCount` + `lastMessageAt` on `TicketSummaryDto` (unread = non-internal messages from others after the caller's `last_read_at`, stamped when the participant fetches the thread; admin queue = 0). (3) `bookingId` query param on `GET /tickets`. (4) optional `clientMessageId` on `POST /tickets/{id}/messages` (deduped, echoed on `PostMessageResult`). (2) **Confirmed:** the role-label approach is intended — no raw identity/name is added (privacy).
|
||||
|
||||
## 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
|
||||
@@ -501,14 +501,14 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
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
|
||||
- **Status:** delivered in refinement-phase-3 — `updatedAt` + `updatedBy` on `PlatformConfigDto` (from the entity's audit fields; falls back to creation).
|
||||
|
||||
## 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
|
||||
- **Status:** delivered in refinement-phase-3 — `GET audit/get_audit_trail` now also filters by `actorId`, `action`, `from`, `to` (all optional; `entityType`/`entityId` are now optional too). **Note:** query params bind camelCase (`actorId`/`from`/`to`), like `pageSize` — not `actor_id`.
|
||||
|
||||
## 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
|
||||
@@ -517,7 +517,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
{ 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
|
||||
- **Status:** deferred in refinement-phase-3 — the RBAC `admin_roles/list|grant|revoke` console. The admin sub-role vocabulary + phone-OTP admins are seeded (refinement-phase-2), but a full grant/revoke management surface is admin-console tooling not on the frontend acceptance path (flagged DEFERRED-IF-MISSING); keep `USE_ADMIN_MOCK` for `/admin/roles`. To deliver: 3 endpoints over `user_roles` (grant/revoke audited) + a `RoleGrant[]` read.
|
||||
|
||||
## 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`
|
||||
@@ -529,7 +529,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" 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
|
||||
- **Status:** partially delivered in refinement-phase-3 — (3) activate/suspend toggle `POST admin/partner-centers/{id}/set-active { isActive }` added; (4) **confirmed** the write-then-masked IBAN contract (PATCH accepts full `settlementIban`; reads return only masked last-4). **Route casing confirmed:** the b15 admin partner-center routes are **kebab-case** (`admin/partner-centers`, `.../set-active`) — an intentional b15 divergence, so the frontend's kebab-case guess is CORRECT (no change needed). **DEFERRED:** (1) `centers/me` + (2) the split portal reads (`centers/me/nurses|bookings|settlement`) — these need the user↔partner-center admin association that REQ-038 deferred; `/partner` stays reachable by direct nav + the partnerCenter mock until that seed + `/me` signal land.
|
||||
|
||||
## 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`
|
||||
@@ -539,7 +539,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
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
|
||||
- **Status:** partially delivered in refinement-phase-3 — `totalIrr` (= platform commission + BNPL commission + VAT) added to `InvoiceDto`. **DEFERRED:** the center-scoped invoice list (depends on the partner portal split reads, REQ-032).
|
||||
|
||||
## 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
|
||||
@@ -552,7 +552,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
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
|
||||
- **Status:** deferred in refinement-phase-3 — verification admin polish (nurse-grouped queue, on-demand signed document URL, explicit whole-verification approve/reject). The per-step admin surface + the transactional `is_verified` flip already exist (b6); these are ergonomic refinements to the admin queue, not on the frontend acceptance path.
|
||||
|
||||
## 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
|
||||
@@ -563,7 +563,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
(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
|
||||
- **Status:** deferred in refinement-phase-3 — refund admin preview + explicit approve/reject (the single `POST admin_refunds` creates+executes today). The customer preview (REQ-020) IS delivered and serves the same decomposition; the admin-side preview/approve/reject split is admin-console tooling.
|
||||
|
||||
## 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
|
||||
@@ -576,7 +576,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
(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
|
||||
- **Status:** deferred in refinement-phase-3 — payout admin single-preview endpoint + `holidayShifted` flag + record-transfer-reference route. The eligible/skipped data is already returned by the batch generate/`GET admin_payouts/eligible`; a consolidated dry-run preview + reconcile-reference write are admin-console refinements.
|
||||
|
||||
## 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
|
||||
@@ -584,6 +584,7 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
|
||||
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:** delivered in refinement-phase-3
|
||||
|
||||
## REQ-038 — Signal on `/me` that the caller administers a partner center (partner auto-routing) — filed by refinement-phase-2 — 2026-07-13
|
||||
- **Need:** add a boolean/id on `MeResult` — e.g. `administersPartnerCenterId: number | null` (or a plain
|
||||
|
||||
Reference in New Issue
Block a user