# UI phases — giving Balinyaar the interface its product deserves **Created:** 2026-07-16 · **Scope:** `client/` only (frontend track) · **Method:** a 15-agent parallel design audit over every UI surface of the client (theme/tokens, shells, component primitives, feature widgets, auth, storefront, booking, checkout/money, account, nurse workspace, nurse trust/ops, admin/partner, messaging/notifications, cross-cutting UX patterns, fa/en microcopy). The full per-area findings — with file/line evidence — live in [`audit/`](audit/). This directory is a **runnable chain of 14 UI phases** (0–13) that takes the client from *"feature-complete but visually a default-MUI starter"* to *"a designed, branded, Persian-native product."* The functionality is already there — this chain is about **look, feel, hierarchy, trust presentation, mobile/RTL/Persian nativeness, and the UX defects the audit surfaced along the way.** Run the phases **in order, one at a time**, pointing a fresh agent at one phase file (*"Execute `dev/post-phase/ui/ui-phase-0-design-language.md` end to end"*). After phases 0–2, most later phases touch disjoint route trees and can be parallelized if you accept some risk; the recommended path is sequential. > **Relation to the other chains.** The [refinement chain](../refinement/README.md) made the app *work* as one > integrated system (it is complete). This chain makes it *feel* like a product. It deliberately does **not** > touch `server/` — where a UI improvement needs a backend change, the phase files a REQ in > [`for-backend.md`](../../shared-working-context/frontend/requests/for-backend.md) and builds mock-tolerant > UI behind the existing `services/{domain}` seams (REQ-001…038 are taken; number onward from there). --- ## What is already good (do not regress it) The audit found the feature layer unusually disciplined. Every phase must preserve: 1. **Token discipline** — 331 `var(--bal-*)` usages across 103 files, effectively **zero hard-coded hexes** in feature code. The two-layer token system (`tokens.css` ↔ `colors.ts`) works; extend it, never bypass it. 2. **The four-state data pattern** — skeleton → error-with-retry → empty → data is genuinely implemented on most feature pages (search results, earnings, verification, tickets…). The gaps are enumerated per phase. 3. **RTL as a habit** — logical properties (`borderInlineStart`, `textAlign: 'start'`, `marginInline*`), deliberate `dir="ltr"` islands for phone numbers/IBANs/clocks, RTL-mirrored message bubbles. 4. **Persian correctness plumbing** — `utils/money.ts` (BigInt IRR, Toman-at-the-boundary, fa digit grouping), `utils/date.ts` (Shamsi via `Intl` `fa-IR-u-ca-persian`), locale digits in counts and pagers. 5. **Product-honesty components** — `EscrowNotice` (product-mandated verbatim copy), `RefundEtaBanner`'s honest BNPL 7–10-day window, `TrustBadge`'s three honest states, EVV's advisory-never-blocking semantics, the two-stage clinical/address disclosure gates, negative-balance "owed back" rendering. 6. **The architecture seams design work needs** — the `AppIcon` string registry (one-file icon swap), the per-actor shell split (`CustomerLayout`/`NurseLayout`/`AdminLayout`/`PartnerLayout`), component defaults in `components/config.ts`, the `services/{domain}` mock seams, the admin composite layer (`AdminDataTable`/`ConfirmDialog`/…), optimistic ticket send with `clientMessageId` reconciliation. 7. **Copy that is already right** — the escrow/payout/refund explainers, the culturally-tuned gender copy, the formal-شما register, specific actionable verification-failure reasons. --- ## What is actually wrong (the problem inventory) Every item is verified in code; file/line evidence is in [`audit/`](audit/) and repeated in the phase files. ### A. The starter is still the face of the app - `createTheme` has **zero `components` overrides** (`theme/theme.ts`) — every Button/Card/TextField/AppBar/ Chip/Dialog/Stepper renders stock Material with recolored primaries. This alone is most of the "old MUI beginner example" feel. - The **brand logo is the starter's Twemoji cartoon pencil** (`AppIcon/icons/PencilIcon.tsx`), rendered at 56px on the auth screens and in every top bar. The seed-deck mark (deep-teal square, cream glyph, terracotta dot) was never built. - The nurse/admin/partner chrome is the untouched starter shell: solid-primary fixed `TopBar` with a static centered label, flat 10-item sidebar whose **active highlight never fires** (locale-prefix bug in `SideBarNavItem`), a permanent `UserInfo` placeholder ("Current User" / "Loading..." in English), physical `paddingLeft/Right` RTL hazards, and a desktop SSR mobile-first flash. - The login page — the only front door — is wrapped in starter dashboard chrome titled **"Unauthorized - Balinyaar"** in English; `ErrorBoundary` is unstyled English with a raw stack dump; `globals.css` is the starter reset; `light.ts`/`dark.ts` are dead starter themes still exported. ### B. The design system is missing a layer - MUI palette has **no success/error/warning/info**, so inline alerts show stock MUI green/red while toasts show brand `--bal-*` colors — two feedback systems for one semantic state. - **Persian typography is Roboto metrics**: non-zero letter-spacing on a joined script, tight heading line-heights that clip Persian ascenders, requested weight 600 that Mikhak doesn't load (renders 700), an EN brand font declared but never wired. - Tokens cover **color only** — no elevation/shadow (grey MUI shadows on warm cream), radius scale, motion, or focus-ring tokens; exactly **one** `:focus-visible` style exists in the whole app. - The icon registry mixes filled/outlined generations, has **no back/chevron icon at all**, and `AppIcon`'s `size` prop is silently broken for MUI icons. `AppButton` ships a starter `margin: 1` default that 213 call-sites in 82 files neutralize with `sx={{ m: 0 }}`. - Missing primitives pages keep hand-rolling: EmptyState/ErrorState (29 dashed-Paper copies in 23 files), PageHeader, Money display, card anatomy (~12 hand-rolled Paper recipes), skeleton twins, relative time, a `formatNumber` helper (the `fa-IR` ternary is copy-pasted 25+ times) — and **no Jalali date picker**, so every date input in a Shamsi-displaying product is a native Gregorian `type="date"`. - No route-level `loading.tsx`/`error.tsx`/`not-found.tsx` anywhere; one static `` for ~60 routes. ### C. Trust surfaces undersell the product Trust *is* the product, and the UI treats it generically: a bare login card with no trust presence; a static ✓ chip that never explains **what** was verified; a checkout whose total is a `subtitle2` row; a payment confirmation with **no reference code**; a nurse verification journey with two competing progress metaphors; a nurse public profile that doesn't answer "would I let this person into my mother's home?". ### D. Real UX defects found along the way (fixed by their area's phase) The audit found genuine bugs beyond styling — the worst: a cancel-request dialog whose **dismiss button is labeled with the destructive action**; the error→false-empty pattern (a failed query renders "you have no patients/services/requests"); **no route to a customer's pending requests** (`useCustomerRequests` is wired to nothing); **no sign-out anywhere in the customer shell**; `PublishGate`'s **fake success snackbar**; bookings list unpaginated (booking #21 unreachable); the nurse day-of flow has **no address, no contact, no navigation affordance**; `DocumentUpload`'s rejected-state re-upload shows no progress; partner booking statuses render as raw English `snake_case`; admin actions target users by hand-typed numeric ID. ### E. Mobile-native and Persian-native gaps No safe-area handling under the customer/nurse bottom navs; OTP inputs without `autocomplete="one-time-code"` / WebOTP in an OTP-first market; Gregorian date pickers everywhere; Latin digits in timers; fa catalog missing ICU plural/zero forms («مشاهده ۰ پرستار»); desktop rendered as an 800px phone column with a mobile tab bar. ### F. Copy defects on trust-critical strings The brand name is spelled two ways («بالین یار» vs «بالین‌یار»); تأیید appears with and without hamza (63 occurrences, both forms); grammar bugs sit on nurse-facing EVV errors and customer address hints; BNPL copy uses banker's jargon (نکول) and one sentence states the **inverse** of the intended risk allocation; policy numbers (72h dispute window, cancellation tiers) are hard-coded into copy the admin config can change. --- ## The 14 UI phases Phases 0–2 build the foundation everything else composes from. Phases 3–11 are area redesigns over disjoint route trees. Phase 12 is the closing sweep; phase 13 is optional and product-gated. | # | Phase | Delivers | Depends on | | --- | --- | --- | --- | | **0** | [Design language & theme foundation](ui-phase-0-design-language.md) | brand mark, `theme.components` pass, semantic palette, Persian type scale, one icon family, token extension (elevation/motion/focus/rating/trust/money), starter purge | — | | **1** | [Shared primitives & app-wide states](ui-phase-1-primitives-and-states.md) | EmptyState/ErrorState kit (+ error→false-empty fixes), PageHeader, card kit, `<Money>`, Jalali date picker, StatusChip v2, StatusTimeline, CountdownTimer v2, RatingInput v2, skeleton twins, route-level loading/error/404, per-route metadata, formatting utils | 0 | | **2** | [Shells & navigation](ui-phase-2-shells-and-navigation.md) | locale-aware nav (`createNavigation`), contextual customer header + safe-area bottom bar, grouped nurse sidebar + nurse bottom nav + identity card, dense admin chrome, de-startered public shell, sign-out / role / locale switchers | 0, 1 | | **3** | [Auth & first-run](ui-phase-3-auth-and-first-run.md) | trust-forward login hero, OTP autofill (WebOTP), terms/privacy consent + pages, illustrated select-role, focused onboarding wizard, returnUrl | 0–2 | | **4** | [Customer storefront](ui-phase-4-customer-storefront.md) | home that sells, Shamsi date filter, sticky search CTA, honest results header + NurseResultCard v2, nurse profile as trust dossier + verification explainer | 0–2 | | **5** | [Booking lifecycle](ui-phase-5-booking-lifecycle.md) | C4 trust-anchored request form, C5 countdown ring + recovery, customer requests tabs on /bookings, booking-detail hero + vertical timeline, cancel-flow fixes, review context | 0–2 (4 recommended) | | **6** | [Checkout & money](ui-phase-6-checkout-and-money.md) | checkout hierarchy + sticky pay bar, receipt-grade confirmation, wallet as money hub, honest BNPL comparison, fiscal-grade invoice, designed wait states | 0–2 (5 recommended) | | **7** | [Nurse daily ops](ui-phase-7-nurse-daily-ops.md) | the real nurse dashboard, visit workspace (address/contact/EVV-first), decision-first request inbox + urgency system, earnings clarity | 0–2 | | **8** | [Nurse business & verification](ui-phase-8-nurse-business-and-verification.md) | activation checklist (honest PublishGate), unified verification journey, DocumentUpload fixes, variant-builder preview, coverage viz, bank flows, public-profile preview | 0–2 (4 for trust components) | | **9** | [Customer account & care circle](ui-phase-9-customer-account-and-care-circle.md) | profile as account hub (+ sign-out entry), care-circle reframe with avatars, per-item care-record editing, real map picker, mobile full-screen forms | 0–2 | | **10** | [Messaging & notifications](ui-phase-10-messaging-and-notifications.md) | chat-grade ticket threads (live, scrolled, grouped), inbox pagination/filters, right-sized emergency affordance, notification center grouping + bell popover | 0–2 | | **11** | [Admin & partner console](ui-phase-11-admin-and-partner-console.md) | URL-synced list state, user/nurse pickers (no raw IDs), verification desk, ticket console lifecycle, AdminDataTable v2, Jalali inputs, partner localization | 0–2 | | **12** | [Copy, motion & final polish](ui-phase-12-copy-motion-and-polish.md) | Persian style guide + catalog sweep, ICU plurals, trust-moments copy, config-served policy numbers (REQ), motion pass, a11y sweep, 4-axes QA | all prior | | **13** | [Public front door](ui-phase-13-public-front-door.md) *(optional)* | public landing, how-it-works, SEO/metadata/OG, guest-browse decision (+ public-endpoint REQs) | 0–2 · product decision | ### Dependency & sequencing ``` Foundation (strictly in order): 0 design language ──► 1 primitives & states ──► 2 shells & navigation Area redesigns (after 0–2; sequential recommended, parallel possible across disjoint trees): 3 auth/first-run 4 storefront ──► 5 booking ──► 6 checkout/money (the customer funnel, in funnel order) 4 ──────────────► 8 nurse business & verification (reuses phase 4's trust components) 7 nurse daily ops 9 customer account · 10 messaging/notifications · 11 admin/partner Closing: 12 copy, motion & polish (last — sweeps everything the earlier phases touched) 13 public front door (any time after 0–2; needs a product decision on guest browse) ``` **Ownership rules that keep parallel runs safe:** phase 0 owns `theme/`, `AppIcon`, `AppButton`, the brand mark; phase 1 owns every *shared* primitive (`StatusChip`, `CountdownTimer`, `RatingInput`, `StepperHeader` usage, state views, `<Money>`, the Jalali picker); phase 2 owns `layout/`. Later phases **consume** these and own only their route tree plus the feature components that belong to it (e.g. `NurseResultCard` → 4, `BookingRequestSummaryCard` → 5, messaging composites → 10). If a later phase finds a foundation gap, it extends the foundation file *minimally* and notes it in its report — it does not fork a local variant. **Minimum path to "the app suddenly looks designed":** phases **0 → 1 → 2**. Those three de-starter every screen at once (theme pass + primitives + chrome); phases 3–11 are then per-area redesigns on a system that already looks right. --- ## How the phase files are written Each file follows the repo's [phase template](../../phases/_shared/phase-template.md): a one-paragraph mission, context (what already exists — don't rebuild), required reading (including the relevant [`audit/`](audit/) files, which carry the full evidence), enumerated scope with file paths, the mocks/REQ posture, the invariants it must not break (including the area's **do-not-regress** list), a Definition of Done, concrete how-to-test steps across the four axes (`/fa` + `/en` × light + dark, mobile + desktop), and a close-out (docs + report + memory). Non-negotiables for every phase (they restate them, but for the human reader): - **Invoke the `frontend-designer` skill before any UI work** — it is the design contract (brand palette, token rules, `App*` wrappers, icon registry, RTL/dark-mode/i18n rules). - **`npm run check` green + `npm run test:ci`** when shared components change; new shared components get co-located tests; `en.json`/`fa.json` stay in sync. - **Frontend lane only.** Backend gaps become REQ entries in [`for-backend.md`](../../shared-working-context/frontend/requests/for-backend.md), never edits to `server/`. - **Verify visually on `/fa` first** — it is the default locale and RTL. ## Related documents - [`audit/`](audit/) — the 15 per-area audit reports (current state, problems with evidence, opportunities, keep-lists) this chain was synthesized from. - [../refinement/README.md](../refinement/README.md) — the integration/production chain that preceded this one (complete). - [../../phases/_shared/agent-operating-rules.md](../../phases/_shared/agent-operating-rules.md) — how an executing agent works a phase; every phase file links it. - [.claude/skills/frontend-designer/SKILL.md](../../../.claude/skills/frontend-designer/SKILL.md) — the design contract this chain builds on (and extends: phase 0 updates it when tokens/icons change). - [../../shared-working-context/frontend/requests/for-backend.md](../../shared-working-context/frontend/requests/for-backend.md) — the REQ tracker; UI phases append REQ-039+ here.