# FRONTEND-CONTINUATION-PLAN.md

> **Recovery-safe execution plan** for converting the Dalseen prototype (`front/`) into the production frontend at `app/`.
>
> **Read this file first at the start of every new session.** It is the single source of truth for "what comes next."
>
> **Last updated:** 2026-05-04 (after Batch B0 — Workspace skeletons)
> **Active project root:** `app/` (Vite + React 18 + React Router + React Query + Tailwind)
> **Prototype reference:** `front/` (legacy compiled HTML/JS) + `docs/handoff/SCREENS-INVENTORY-*.md` (specs)

---

## §1 — Current Project State

### §1.1 Architecture (do not touch)

The shell, routing, auth, session, mock adapter, and design tokens are **complete and working**. Treat this layer as frozen unless a module legitimately requires extending it. Files:

```
app/src/app/                     ← shell, routes, sidebar nav (locked)
app/src/core/api/                ← request/http/mockAdapter/queryClient (locked)
app/src/core/session/            ← sessionStore (locked)
app/src/core/hooks/useT.js       ← bilingual EN/AR helper
app/src/core/hooks/usePermission ← granular permission gate
app/src/core/utils/format.js     ← cn, formatSAR, formatNumber, formatDate
app/src/components/              ← Badge, Button, Drawer, Modal, Icon, Input, PageHeader,
                                   Section, StatCard, States, Table, Tabs, Toolbar
```

### §1.2 Implemented (✅ done — do not regenerate)

| Module | Path(s) | State |
|---|---|---|
| Auth | `modules/auth/LoginPage.jsx` + hooks/api/ProtectedRoute | ✅ wired |
| Dashboard | `modules/dashboard/DashboardPage.jsx` | ✅ stub-grade (KPIs only — see §2.5) |
| Platform · Tenants | `modules/platform/TenantsPage.jsx` | ✅ list + drawer + suspend/reactivate |
| Platform · Signups | `modules/platform/SignupsPage.jsx` | ✅ list + promote/reject |
| Platform · Onboarding | `modules/platform/OnboardingPage.jsx` | ✅ list + nudge |
| Platform · Plans | `modules/platform/PlansPage.jsx` | ✅ list |
| Platform · Billing | `modules/platform/BillingPage.jsx` | ✅ list + remind |
| Platform · Support | `modules/platform/SupportPage.jsx` | ✅ list + assign/resolve |
| Platform · Health | `modules/platform/HealthPage.jsx` | ✅ read-only |
| Platform · Compliance | `modules/platform/CompliancePage.jsx` | ✅ read-only |
| Platform · Incidents | `modules/platform/IncidentsPage.jsx` | ✅ read-only |
| Platform · Releases | `modules/platform/ReleasesPage.jsx` | ✅ read-only |
| Platform · Audit | `modules/platform/AuditPage.jsx` | ✅ read-only |
| HR (Workspace) | `modules/hr/HRPage.jsx` | ✅ Staff / Leave / Attendance / Payroll tabs (read-only — approve/reject buttons are dead) |
| Retail (Workspace) | `modules/retail/RetailPage.jsx` | ✅ Sales / Catalog / Inventory / Customers / Suppliers tabs (read-only) |
| Dine-in (Workspace) | `modules/dine/DinePage.jsx` | ✅ Floor / Kitchen / Menu tabs (read-only — Bump / Mark ready buttons are dead) |
| Accounting (Workspace) | `modules/accounting/AccountingPage.jsx` | ✅ Reports / Invoices / Bills / VAT / COA tabs (read-only) |

### §1.3 Mocks present (`app/src/core/api/mocks/`)

`auth.mock.js`, `platform.mock.js`, `retail.mock.js`, `dine.mock.js`, `hr.mock.js`, `accounting.mock.js`, `owner.mock.js` — all auto-imported by `mockAdapter.js`. Mocks are **GET-only fixtures** today; no POST/PATCH/DELETE handlers exist for the workspace modules.

### §1.4 Still incomplete (the backlog)

#### A. ComingSoon usage
**None at runtime.** `app/src/modules/_stubs/ComingSoon.jsx` exists but no route renders it (the workspace stubs were replaced in Batch B0). Keep the file — it is a useful placeholder for future top-level modules.

