# 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 `/en` → `dir` 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
  `clientApi`s 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.
