11 KiB
Frontend Phase 0 — Foundations: app shells, design system & the data/contract patterns
Mission: turn the inherited starter into a clean Balinyaar foundation for the three actor experiences (family/customer, nurse, admin). Remove the demo leftovers, build the app shells and route groups each actor needs, and lock in the patterns every later frontend phase will follow: how a
services/{domain}talks to the API, how TanStack Query caches it, how types come from the published contract, and where shareable components live. No real feature data yet (no backend dependency) — this phase makes f1–f15 fast, consistent, and re-render-cheap.Track: frontend · Depends on: nothing (
frontend-phase-0, no backend phase required) · Unlocks: every frontend phase Before you start, read../_shared/agent-operating-rules.md. It is not optional.
1. Context — where this sits
The client (client/, Next.js 16 App Router + React 19 + MUI v9 + next-intl, fa default & RTL)
already ships a full app shell and an App* component library — you keep and build on these and
remove the demo bits.
What already exists (do not rebuild) — confirmed in the codebase:
- Root layout
src/app/[locale]/layout.tsx(renders<html lang dir>, providers: NextIntl → Auth → Theme → Query → Notistack),(private-routes)/(public-routes)groups, theTopBarAndSideBarLayoutengine +TopBar/SideBar/BottomBar. - Theme system (brand tokens teal
#1d4a40, terracotta#d98c6a, cream intheme/colors.ts+tokens.css;APP_THEME_LTR/RTL, dark mode), i18n (routing.ts,request.ts), the cookie manager,clientFetch/serverFetch+ApiError, TanStack Query (makeQueryClient/QueryProvider), the toast bridge,AuthContext, the middleware auth gate. - The
App*library:AppButton,AppIconButton,AppAlert,AppIcon,AppImage,AppLink,AppLoading(+ErrorBoundary,UserInfo); theauthservice (useLogin/useLogout/useCurrentUser).
What is demo scaffolding you will remove in this phase:
- The
toastDemoi18n namespace (bothen.json/fa.json) and the placeholderHomePage(<Typography>Balin yaar</Typography>with its unusedt). - The unregistered dead icons
AppIcon/icons/CurrencyIcon.tsxandYellowPlanIcon.tsx. - Fix the small drift noted in the audit:
AppLoadingmissing from the@/componentsbarrel export;BottomBarreading globallocationinstead ofusePathname.
Auth note: login is currently username/password. It becomes phone-OTP in f1-b2 — don't wire login screens here; this phase only prepares the shells and patterns.
2. Required reading (do this first)
../_shared/agent-operating-rules.mdand../_shared/frontend-conventions-checklist.md.client/CLAUDE.mdin full — the engineering contract (RSC boundary, layouts, i18n, theme, cookies, fetch services, anti-patterns). Note the doc/code drift the audit found (e.g. aColorSchemeScriptis referenced but doesn't exist) — trust the code, and fix the doc if you touch that area.- Invoke the
frontend-designerskill — it is the design/brand contract (palette, tokens, typography, theApp*library, layout shells, the hard UI rules). All visual work goes through it. product/wireframes/index.html— the visual baseline: mobile-first RTL app, deep-green brand, the 5-tab bottom nav for the customer app (خانه/Home · رزروها/Bookings · بیماران/Patients · کیفپول/Wallet · پروفایل/Profile), and the nurse-only screens. This phase builds the shells those screens will live in.../../contracts/README.md+conventions/api-conventions.md+money-and-types.md— how you'll type and format server data (envelope, IRR-as-string + Toman display, enums-as-codes, UTC + Shamsi display).- The existing
src/services/auth/*— the exact pattern (types.ts/keys.ts/apis/clientApi.ts/hooks/use*.ts/index.ts) every new domain service copies.
3. Scope — build this
3.1 Clean up the demo scaffolding
Remove the toastDemo namespace, the placeholder home page content, the two dead icons; fix the
AppLoading barrel export and the BottomBar usePathname bug. Keep everything else. npm run check
stays green throughout.
3.2 The three actor app shells + routing
Balinyaar has three audiences with different chrome. Establish them now (empty/placeholder content is fine — they fill up in later phases):
- Customer (family) app — mobile-first shell with the bottom tab nav (Home/Bookings/Patients/ Wallet/Profile) per the wireframe; this is the primary experience.
- Nurse app — its own shell (the wireframe's "نمای پرستار" screens: verification, dashboard, EVV).
- Admin/backoffice — a desktop-oriented shell (sidebar nav) for the ops console (f15).
Decide the routing that expresses these cleanly within the existing [locale] + route-group structure
(e.g. role-scoped route groups/segments under (private-routes)), without adding any layout above
[locale] and without breaking the server/client boundary. Drive nav by role from AuthContext
(roles arrive in f1-b2 — design the shell to read a role and render the right chrome; default gracefully
until roles exist). Build a shared bottom-nav and shared sidebar-nav component at the right level
in src/layout/ / src/components/. Update the Project Structure tree in client/CLAUDE.md for any
new route group/folder.
3.3 The services/{domain} + Query caching pattern (the reference implementation)
Codify the data pattern every later phase copies, using the auth service as the template and the
checklist's caching rules:
- A
keys.tsquery-key factory per domain; deliberatestaleTime/gcTime; mutations invalidate orsetQueryDataso data already in cache is never needlessly refetched. apis/clientApi.ts(+serverApi.tsonly when an RSC needs it) wrappingclientFetch/serverFetch; one hook per file.- A documented way to derive
types.tsfrom the published contract (dev/contracts/) — and, when a backend phase isn't ready, a mockclientApibehind the same seam plus a row in your report (so it's swapped cleanly once the real endpoint lands). Provide a tiny example domain (or thoroughly document theauthone) so f1 starts by copying, not inventing. - A small money/format util (
formatIrrToToman, integer-safe parse of IRR strings, Shamsi date display) insrc/utils/per the money-and-types contract — used wherever prices/dates render.
3.4 Shared composite components (built once, reused everywhere)
Build the cross-cutting composite components the wireframe implies, at the shared level (src/components/…),
each with a co-located *.test.tsx, each composed from MUI/App* primitives (never re-implementing a
root primitive): an OTP code input, a phone-number field (Iranian format, RTL-safe), a stepper/
progress header (used by onboarding + verification), a status chip (verified/pending/…); a
nurse/result card and a price-breakdown can be stubbed here or deferred to their phases — your
call, but if you build them, build them shared. Keep page-only composition in pages.
3.5 i18n namespaces baseline
Establish the namespace conventions for the feature areas to come (e.g. auth, onboarding,
verification, search, booking, payment, bnpl, reviews, notifications, admin, common,
nav) — seed common/nav with the shell strings you add, in both en.json and fa.json, in
sync. RTL-first.
4. Mocks & seams in this phase
No backend dependency. Where you demonstrate the data pattern without a live endpoint, use a mock
clientApi behind the services/{domain} seam and note it in your report — this is the template f1+
follow until their backend phase is merged.
5. Critical rules you must not get wrong
- Never add a layout above
[locale]and never break the RSC/client boundary (the audit shows the current setup is load-bearing — seeclient/CLAUDE.md). - Design RTL-first,
fadefault; every string in both locale files. - Colours from tokens, MUI v9 API only, pre-built themes only.
- Caching is a feature: set
queryKey/staleTimedeliberately and invalidate on mutation — the whole point of this phase is that later phases don't over-fetch or over-render. - MUI primitives stay MUI; shareable composites live shared, not in a page.
- Keep
npm run checkgreen and translations in sync at every step.
6. Definition of Done
The shared definition-of-done.md, plus:
- Demo scaffolding removed; the two barrel/
BottomBarbugs fixed;npm run checkgreen;npm run test:cigreen for the shared components you add. - The three actor shells exist and render with role-aware nav (degrading gracefully before roles
exist); no layout added above
[locale]. - The
services/{domain}+ Query caching pattern is implemented and documented as the reference; the money/format util exists. - The shared composite components added each have a co-located test.
client/CLAUDE.mdProject Structure updated for new route groups/folders; any doc drift you touched is corrected.
7. How to test (what a human can verify after this phase)
npm run dev→ the app boots; visiting the customer area shows the mobile shell with the 5-tab bottom nav; the nurse and admin areas show their shells; switching locale flipsdir/strings correctly; dark mode still works.npm run checkandnpm run test:cipass; the new shared components render and their interactions fire callbacks in tests.- The reference
services/{domain}(or the documentedauthone) shows a query caching + a mutation invalidating it in React Query Devtools.
8. Hand off & document (close the phase)
- Docs: update
client/CLAUDE.mdProject Structure (route groups, new shared components, the services pattern note); fix any drift you touched. - Contracts: none produced (frontend consumes). If the b0 swagger snapshot exists, wire the
types-from-contract step against it; otherwise document the intended step. File any envelope/format
question in
shared-working-context/frontend/requests/for-backend.md. - Handoff & report: append to
shared-working-context/frontend/STATUS.md; writereports/frontend-phase-0-report.md(shells built, the reference data pattern, which composites are shared, what's mocked client-side and how f1 swaps it). - Memory: save a
projectmemory note for the actor-shell/routing decision and the data pattern, with aMEMORY.mdpointer.