#### B. Routes wired but read-only — actions are visually present but dead
| Page | Dead buttons / actions |
|---|---|
| HR · Leave | Approve / Reject |
| HR · Staff | Add employee, Export |
| HR · Payroll | (no actions yet — needs "Run payroll" / "File WPS") |
| Dine · KDS | Bump, Mark ready |
| Dine · Floor | (no actions — needs "Open table" / "Close check") |
| Retail · Sales | Refund, Print receipt |
| Retail · Products | Edit, Adjust stock, Archive |
| Accounting · Invoices | Send, Mark paid, ZATCA re-clear |
| Accounting · Bills | Mark paid |
| Accounting · VAT | File return |
| All `Export` buttons globally | dead |
| All `New <thing>` buttons globally | dead |

#### C. Modules **not yet started** (no folder under `app/src/modules/`)

| Module | Source spec | Notes |
|---|---|---|
| **Pay** | `docs/handoff/SCREENS-INVENTORY-Pay.md` | Standalone payments / WPS / payouts module per the prototype. No route, no nav entry, no mock. |
| **Owner** | `docs/handoff/SCREENS-INVENTORY-Owner+HR.md` (Owner section) | Tenant owner self-service: plan, billing portal, branches, users, settings. Stub `owner.mock.js` exists with one endpoint. |
| **Common settings** | `docs/handoff/SCREENS-INVENTORY-Common.md` | Profile, notifications, fiscal calendar, VAT codes, company profile. |
| **POS shell** | prototype `front/` retail screens (full-screen cashier UI) | Out of scope for v1 web — defer to v1.1 unless re-prioritised. |

#### D. Pages that exist but match prototype <70%
- **DashboardPage** — current version is a 4-KPI placeholder + "next iteration" footer. Prototype has 12+ widgets (sales chart, branch heatmap, top SKUs, alerts, recent activity).
- **HRPage > Payroll** — list only; prototype has run-detail drawer with payslip preview + WPS file generator.
- **AccountingPage > Reports** — three summary cards; prototype has filterable P&L / BS / Cashflow with comparative columns and export.

### §1.5 Risky files — avoid wholesale edits

| File | Why risky |
|---|---|
| `app/src/app/App.jsx` | Touches the whole route tree. **Append-only edits** — never reorder or rewrite. |
| `app/src/app/AppShell.jsx` | Sidebar + header layout used by every authed route. Layout regression cascades everywhere. |
| `app/src/app/nav.config.jsx` | Drives the sidebar. Adding entries here is fine (declarative); never reorder. |
| `app/src/core/api/mockAdapter.js` | Central router. New mocks must be **added via `import` line** + a separate file in `mocks/`. Never inline handlers here. |
| `app/src/core/session/sessionStore.js` | Auth + tenant + locale state. Touch only when adding new permission keys. |
| `app/src/components/*.jsx` | Shared. Extend by adding props with defaults; never rename existing props. |
| Any file > 400 LOC | High blast radius. Split into sibling files before extending. |

---

## §2 — Execution Strategy

### §2.1 Hard rules (non-negotiable)

1. **One module per batch.** A "batch" = one route or one tab inside an existing page. Never two.
2. **No full-project rewrites.** No "while I'm in there" cleanups. If a refactor is genuinely needed, file it as a separate batch.
3. **No massive search/replace.** All edits are scoped to ≤ 3 files per batch (page + api + hooks; or page only).
4. **No API auditing inside a UI batch.** The API surface is already audited (`docs/handoff/OWNER-HR-OPENAPI-VERIFICATION.md`, `FLOW-INVENTORY*.md`). If a screen needs an endpoint that's missing, **add the mock fixture** and tag the gap in `docs/handoff/MISSING-SCREENS-INVENTORY.md` — don't go down the audit rabbit hole mid-UI work.
5. **Mocks first, real backend second.** Every screen ships against the in-process mock adapter. Real-backend swap is a separate, later phase (single config flag flip in `core/config.js`).
6. **Commit after every completed module.** Single squashed commit, message format: `feat(<module>): <screen> — Batch B<N>`. See §5.
7. **No new dependencies.** The current `package.json` is the floor. Adding a library = separate batch with explicit user approval.
8. **Bilingual (EN/AR) is mandatory.** Every visible string goes through `useT()`. Skipping AR is a defect.
9. **Permission-gated.** Every route in `App.jsx` wraps its element in `<ProtectedRoute permission="…">`. The permission key matches `nav.config.jsx`.
10. **The prototype is the source of truth for UX.** When in doubt, screenshot the prototype and match it; don't invent.

