Files
baya-monorepo/archive/build-chain/working-context/reports/frontend-phase-0-report.md
T
2026-08-02 18:48:32 +03:30

6.8 KiB

Frontend Phase 0 — Foundations: app shells, design system & data/contract patterns — Report (2026-07-02)

What was built

Cleanup (3.1)

  • Removed the toastDemo i18n namespace (both locales) and the placeholder home page.
  • Deleted the two dead icons (AppIcon/icons/CurrencyIcon.tsx, YellowPlanIcon.tsx).
  • Fixed BottomBar to read the route via usePathname() (was the global location) and made it locale-aware (highlights the active tab, pushes locale-prefixed routes).
  • Audit note "AppLoading missing from the @/components barrel" — verified it is already exported (components/common/index.tsx); no change needed.

Actor shells + routing (3.2) — three role-scoped experiences under (private-routes), no layout added above [locale]:

  • Customer (family)(customer) route group (no URL segment) at /, /bookings, /patients, /wallet, /profile; CustomerLayout = slim TopBar + the 5-tab BottomBar from the wireframe.
  • Nurse/nurse, /nurse/verification, /nurse/visits; NurseLayout on the shared TopBarAndSideBarLayout engine.
  • Admin/admin, /admin/users, /admin/notifications; AdminLayout, persistent desktop sidebar.
  • Role model: constants/roles.ts (AppRole), optional User.roles, and useActorRole() (defaults to customer until the server seeds roles in f1-b2). Nav is built per shell from useTranslations('nav').

Data pattern + utils (3.3)

  • Reference domain services/patients/ mirroring auth: types.ts (+ the PatientsApi seam interface), keys.ts (hierarchical factory), constants.ts (mock toggle + staleTime), apis/ (clientApi real, mockApi in-memory, index selects by config), hooks/ (usePatients with staleTime, useAddPatient invalidates the list), barrel exporting hooks only.
  • Shared wire types lib/api/types.ts: ApiEnvelope<T> + unwrap(), Paginated<T>, PageParams.
  • Money/date utils in @/utils: parseIrr/rialToToman/formatIrr/formatIrrToToman (integer-safe BigInt) and formatShamsiDate/formatShamsiDateTime (Intl Persian calendar — no date lib). Plus toEnglishDigits/digitsOnly in utils/text.ts.

Shared composites (3.4) — each in src/components/<Name>/ with a co-located .test.tsx, composed from MUI/App* primitives, i18n-agnostic (labels passed by caller):

  • OtpInput (auto-advance, backspace-to-previous, paste distribution, digit-normalizing, LTR-in-RTL),
  • PhoneNumberField (Iranian mobile, normalizes Persian/Arabic digits, caps at 11, isIranianMobile),
  • StepperHeader (MUI Stepper, RTL-aware), StatusChip (verified/pending/rejected/… off --bal-* tokens),
  • PlaceholderScreen (empty-state used by every not-yet-built screen).
  • Nurse/result card and price-breakdown were deferred to their feature phases (per the phase's "your call").

i18n (3.5) — seeded nav, common, shell, patients in both en.json/fa.json (in sync, RTL-first). Documented the future namespace conventions in client/CLAUDE.md.

What is now testable (and exactly how)

  1. cd client && npm run dev → open http://localhost:3000 (redirects to /fa).
    • Customer shell: mobile 5-tab bottom nav (خانه/رزروها/بیماران/کیف‌پول/پروفایل); tapping switches routes and highlights the active tab.
    • Nurse shell: /fa/nurse — TopBar + sidebar (داشبورد/احراز هویت/ویزیت‌ها).
    • Admin shell: /fa/admin — persistent sidebar on desktop (نمای کلی/کاربران/اعلان‌ها).
    • Switch locale to /endir flips to LTR and all strings translate; dark-mode toggle still works.
  2. Reference data pattern: /fa/patients shows the mocked list (~400 ms latency), an add form (name + gender). Submitting adds the patient and the list updates without a refetch — open React Query Devtools to watch ['patients','list',…] cache + the invalidation on mutation success.
  3. npm run check (type + lint) and npm run test:ci (72 tests, 12 suites) both pass. npm run build passes when NEXT_PUBLIC_API_URL is set (see Follow-ups).

What is mocked / waiting on a real service

  • Patients domain — client-side mock. services/patients/apis/mockApi.ts (patientsMockApi) implements the PatientsApi interface (services/patients/types.ts) in memory. Selected by USE_PATIENTS_MOCK = true in services/patients/constants.ts. The real clientApi.ts is written against /patients (GET list + POST create) and already unwraps the ApiEnvelope. To make real: publish the patients contract + endpoints, set USE_PATIENTS_MOCK = false — no hook/component change. (This is a frontend client-side mock, not a backend DI seam, so it is recorded here rather than in the backend-owned mocks-registry.md.)
  • This is the template f1+ copy for any domain whose backend phase hasn't merged.

Contracts

  • Produced: none (frontend consumes).
  • Consumed: dev/contracts/conventions/{api-conventions,money-and-types}.md and the b0 openapi/swagger.v1.json (only ping endpoints exist yet). Types-from-contract step is wired for the patients reference (shapes mirror the intended wire; ApiEnvelope/Paginated in lib/api/types.ts).
  • Request filed: frontend/requests/for-backend.md REQ-001 (confirm envelope unwrapping, wire casing, pagination payload shape).

Docs updated

  • client/CLAUDE.md: Project Structure tree (new route groups, actor layouts, shared composites, services/patients, lib/api/types.ts, constants/roles.ts, money/date utils); i18n namespaces + future-namespace conventions; a new services/{domain} reference pattern subsection (caching, mock seam, envelope, money/dates). Corrected the ColorSchemeScript doc drift in the two structure lines that named it (it is neither exported from @/theme nor rendered).

Follow-ups for later phases

  • Envelope unwrapping (REQ-001): clientFetch/serverFetch currently return the raw body, so domain clientApis call unwrap(). If the team prefers central unwrapping, that touches the auth plumbing — coordinate before changing. Wire casing observed is camelCase, not the snake_case api-conventions implies; confirm and update the convention doc.
  • Role guards: shells read useActorRole() but do not yet guard cross-actor access (any authed user can open /nurse, /admin). Add real guards once roles land in f1-b2.
  • Login is username/password today; phone-OTP arrives in f1-b2 (use OtpInput/PhoneNumberField).
  • npm run build needs NEXT_PUBLIC_API_URL: @/config uses envRequired, which throws at import. Dev works via the committed .env.development; a production build must supply the var (as it always would once any page imports the fetch layer). Not a code defect — an env expectation to note in CI.