Files
baya-monorepo/dev/post-phase/ui/README.md
T
2026-07-17 13:22:04 +03:30

16 KiB
Raw Blame History

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/.

This directory is a runnable chain of 14 UI phases (013) 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 02, 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 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 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.csscolors.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 plumbingutils/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 componentsEscrowNotice (product-mandated verbatim copy), RefundEtaBanner's honest BNPL 710-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/ 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 <title> 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 02 build the foundation everything else composes from. Phases 311 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 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 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 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 trust-forward login hero, OTP autofill (WebOTP), terms/privacy consent + pages, illustrated select-role, focused onboarding wizard, returnUrl 02
4 Customer storefront home that sells, Shamsi date filter, sticky search CTA, honest results header + NurseResultCard v2, nurse profile as trust dossier + verification explainer 02
5 Booking lifecycle C4 trust-anchored request form, C5 countdown ring + recovery, customer requests tabs on /bookings, booking-detail hero + vertical timeline, cancel-flow fixes, review context 02 (4 recommended)
6 Checkout & money checkout hierarchy + sticky pay bar, receipt-grade confirmation, wallet as money hub, honest BNPL comparison, fiscal-grade invoice, designed wait states 02 (5 recommended)
7 Nurse daily ops the real nurse dashboard, visit workspace (address/contact/EVV-first), decision-first request inbox + urgency system, earnings clarity 02
8 Nurse business & verification activation checklist (honest PublishGate), unified verification journey, DocumentUpload fixes, variant-builder preview, coverage viz, bank flows, public-profile preview 02 (4 for trust components)
9 Customer account & care circle profile as account hub (+ sign-out entry), care-circle reframe with avatars, per-item care-record editing, real map picker, mobile full-screen forms 02
10 Messaging & notifications chat-grade ticket threads (live, scrolled, grouped), inbox pagination/filters, right-sized emergency affordance, notification center grouping + bell popover 02
11 Admin & partner console URL-synced list state, user/nurse pickers (no raw IDs), verification desk, ticket console lifecycle, AdminDataTable v2, Jalali inputs, partner localization 02
12 Copy, motion & final polish 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 (optional) public landing, how-it-works, SEO/metadata/OG, guest-browse decision (+ public-endpoint REQs) 02 · product decision

Dependency & sequencing

Foundation (strictly in order):
  0 design language ──► 1 primitives & states ──► 2 shells & navigation

Area redesigns (after 02; 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 02; 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 311 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: a one-paragraph mission, context (what already exists — don't rebuild), required reading (including the relevant 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, never edits to server/.
  • Verify visually on /fa first — it is the default locale and RTL.