16 KiB
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 (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 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 infor-backend.mdand builds mock-tolerant UI behind the existingservices/{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:
- 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. - 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.
- RTL as a habit — logical properties (
borderInlineStart,textAlign: 'start',marginInline*), deliberatedir="ltr"islands for phone numbers/IBANs/clocks, RTL-mirrored message bubbles. - Persian correctness plumbing —
utils/money.ts(BigInt IRR, Toman-at-the-boundary, fa digit grouping),utils/date.ts(Shamsi viaIntlfa-IR-u-ca-persian), locale digits in counts and pagers. - 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. - The architecture seams design work needs — the
AppIconstring registry (one-file icon swap), the per-actor shell split (CustomerLayout/NurseLayout/AdminLayout/PartnerLayout), component defaults incomponents/config.ts, theservices/{domain}mock seams, the admin composite layer (AdminDataTable/ConfirmDialog/…), optimistic ticket send withclientMessageIdreconciliation. - 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
createThemehas zerocomponentsoverrides (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
TopBarwith a static centered label, flat 10-item sidebar whose active highlight never fires (locale-prefix bug inSideBarNavItem), a permanentUserInfoplaceholder ("Current User" / "Loading..." in English), physicalpaddingLeft/RightRTL 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;
ErrorBoundaryis unstyled English with a raw stack dump;globals.cssis the starter reset;light.ts/dark.tsare 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-visiblestyle exists in the whole app. - The icon registry mixes filled/outlined generations, has no back/chevron icon at all, and
AppIcon'ssizeprop is silently broken for MUI icons.AppButtonships a startermargin: 1default that 213 call-sites in 82 files neutralize withsx={{ 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
formatNumberhelper (thefa-IRternary is copy-pasted 25+ times) — and no Jalali date picker, so every date input in a Shamsi-displaying product is a native Gregoriantype="date". - No route-level
loading.tsx/error.tsx/not-found.tsxanywhere; 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 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 | 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 | 0–2 |
| 4 | Customer storefront | 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 | 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 | 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 | the real nurse dashboard, visit workspace (address/contact/EVV-first), decision-first request inbox + urgency system, earnings clarity | 0–2 |
| 8 | Nurse business & verification | 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 | 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 | 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 | 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 | 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) | 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: 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-designerskill before any UI work — it is the design contract (brand palette, token rules,App*wrappers, icon registry, RTL/dark-mode/i18n rules). npm run checkgreen +npm run test:ciwhen shared components change; new shared components get co-located tests;en.json/fa.jsonstay in sync.- Frontend lane only. Backend gaps become REQ entries in
for-backend.md, never edits toserver/. - Verify visually on
/fafirst — it is the default locale and RTL.
Related documents
audit/— the 15 per-area audit reports (current state, problems with evidence, opportunities, keep-lists) this chain was synthesized from.- ../refinement/README.md — the integration/production chain that preceded this one (complete).
- ../../phases/_shared/agent-operating-rules.md — how an executing agent works a phase; every phase file links it.
- .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 — the REQ tracker; UI phases append REQ-039+ here.