### §2.2 Batch shape (mechanical recipe)

A batch is a single message exchange that ends with a working route. Inside one batch:

1. Read the prototype source (`front/<module>/<screen>.compiled.js`) and the matching `SCREENS-INVENTORY-*.md` row.
2. If a mock endpoint is missing, add a fixture handler to `app/src/core/api/mocks/<module>.mock.js` (GET only — mutations stub to `{ ok: true }`).
3. Write `app/src/modules/<module>/<Screen>Page.jsx`.
4. If the module is new, also write `<module>.api.js` and `<module>.hooks.js` and create the folder.
5. Wire the route in `App.jsx` (append, don't reorder).
6. Add a nav entry in `nav.config.jsx` if it's user-visible.
7. Smoke-test: `npm run build` + load the route + click every interactive control.
8. Commit.

That's it. If a batch grows past three files of edits, **stop and split it**.

### §2.3 What we are NOT doing

- Not building the POS cashier UI (defer).
- Not building the marketing/public site.
- Not building any animations beyond what shared components already provide.
- Not migrating the prototype's compiled JS — we re-implement against React + the new design system.
- Not touching the backend. All work is FE.

---

## §3 — Module Conversion Checklist

Use this checklist verbatim for every batch. Tick boxes as you go; an unticked box at commit time = the batch is not done.

```
[ ] 1. ROUTE
       - Added under correct parent in app/src/app/App.jsx
       - Wrapped in <ProtectedRoute permission="…">
       - Path matches nav.config.jsx
[ ] 2. NAV ENTRY
       - Added to nav.config.jsx with EN + AR labels and icon
       - Permission key matches the route
       - (Skip only for sub-tabs that live inside a parent page)
[ ] 3. PAGE.JSX
       - File: app/src/modules/<module>/<Screen>Page.jsx
       - Default-exports a single React component
       - Uses useT() for every string
       - Header: kicker (uppercase) + title + subtitle (bilingual)
       - Action buttons in top-right (even if dead — visual completeness)
[ ] 4. API FILE (per module, shared across screens)
       - File: app/src/modules/<module>/<module>.api.js
       - Exports a single object: <module>Api = { method: (params) => request.get/post(...) }
       - One method per endpoint; no inlined business logic
[ ] 5. HOOKS FILE (per module)
       - File: app/src/modules/<module>/<module>.hooks.js
       - useQuery for reads; useMutation + invalidateQueries for writes
       - Query keys are arrays starting with the module name: ['hr','staff', params]
[ ] 6. MOCK / FALLBACK DATA
       - Handler in app/src/core/api/mocks/<module>.mock.js
       - At minimum 6–12 fixture rows, bilingual where the field exists
       - Mutations: return ok({ ok: true }) — no need to mutate fixtures unless the screen reads back its own writes
[ ] 7. LOADING STATE
       - Table component already handles isLoading={q.isLoading}
       - For non-table layouts, show <div className="card p-12 text-center text-ink-400 text-sm">Loading…</div>
[ ] 8. EMPTY STATE
       - Table component shows "No results." automatically
       - For richer empties, use <EmptyState> from components/States.jsx
[ ] 9. ERROR STATE
       - {q.isError && <ErrorBanner error={q.error} onRetry={q.refetch} />}
       - Place above the table/grid, not inside it
[ ] 10. PERMISSIONS
       - Route gate matches the most-restrictive permission for the page
       - Inline action buttons that need a higher permission use usePermission()
[ ] 11. BASIC INTERACTIONS
       - Filters: pill bar pattern from TenantsPage (FilterPills component, copy verbatim)
       - Row click → drawer (use <Drawer> from components/Modal.jsx) when detail is needed
       - Mutations: button shows loading={mut.isPending}, on success closes drawer + invalidates query
[ ] 12. BILINGUAL
       - Verified by toggling locale: every visible string flips
       - Numbers via formatNumber(n, locale); money via formatSAR(n, locale)
[ ] 13. NO CONSOLE ERRORS
       - Open the route, open devtools, click around — must be clean
[ ] 14. COMMIT
       - git add only the 3–5 files this batch touched
       - Message: feat(<module>): <screen> — Batch B<N>
```

---

## §4 — Batch Order

Dependencies first, leaf screens last. This is the order; **do not skip ahead**, even if a later batch looks easier — earlier batches harden patterns the later ones rely on.

### §4.1 Phase P1 — Pilot blockers (workspace mutations work end-to-end)

These batches make the existing read-only screens actually do things. No new modules — just upgrading what's there.

| # | Batch | Files touched | Why first |
|---|---|---|---|
| **B1** | HR · Leave approve/reject mutations | `hr.api.js`, `hr.hooks.js`, `HRPage.jsx`, `mocks/hr.mock.js` | Smallest mutation surface; sets the pattern for every later mutation. |
| **B2** | Dine · KDS bump / mark-ready | `dine.api.js`, `dine.hooks.js`, `DinePage.jsx`, `mocks/dine.mock.js` | Validates the optimistic-update pattern (KDS UI feels broken without it). |
| **B3** | Retail · Products edit drawer + stock adjust | `retail.api.js`, `retail.hooks.js`, `RetailPage.jsx`, `mocks/retail.mock.js` | First "row click → drawer with form" pattern in workspace. |
| **B4** | Accounting · Invoices send / mark-paid + invoice detail drawer | `accounting.api.js`, `accounting.hooks.js`, `AccountingPage.jsx`, `mocks/accounting.mock.js` | Cements the drawer-with-form pattern; invoice detail is the highest-value drill-down. |
| **B5** | Accounting · Bills mark-paid + VAT file-return | same module | Quick wins reusing B4's drawer. |
| **B6** | HR · Payroll run-detail drawer (payslip preview, WPS file button) | hr.* | Most complex drawer in the module. |

### §4.2 Phase P2 — Dashboard upgrade

| # | Batch | Files touched |
|---|---|---|
| **B7** | DashboardPage v2 — sales chart card + branch heatmap card | `DashboardPage.jsx`, new `mocks/dashboard.mock.js`, new `dashboard.api.js`, `dashboard.hooks.js` |
| **B8** | DashboardPage v2 — top SKUs + alerts + recent activity | same files |

### §4.3 Phase P3 — Owner module (tenant self-service)

| # | Batch | New files |
|---|---|---|
| **B9** | Owner shell + nav group + `OwnerPage.jsx` (tabs scaffold) + extend `owner.mock.js` | `modules/owner/OwnerPage.jsx`, `owner.api.js`, `owner.hooks.js`; nav.config + App.jsx |
| **B10** | Owner · Plan & billing portal tab | `OwnerPage.jsx` only |
| **B11** | Owner · Branches tab | same |
| **B12** | Owner · Users & roles tab | same |

### §4.4 Phase P4 — Common settings

| # | Batch | New files |
|---|---|---|
| **B13** | Settings shell — `SettingsPage.jsx` with tabs (Profile / Notifications / Company / Fiscal / VAT codes) | `modules/settings/*` |
| **B14** | Settings · Profile + Notifications tabs | `SettingsPage.jsx` |
| **B15** | Settings · Company profile + Fiscal calendar tabs | same |
| **B16** | Settings · VAT codes tab | same |

### §4.5 Phase P5 — Pay module

| # | Batch | New files |
|---|---|---|
| **B17** | Pay shell + nav entry + `PayPage.jsx` (Payouts / WPS / Receivables tabs) + `pay.mock.js` | `modules/pay/*` |
| **B18** | Pay · Payouts list + run drawer | `PayPage.jsx` |
| **B19** | Pay · WPS file generator | same |
| **B20** | Pay · Receivables aging | same |

### §4.6 Phase P6 — Hardening

| # | Batch |
|---|---|
| **B21** | Wire `Export` buttons globally (CSV download per page) |
| **B22** | Wire `New <thing>` buttons → create-form drawer per page |
| **B23** | Real-backend swap audit: walk every `request.*` call, confirm path matches `openapi.yaml`, flip `core/config.js` flag in a feature branch and smoke-test |

---

## §5 — Crash Recovery Rules

### §5.1 Session start ritual (every new chat)

```
1. Read this file (docs/handoff/FRONTEND-CONTINUATION-PLAN.md) cover-to-cover.
2. Run `git status` and `git log --oneline -20` in the project root.
3. Locate the last commit matching `feat(<module>): <screen> — Batch B<N>`.
   That number is the last completed batch.
4. The next batch is B<N+1> from §4. Do not reorder.
5. Open the §3 checklist and start ticking boxes for B<N+1>.
6. Do not regenerate any module already listed in §1.2 (Implemented).
```

### §5.2 Mid-batch crash

```
1. On restart, run `git diff` and `git status` — uncommitted work survives.
2. Compare against the §3 checklist: which boxes were already ticked?
3. Resume from the first unticked box. Do not start over from box 1.
4. If the diff is incoherent (file half-written, syntax broken):
     git stash
   …then redo the batch from the §3 checklist using a clean tree.
```

### §5.3 Commit discipline

- One commit per completed batch, no exceptions.
- Commit message: `feat(<module>): <screen> — Batch B<N>` (e.g. `feat(hr): leave approve/reject — Batch B1`).
- Include in the commit body: which §3 checklist boxes were verified by hand.
- Never `git commit -a`. Always `git add` the specific files this batch touched.

### §5.4 What "never regenerate" means

If a file already exists under `app/src/modules/<module>/` and is listed in §1.2 as ✅, **do not rewrite it**. Extend it via `str_replace_edit` for additive changes only. Wholesale rewrites silently revert good work that survived a crash.

### §5.5 Update this file at the end of every batch

Before committing batch B<N>:
1. Move the row from §4 (Batch Order) to §1.2 (Implemented).
2. Bump the "Last updated" line at the top.
3. If new dead buttons or gaps were introduced, add them to §1.4.
4. Commit the doc change as part of the batch (not a separate commit).

---

## §6 — Definition of Done (per batch)

A batch is **DONE** when **all** of the following hold:

1. ✅ No `<ComingSoon>` rendered on the route.
2. ✅ Page matches the prototype reference (within ±10% — exact pixel parity is not required, but layout, columns, KPIs, filters, and primary actions are present).
3. ✅ Every interactive control either does something real or is removed. **No dead buttons** (the only exception: aspirational `Export` and `New …` buttons explicitly tracked in §1.4 — these are wired in Phase P6).
4. ✅ Zero console errors on route load and every interaction.
5. ✅ Loading, empty, and error states all reachable and visually correct.
6. ✅ Bilingual: every visible string flips when locale toggles.
7. ✅ Permission gate present on the route; matches `nav.config.jsx`.
8. ✅ `npm run build` succeeds.
9. ✅ Existing architecture preserved — no new top-level folders, no new dependencies, no churn in §1.5 risky files beyond a pure append.
10. ✅ Commit made with the prescribed message format.
11. ✅ This MD file updated per §5.5.

If any box is unchecked, the batch is **NOT DONE** — do not move on to the next batch.

---

## Appendix A — Reference Map

| Need | File |
|---|---|
| What endpoints exist? | `docs/handoff/OWNER-HR-OPENAPI-VERIFICATION.md`, `docs/handoff/FLOW-INVENTORY.md` (+ Addendum), `docs/handoff/routes-api.php`, `docs/openapi/openapi.yaml` |
| What does the prototype render? | `docs/handoff/SCREENS-INVENTORY-{Retail,Pay,Dine,Accounting,Owner+HR,Platform,Common}.md`, plus the corresponding `front/<module>/<screen>.compiled.js` |
| What's still missing vs backend? | `docs/handoff/MISSING-SCREENS-INVENTORY.md` |
| Design tokens / colors / type | `docs/handoff/DESIGN-SYSTEM.md`, `app/tailwind.config.js`, `app/src/styles/*` |
| Multi-step flows (modals/wizards) | `docs/handoff/FLOW-INVENTORY.md` + `FLOW-INVENTORY-Addendum.md` |
| User journeys (which screens compose a flow) | `docs/handoff/USER-FLOWS.md` |
