start of manual testing

This commit is contained in:
hamid
2026-07-27 00:54:22 +03:30
parent 12ce7fa7de
commit bd06ef0016
21 changed files with 2289 additions and 12 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

@@ -0,0 +1,66 @@
![alt text](image.png)
in the login page, the main card has a big border radius number which should be less, and in fact for all papers that should happen
the options under the main paper should move inside the paper and have a better positioning
there is no need for the top bar in the login page,
the language and theme switch also should be only in the settings, not in every top bar in the app,
the icon sets should be totally replaced with a more modern icon set, and the icon mappign should be realted.
the default route should be dynamically deteceted,
i mean now whan i open the app and go to /fa or /en
it stays there and just a loading is displayed to me but it should be infered based on the user role and navigate the user to the right path
and if the
i get this error when i enter the phone number and submit the form
# error start
## Error Type
Console Error
## Error Message
Functions are not valid as a React child. This may happen if you return transformed instead of <transformed /> from render. Or maybe you meant to call this function rather than return it.
<p>{transformed}</p>
at p (<anonymous>:null:null)
at OtpStep (src/components/auth/OtpStep.tsx:103:9)
at LoginFlow (src/components/auth/LoginFlow.tsx:52:9)
at LoginScreen (src/app/[locale]/(public-routes)/login/LoginScreen.tsx:12:7)
at Page (src\app\[locale]\(public-routes)\login\page.tsx:12:10)
## Code Frame
101 | {t('otp_title')}
102 | </Typography>
> 103 | <Typography variant="body2" sx={{ color: 'text.secondary' }}>
| ^
104 | {t.rich('otp_sent_to', {
105 | // <bdi dir="ltr"> isolates the masked number so the RTL sent...
106 | // never reorders the digit/bullet runs around it (the classi...
Next.js version: 16.2.9 (Turbopack)
# Error End
![alt text](image-1.png)
after submitting the phone number the otp input ui needs a better spacing, the first two input are stuck together. this is in fa locale, in the en locale its ok.
# nurse dashboard Start
![whole nurse dashboard page](image-2.png)
![cards](image-3.png)
![alt text](image-4.png)
this dashboard should be totally refactorred,
the ui is kinda old and not a modren and with a good ux,
some text has not proper placing and some of them are too large,
the header and the type of accessing to the dashboard is too old style,
there must not be a header like that, and a side drawer, i modern smooth bottom navbar which have only three options ( as the groups of the drawer items are ) and just a forth item for the support and setting.
so each of the gropus of the side bar should have a root page which handles the links to the sub pages. and in those root pages its better to have a summary of that domain.
two notes:
- icons should be changed till here so i don't mention them again
- ui have much work to do to be acceptable.
there is a horizontal scroll in this page, this should not be like that,
the whole app should be scoped to a mobile size app, i mean if i scretch the chrome responsive mode, the header and the footer should have a maximum width not to strech and fit to the space
no matter what is the device view port, this should be a mobile sized app. all that sidebar in the desktop width is not needed, at least for now, we have to make the app very user friendly with a mobile user mindset
+251
View File
@@ -0,0 +1,251 @@
# Balinyaar — Manual Testing Plan
The flow-by-flow walkthrough for testing the whole product against the **seeded lifecycle demo world**.
Written after the UI/backend/refinement phase chains completed (2026-07-26). Companion docs:
- **Bring-up**: [refinement/RUNBOOK.md](refinement/RUNBOOK.md) — how to boot API + client, OTP login mechanics.
- **Business rules with numbers**: `product/business/` — what "correct" means; the load-bearing numbers are
repeated inline below.
> **How to use this doc:** pick a flow section, log in as the named account, follow the steps, compare
> against *Expected*. Anything marked ⚠ **known gap** is pre-existing and filed (REQ-xxx) — record it as
> confirmation, not as a new bug. Anything else that deviates is a genuine finding.
---
## 1. Environment
| Piece | Where | Notes |
| --- | --- | --- |
| API | `http://localhost:5002` (`cd server && dotnet run --project src/API/Baya.Web.Api/Baya.Web.Api.csproj`) | Boots in Development: migrates + seeds (reference + demo world + **lifecycle world**) against the DB in `appsettings.Development.json` — currently the **remote dev SQL Server** (`87.107.152.16`). Swagger at `/swagger`. |
| Client | `http://localhost:3000` (`cd client && npm run dev`) | `.env.development` already points at `http://localhost:5002`. |
| Crypto keys | `dotnet user-secrets` (from `server/src/API/Baya.Web.Api`) | The committed config carries `SET_VIA_USER_SECRETS_OR_ENV` placeholders. The remote DB's data is encrypted under the **dev keys** — any machine booting against it must set the same four user-secrets: `IdentitySettings:SecretKey` = `dev-only-jwe-signing-key-not-for-production-0123456789abcdef`, `IdentitySettings:Encryptkey` = `dev-only-16bytes`, `Seams:FieldEncryption:Key` = `local-dev-field-encryption-key-not-for-production`, `Seams:FieldEncryption:HashKey` = `local-dev-field-hash-key-not-for-production`. Booting with *different* field keys makes every phone lookup miss and every PII read throw `Padding is invalid`. |
| OTP codes | server console (`MOCK SMS — OTP code …`) or `GET /api/v1/dev/last_otp/{phone}` | Resend window 120 s, 5 wrong attempts per code, OTP valid 60 s. The OTP endpoints are rate-limited per IP — hammering logins in scripts will 429. |
| Reset | drop the `Baya` DB (`dotnet ef database drop --force --project src/Infrastructure/Baya.Infrastructure.Persistence --startup-project src/API/Baya.Web.Api`), reboot | Everything reseeds. Needed when the **time-relative scenarios age out** (see §3 note). |
---
## 2. Test accounts
All log in via phone-OTP at `/login`. Any listed account works immediately.
| Phone | Actor | Who | Carries |
| --- | --- | --- | --- |
| `09120000001` | nurse (verified) | زهرا عزیزی | 4 variants (incl. the 5-session package), whole-city+2-district coverage, ★5.00 (1 published review), 3 completed bookings, a pending request in the inbox, the in-progress visit today, earnings incl. a **paid** payout and a **pending clawback** |
| `09120000002` | nurse (verified) | علی کریمی | Partner-sponsored (مرکز پرستاری آرامش), 2 completed bookings (one BNPL), a **draft** payout waiting, a hidden 1★ review, an expired request |
| `09120000003` | nurse (unverified) | مریم احمدی | Mid-pipeline verification (KYC+Shahkar passed, MoH license in review w/ document, criminal record pending) — **never searchable** |
| `09120000010` | customer | سارا محمدی | 2 patients, 1 address, 6 bookings across all states, pending/accepted/rejected requests, tickets, notifications, care records |
| `09120000011` | customer | رضا حسینی | 1 infant patient, 2 completed bookings (one BNPL w/ processing refund), expired + cancelled requests, a closed support ticket |
| `09120000020` | admin (`super_admin`) | نگار مدیری | Full `/admin` console incl. RBAC |
| `09120000021` | admin (`finance`) | کامران مالی | `/admin` scoped to money consoles (`useAdminCapabilities`) |
| `09120000030` | partner owner | بهنام رستگار | Owns the merchant-of-record center; **navigate to `/partner` manually** after login (⚠ REQ-038 — no `/me` partner signal) |
| any new `09xxxxxxxxx` | fresh user | — | Registers on first OTP verify → `/select-role` → onboarding. Use for first-run testing. |
---
## 3. The seeded world at a glance
Booking scenarios (all Tehran; seed-time-relative — **T0 = the boot that first seeded**):
| Key | Who | State | Money / attachments |
| --- | --- | --- | --- |
| pending request | محمدی → عزیزی | `pending_nurse_response`, 24 h countdown | nurse-inbox + C5 tracker fodder |
| accepted request | محمدی → عزیزی | `accepted_awaiting_payment` (24 h demo window, not the real 30 min) | checkout entry; **1 failed card attempt** (wallet history) |
| rejected / expired / cancelled requests | mixed | terminal request states | C5 terminal cards + inbox tabs |
| B1 `upcoming` | محمدی × عزیزی | confirmed, scheduled T0+3d, care instructions written | paid (card), invoice issued, coordination ticket |
| B2 `in_progress` | محمدی × عزیزی | 5-session package: 2 done, **session 3 checked-in now**, 2 scheduled | paid, emergency ticket logged |
| B3 `completed_in_window` | محمدی × عزیزی | completed T01d, dispute window open until T0+2d | review **pending moderation**, care record |
| B4 `completed_paid` | محمدی × عزیزی | completed T010d, **paid out** | ★5 **published** review (punctual/professional), care record |
| B5 `completed_eligible` | حسینی × کریمی | completed T05d, in the **draft batch** | hidden 1★ review, **out-of-range EVV** (1220 m) |
| B6 `bnpl_settled` | حسینی × کریمی | completed T06d, paid via SnappPay (net-of-fee) | **processing `bnpl_revert` 50% refund** (ETA ~10 business days), excluded from payouts, care record |
| B7 `cancelled_refunded` | محمدی × عزیزی | cancelled ≥24 h ahead (standard_24h, 100%) | **succeeded card refund** |
| C8 `clawback` | محمدی × عزیزی | completed T011d, paid out, then fully refunded | **pending nurse clawback**, support alert |
Plus: 9+ tickets (coordination per booking, 3 refund tickets, open support w/ an **internal admin note**,
closed support, emergency), notifications for every persona (mixed read/unread), 4 support alerts
(low-rating / EVV-mismatch / clawback / emergency), a paid + a draft payout batch, invoices for all 8
bookings (کریمی's resolve to the partner center as merchant-of-record).
> **Time decay:** the world is date-relative and ages. After ~24 h the pending request expires (the sweep
> runs every minute); after ~2 days B3's dispute window closes and the "review-eligible + in-window" state
> is gone; the accepted request's payment window lasts 24 h. **To refresh the timeline: drop the DB and
> reboot** (seeder guards make an in-place re-run a no-op, not a re-date).
---
## 4. Mock-vs-real map (critical for honest testing)
15 of 22 client domains hit the real API. **7 still run on in-browser mocks** (`USE_*_MOCK = true` in
`client/src/services/{domain}/constants.ts`) because a blocking backend REQ is deferred. On those screens
the UI shows **mock data regardless of the seeded DB** — test the UI/UX there, and verify the *server*
data through Swagger instead.
| Mocked domain | Screens affected | Server data still verifiable via |
| --- | --- | --- |
| `verification` | nurse `/nurse/verification/*` journey, admin `/admin/verification` queue | `GET nurse_verification/status` (nurse token), Swagger |
| `refunds` | customer cancel flow + `/bookings/[id]/refund_status`, wallet «استردادها» | `GET /api/v1/refunds/by_booking/{id}`, `GET /api/v1/admin_refunds` |
| `payouts` | nurse `/nurse/earnings*`, admin `/admin/payouts` | `GET /api/v1/nurse_payouts/earnings_balance|history`, `GET /api/v1/admin_payouts/batches` |
| `admin` | `/admin/config|holidays|audit|alerts|roles|users` | b1 admin endpoints in Swagger |
| `bnpl` | the whole D1D5 BNPL checkout + wallet «اقساط» | `GET /api/v1/admin_bnpl/{id}` |
| `partnerCenter` | `/partner/*` portal + `/admin/partners` | `GET /api/v1/admin/partner-centers` |
| `patientRecords` | E2 family care record editor + nurse visit-note panel | `GET /api/v1/patients/{id}/care_records` |
**Real domains** (UI = server truth): auth, geography, patients, profiles, nurse-bank, addresses,
serviceAreas, catalog, search, bookingRequests, bookings, payment, reviews (incl. **admin moderation**),
tickets (incl. **admin ticket console**), notifications.
---
## 5. Flow walkthroughs
### 5.1 Auth & first-run (real)
| # | Steps | Expected |
| --- | --- | --- |
| A1 | `/login` → fresh phone → request code → wrong code ×5 | Refused after 5 attempts until a fresh code; resend locked 120 s; no reveal whether the phone exists |
| A2 | Fresh phone, correct code | → `/select-role` (no roles yet) → pick خانواده → `/onboarding` wizard (relation → first patient) → customer home |
| A3 | Same phone again later | Straight to customer home (role remembered) |
| A4 | Nurse `09120000001` login | Routed to `/nurse` dashboard (never a flash of the customer shell) |
| A5 | Admin `09120000020` vs `09120000021` | Both land `/admin`; finance sees **only** money consoles in the sidebar |
| A6 | Deep link while logged out (e.g. `/bookings`) | → `/login?next=/bookings` → after login lands back on `/bookings` |
| A7 | Logged out, open `/` | Public landing (`/welcome` content, URL stays `/`) — ⚠ verify via `npm run build && npm start` (dev-server root-path quirk, ui-phase-13) |
### 5.2 Customer — discovery & booking request (real)
Login: `09120000010`.
| # | Steps | Expected |
| --- | --- | --- |
| C1 | Home → search entry → category سالمند, region Tehran/whole city | Live count CTA > 0; unverified مریم احمدی **never** appears in any result |
| C2 | Results | عزیزی shows ★5.00 (1 نظر), 3 visits, tappable verified badge; district-3 search still shows her whole-city rows |
| C3 | Gender filter مرد | Only کریمی remains |
| C4 | Open عزیزی's profile | Trust dossier: badge → verification panel (credential **types only**, never numbers); services/prices tab; «نظرات» tab shows exactly **1** published review with tags — the pending + hidden ones never |
| C5 | «درخواست رزرو» → C4 form: patient حسن, address, tomorrow, morning window → submit | Request created; C5 tracker shows a **24 h** countdown ring |
| C6 | As عزیزی (second browser/profile): `/nurse/requests` | New request at top with urgency countdown; detail shows **only** customer notes + coarse city/district (⚠ stage-1 masked address) |
| C7 | Accept it | Customer C5 flips to accepted + **30-minute** payment window countdown (real window — the seeded one is a 24 h demo exception) |
| C8 | Reject another (with reason) | C5 terminal card + «درخواست دوباره» / «پرستاران مشابه» off-ramps |
### 5.3 Customer — checkout & payment (real contract, mock PSP)
| # | Steps | Expected |
| --- | --- | --- |
| P1 | C5 of the seeded accepted request → «پرداخت» → C6 | Nurse identity + `<Money>` total (variant price), reconciling breakdown, escrow explainer. ⚠ REQ-046: avatar/badge enrichment may be absent on the real path |
| P2 | «ادامه پرداخت» (card) | Initiate succeeds → browser redirects to `https://mock-psp.local/...` — a **dead page. Expected**: the mock PSP has no UI (real E2E completion needs the Phase-8 real PSP config). |
| P3 | To actually complete a payment: Swagger → `POST /api/v1/bookings/convert` body `{"bookingRequestId": <id>}` with the **customer's** bearer token (Dev-only capture simulator) | Booking appears under «رزروها» as confirmed; coordination ticket auto-opens; invoice issued; nurse gets a notification |
| P4 | Wallet «پرداخت‌ها» | ⚠ REQ-047: **empty on the real path** (no transactions-list endpoint). The seeded failed+succeeded transactions are visible in DB/Swagger only |
| P5 | BNPL branch (D1D5) | ⚠ Whole flow is client-**mock** (REQ-022/024); `/bookings/checkout/bnpl/gateway` only exists under `npm run dev`. Server-side BNPL truth: `admin_bnpl` via Swagger (B6 is `reverted`) |
### 5.4 Customer — bookings lifecycle (real)
| # | Steps | Expected |
| --- | --- | --- |
| L1 | `/bookings` tabs | «در انتظار پاسخ»: pending request w/ countdown · «فعال»: B1, B2 · «گذشته»: B3, B4, B7, C8 |
| L2 | B1 (upcoming) detail | Status timeline at تایید شده; next-session headline T0+3d; `.ics` download; address card |
| L3 | B2 (package) detail | 5 sessions listed: 2 completed, 1 **در حال ویزیت** (presence headline), 2 scheduled |
| L4 | B3 review CTA | Star strip on the completed row → review form (context recap + moderation note) — but B3 already carries a pending review, so expect the **"under review"** state, never a second form |
| L5 | B4 | «مشاهده نظر» shows the published ★5 review state |
| L6 | B1 → لغو رزرو | Off-ramps first; tier disclosure: **≥48 h → 100%، ≥24 h → 50%، <24 h → 0%** (server tiers) — ⚠ the UI copy states a single 24 h boundary (REQ-065 divergence; record the exact numbers shown). ⚠ the actual cancel + refund-status screens run on the **mock** refunds domain — server truth via Swagger |
| L7 | B7 → وضعیت استرداد | ⚠ mock domain: UI shows mock stages. Server truth: refund `succeeded`, channel `psp_card` (`GET refunds/by_booking/{B7}`) |
| L8 | `/bookings/[B1]/invoice` | Real invoice: sequential number, VAT = 10% **on the commission line only**, مودیان state `pending`. ⚠ REQ-049: payment-method/reference/seller-fiscal block may be absent |
### 5.5 Customer — account, care circle, tickets, notifications
| # | Steps | Expected |
| --- | --- | --- |
| E1 | `/patients` («حلقهٔ مراقبت») | حسن + فاطمه cards; add/edit/archive (real); tap → E2 record |
| E2 | `/patients/[حسن]/record` | ⚠ patientRecords domain is **mock**: meds/routine/tasks + the nurse visit-note history shown are mock data (the 2 real seeded notes are server-side only). Access-denied state testable with the mock's foreign-patient id 8888 |
| E3 | `/addresses` | Real CRUD; map is the canvas stand-in unless `NEXT_PUBLIC_NESHAN_KEY` is set |
| E4 | `/profile` | Identity header (server-masked phone), personal-info edit, language row, emergency-contact card; avatar upload round-trips |
| E5 | `/support/tickets` | Real inbox: refund tickets (`TKT-DEMORF0x`), open support `TKT-DEMOSUP1`, coordination tickets; thread of `TKT-DEMOSUP1` shows customer msg + admin reply + follow-up — **the internal admin note must never appear** |
| E6 | Send a message; send another containing `/fail` | Normal send lands; ⚠ `/fail` sentinel only drives the mock — on the real path it just sends |
| E7 | `/notifications` | Seeded rows, unread-first, day-grouped; mark-read flips the bell count. ⚠ **Notification titles/bodies are English** — server-rendered copy from the real handlers (finding F-4 §7) |
### 5.6 Nurse — daily ops (real except earnings)
Login: `09120000001`.
| # | Steps | Expected |
| --- | --- | --- |
| N1 | `/nurse` dashboard | Next-visit card (B2 today), requests strip (pending w/ countdown), earnings snapshot (⚠ mock numbers — payouts domain), activation checklist collapsed to «فعال در جستجو» |
| N2 | `/nurse/visits` | Today's feed shows B2 session 3 **checked-in** → the check-out CTA is the hero action |
| N3 | Check out (confirm step) | Session completes; EVV panel updates. GPS: set `NEXT_PUBLIC_EVV_MOCK_GPS=in_range` in `client/.env.local` to force a passing location, else real geolocation runs (out-of-tolerance is **advisory** — banner + staff alert, never a block). Completing the **last** session would complete the booking and start its 72 h dispute clock |
| N4 | `/nurse/visits/[B2]` | Address card + map link (⚠ REQ-051: address may stay masked w/ quiet fallback note), gated care card (care instructions **readable** post-confirmation), visit-note composer (⚠ mock — patientRecords) |
| N5 | `/nurse/requests` | Tabs: pending (live countdown) / answered / expired. Accept behind confirm dialog → opens the payment window |
| N6 | `/nurse/earnings` + `/payouts` | ⚠ **Mock domain** — UI shows mock buckets. Server truth (Swagger, nurse token): `earnings_balance` = signed ledger sum (عزیزی: B1+B2+B3 payouts pending — B7 reversed, B4/C8 paid out), `history` shows the **paid** payout w/ masked IBAN |
| N7 | `/nurse/services` | 4 offerings incl. the package variant; edit/deactivate; the accepting-bookings toggle is real (pausing → disappears from search) |
| N8 | `/nurse/coverage` | Whole-city + districts 1&3; duplicate add → 409 message |
| N9 | `/nurse/bank` | Verified account, masked IBAN, ownership state «تأیید شده» |
| N10 | As کریمی (`09120000002`) | Draft-batch earnings waiting; B6's payout share reversed by the 50% refund; hidden review does **not** appear on his public profile (0 reviews) |
| N11 | As احمدی (`09120000003`) | Activation checklist far from complete; `/nurse/verification` — ⚠ **mock domain**: the journey UI shows mock state; the real mid-pipeline case (KYC ✓, Shahkar ✓, license in-review, criminal pending) is server-side (`nurse_verification/status` via Swagger). She must never appear in search |
### 5.7 Admin console
Login: `09120000020` (all consoles) and `09120000021` (money only).
| # | Console | Real/Mock | What the seeded world provides (server-side) |
| --- | --- | --- | --- |
| AD1 | `/admin/reviews` moderation queue | **Real** | B3's pending review — publish it → عزیزی's public aggregate recomputes (★ count 2); hide/reject paths; the hidden 1★ shows the hide flow already happened |
| AD2 | `/admin/tickets` | **Real** | Full queue incl. emergency (red) + refund tickets; thread of `TKT-DEMOSUP1` **shows** the internal note distinctly; composer's internal-note mode goes amber |
| AD3 | `/admin/verification` | ⚠ Mock | Real queue data (احمدی in review + document metadata) via Swagger `admin_verifications`; the document's signed-URL fetch 404s (no real bytes — expected) |
| AD4 | `/admin/payouts` | ⚠ Mock | Real: `admin_payouts/batches` shows the **completed** batch (2 links) + the **draft** batch; `batches/{id}/process` on the draft is the demoable money-out action; `eligible` preview |
| AD5 | Refunds (via ticket RefundPanel) | ⚠ Mock | Real: `admin_refunds` lists 3 refunds; `{id}/confirm_settlement` on the **processing BNPL** refund is the demoable action (posts the clearing leg) |
| AD6 | `/admin/alerts` | ⚠ Mock | Real: 4 seeded alerts (low_rating / evv_location_mismatch / nurse_clawback / emergency) via `support_alerts` endpoints |
| AD7 | `/admin/config`, `/admin/holidays`, `/admin/audit`, `/admin/users`, `/admin/roles` | ⚠ Mock | Real: b1 endpoints (config list incl. the §6 numbers, audit trail rows for every seeded money/trust entity — actor `null` = system) |
| AD8 | `/admin/partners` | ⚠ Mock | Real: `admin/partner-centers` shows مرکز پرستاری آرامش (MoR, verified, masked IBAN), کریمی sponsored |
### 5.8 Partner portal (⚠ mock — REQ-032/033/038)
Login `09120000030` → navigate to `/partner` manually. UI runs on mock center data; the real center +
MoR invoice resolution (کریمی's two invoices carry `issuing_entity_type = partner_center`) is verifiable
via Swagger. Test the portal chrome, the MoR settlement view, and the CSV export against mock data.
---
## 6. The numbers the UI must respect
From seeded `platform_configs` (admins can change them; rates are **snapshotted** — a change never
re-prices an existing booking/invoice/deadline):
| Rule | Value |
| --- | --- |
| Nurse response deadline | **24 h** (frozen per request) |
| Payment window after accept | **30 min** (frozen per request) |
| Dispute window after completion | **72 h** → then payout-eligible |
| Platform commission | **15%** of gross (`gross = commission + payout`, always) |
| VAT | **10%**, on the **commission line only** |
| Cancellation tiers | ≥48 h → 100% · ≥24 h → 50% · <24 h → 0% (⚠ client copy says a single 24 h boundary — REQ-065) |
| BNPL provider fee | **7%** — a **platform expense**; the nurse payout is payment-method-invariant |
| BNPL refund ETA | ~**10 business days** (Fridays skipped); UI copy says 710 |
| EVV tolerance | **200 m**, advisory only |
| No-show threshold | **60 min** after scheduled start |
| Payout cadence | weekly generation (auto, draft); **processing stays a manual admin action** |
| Review alert | rating ≤ **2** raises a staff alert |
| OTP | resend 120 s · 5 attempts · code lives 60 s · session 30 d · access token 60 min |
---
## 7. Findings from this bring-up (decide / track)
Recorded while building the seed — each needs an owner decision:
| # | Finding | State |
| --- | --- | --- |
| F-1 | **Committed real DB credential**: `appsettings.Development.json` ships the remote server's SQL login in git (the exact thing refinement-phase-5 removed; the pre-commit hook that blocks it isn't enabled on this clone). Recommendation: move the connection strings to user-secrets like the crypto keys and restore placeholders. | **Open — decision needed** |
| F-2 | **`/me` hardcoded `hasCustomerProfile`/`hasNurseProfile`/`nurseVerificationStatus`** to `false`/`not_started` for everyone (broke the customer home profile nudge + profile-hook invalidations). | **Fixed** this session (snapshot projection + `ToMeResult`) |
| F-3 | **Stored Persian text is normalized destructively**: an `ApplicationDbContext` save hook runs `Fa2En().FixPersianChars()` over every string property — Persian digits become ASCII and **ZWNJ becomes a space** in everything persisted (e.g. «شبانه‌روزی» → «شبانه روزی»), contradicting the client's STYLE.md ZWNJ rules. Any Persian-literal equality against stored data silently misses. | **Open — decision needed** (legacy starter behavior; removing it changes stored data shape) |
| F-4 | **Notification copy is English on the real path** — the b-phase handlers write `"Booking confirmed"`-style titles/bodies straight into `ops.Notifications`; the Persian UI renders them verbatim. | **Open — decision needed** (server-side i18n or client-side type→copy mapping) |
| F-5 | Mock PSP redirect goes to a dead host (`mock-psp.local`) — in-browser card completion impossible until a real PSP is configured (`Payments:Provider=zarinpal`); the Dev `bookings/convert` affordance is the workaround (§5.3 P3). | By design (refinement-phase-8 rails exist behind config) |
| F-6 | 7 client domains still mocked (§4) — the biggest lever for "test everything for real" is flipping `verification`, `refunds`, `payouts` (user halves are contract-ready; the blocking REQs are admin-side). Flipping a shared flag turns the admin half's screens into real-API screens against missing endpoints. | **Open — decision needed** (split flags per half, or deliver the admin REQs) |
| F-7 | Seeded object-storage keys (verification document, invoice PDFs) have no real bytes — signed-URL fetches 404 in admin viewers. | Accepted for dev (never fake bytes) |
---
## 8. Suggested test order
1. **Auth & routing** (§5.1) — everything depends on it.
2. **Customer discovery → request → accept → convert → booking** (§5.25.4) — the core funnel, all real.
3. **Nurse ops** (§5.6) — inbox/EVV against the same bookings.
4. **Reviews + tickets + notifications** (§5.4 L4/L5, §5.5 E5E7) — real, seeded both sides.
5. **Admin real consoles** (§5.7 AD1/AD2) — moderation + tickets.
6. **Mock-domain UI passes** (§5.3 P5, §5.5 E2, §5.6 N6/N11, §5.7 AD3AD8, §5.8) — UX only, verify server truth via Swagger as listed.
7. Sweep §7's decisions.
+10
View File
@@ -86,6 +86,15 @@ demo nurses with priced variants + Tehran coverage (and therefore real `nurse_se
customers with patients and addresses. The console logs `Demo world seeded: 3 nurse(s), 2 customer(s)…` (or
`already seeded — no-op` on a subsequent run). It is **idempotent** and **never runs outside Development**.
On top of that, the **lifecycle seeder** (`DemoLifecycleSeeder`) populates every flow's mid-state so manual
testing never starts from an empty world: booking requests in every status, 8 bookings across every reachable
state (incl. a 5-session package mid-engagement and a cancelled-and-refunded one), the balanced ledger, three
refunds (card-succeeded / BNPL-processing / post-payout clawback), a **paid** and a **draft** payout batch,
reviews in all moderation states, tickets, notifications, patient care records, a merchant-of-record partner
center, and a mid-pipeline verification case. The console logs `Demo lifecycle seeded: …` (or `already
seeded — no-op`). The full scenario map + per-flow walkthroughs live in
[`dev/post-phase/manual-testing-plan.md`](../manual-testing-plan.md).
### Terminal 2 — frontend (from `client/`)
```bash
@@ -114,6 +123,7 @@ endpoint works). Use them to see the real path populated:
| `09120000011` | customer | رضا حسینی (male) | 1 patient, 1 Tehran address |
| `09120000020` | admin (`super_admin`) | نگار مدیری (female) | full backoffice — **lands on `/admin`**, sees every console incl. RBAC |
| `09120000021` | admin (`finance`) | کامران مالی (male) | scoped backoffice — lands on `/admin`, sidebar shows only the money consoles (`useAdminCapabilities` gating) |
| `09120000030` | partner-center owner | بهنام رستگار (male) | owns مرکز پرستاری آرامش (merchant-of-record, sponsors علی کریمی). No admin/nurse role — log in, then navigate to `/partner` manually (REQ-038: no `/me` partner signal yet) |
> The old username+password `admin`/`qw123321` account is **no longer auto-seeded** (refinement-phase-5 —
> no committed credential). To bootstrap a break-glass username+password admin, set both secrets before boot,