# FRONTEND-COMPLETION-AUDIT.md

> **Scope:** prototype frontend only. No API verification, no backend work, no code changes.
> **Date:** post-R8 (HR + Retail + Dine + Accounting refactors landed).
> **Method:** scan of `app/src/app/{App,nav.config}.jsx`, every `app/src/modules/*` file, every shared `app/src/components/*`, cross-referenced against `docs/handoff/MISSING-SCREENS-INVENTORY.md`, `MODULE-MAP.md`, `SCREENS-INVENTORY-*.md`.
> **Purpose:** identify what's done, what's shallow, what's missing, and what's safe to do next.

---

## §1 — Completed modules

A "completed module" here means: the route exists, the page renders, KPI/list/filter UX is in place, the module shell is split into per-tab files, and bilingual coverage is complete inside the module. **It does NOT mean detail drawers, mutations, or backend wiring are done** — those are tracked as gaps below.

| Module | Route | Shell file | Sub-pages | Status | Notes |
|---|---|---|---|---|---|
| **Auth** | `/login` | `auth/LoginPage.jsx` | — | ✅ Done | Demo-account quick-fill works. |
| **Dashboard** | `/` | `dashboard/DashboardPage.jsx` | — | ⚠️ Shallow | 4 hardcoded KPIs + "Detailed dashboards land in the next iteration." card. Placeholder only. |
| **Platform · Tenants** | `/platform/tenants` | `platform/TenantsPage.jsx` | — | ✅ Done | KPI strip + filter bar + paginated list + drawer. Reference pattern for the workspace modules. |
| **Platform · Signups** | `/platform/signups` | `platform/SignupsPage.jsx` | — | ✅ Done | Approve/reject mutations wired. |
| **Platform · Onboarding** | `/platform/onboarding` | `platform/OnboardingPage.jsx` | — | ✅ Done | Nudge mutation wired. |
| **Platform · Plans** | `/platform/plans` | `platform/PlansPage.jsx` | — | ✅ Done | Read-only catalog; "New plan" is dead. |
| **Platform · Billing** | `/platform/billing` | `platform/BillingPage.jsx` | — | ✅ Done | Read-only list + drawer. |
| **Platform · Support** | `/platform/support` | `platform/SupportPage.jsx` | — | ✅ Done | Re-assign + Resolve mutations wired; ticket conversation has hardcoded English seed copy. |
| **Platform · Health** | `/platform/health` | `platform/HealthPage.jsx` | — | ✅ Done | Read-only. |
| **Platform · Compliance** | `/platform/compliance` | `platform/CompliancePage.jsx` | — | ✅ Done | Read-only; "Run scan" dead. |
| **Platform · Incidents** | `/platform/incidents` | `platform/IncidentsPage.jsx` | — | ✅ Done | Read-only timeline. |
| **Platform · Releases** | `/platform/releases` | `platform/ReleasesPage.jsx` | — | ✅ Done | Read-only. |
| **Platform · Audit** | `/platform/audit` | `platform/AuditPage.jsx` | — | ✅ Done | Read-only; "Verify chain" dead. |
| **HR** | `/hr` | `hr/HRPage.jsx` | Staff · Leave · Attendance · Payroll | ✅ Done (R5) | Leave approve/reject wired; rest read-only. |
| **Retail** | `/retail` | `retail/RetailPage.jsx` | Sales · Products · Inventory · Customers · Suppliers | ✅ Done (R6) | All read-only after refactor. |
| **Dine-in** | `/dine` | `dine/DinePage.jsx` | Floor · Kitchen · Menu | ✅ Done (R7) | KDS auto-refresh wired; mutations TBD. |
| **Accounting** | `/accounting` | `accounting/AccountingPage.jsx` | Reports · Invoices · Bills · VAT · COA | ✅ Done (R8) | All read-only. |

**Total routes mounted:** 17 (1 auth + 1 dashboard + 11 platform + 4 workspace).

---

## §2 — Missing modules / pages

### §2.1 — Modules referenced in handoff docs but absent from the prototype

These are top-level capabilities catalogued in `MISSING-SCREENS-INVENTORY.md` and the various `SCREENS-INVENTORY-*.md` documents that have **no route, no nav entry, and no module folder** in `app/src/modules/`. They are not currently expected for V1.0 of the prototype unless flagged otherwise.

| Module | Inventory ref | Priority | Why it matters |
|---|---|---|---|
| **CRM / Customer 360** | `MS-CRM-001`, `MS-CRM-002` | ⚠️ V1.0 HIGH | The customer drawer in Retail and Accounting are siloed views; there's no unified Profile / Sales / AR / Statements / Loyalty / Tickets surface. |
| **Loyalty** | `MS-RETAIL-001`, `MS-CRM-003` | ⚠️ V1.0 HIGH | No Programs / Tiers / Members / Settings tabs anywhere. |
| **Gift cards** | `MS-RETAIL-002` | 📌 V1.0 NICE | No issuance UI. |
| **Promotions** | `MS-RETAIL-003` | ⚠️ V1.0 HIGH | No builder; POS has no source-of-truth for promos. |
| **Pricing / Price lists** | `MS-RETAIL-004` | 📌 V1.0 NICE | No multi-tier pricing surface. |
| **Inter-branch transfers** | `MS-RETAIL-006` | ⚠️ V1.0 HIGH | Inventory page shows on-hand only; no dispatch / receive / variance flow. |
| **Pay / Settlements** | `MS-PAY-001`, `MS-PAY-002`, `MS-PAY-003` | ⚠️ V1.0 HIGH | No Pay module exists; settlements + reconciliation absent. |
| **ATS / Recruit** | `MS-HR-001`, `MS-HR-002` | ⚠️ V1.0 HIGH | No Jobs / Candidates board. |
| **Org chart** | `MS-HR-009` | ⚠️ V1.0 HIGH | No tree view. |
| **EOSB calculator** | `MS-HR-010` | ⚠️ V1.0 HIGH | KSA labour-law accrual surface absent. |
| **HR Helpdesk** | `MS-HR-008` | 📌 V1.0 NICE | Tickets surface absent. |
| **Expense claims** | `MS-HR-005` | ⚠️ V1.0 HIGH | Submission + approval flow absent. |
| **Loans / Performance / Assets / Learning** | `MS-HR-003/004/006/007` | 🗓️ V1.1 | Defer per Mohammed's roadmap. |
| **Year-end close** | `MS-ACCT-008` | ⚠️ V1.0 HIGH | No ceremony wizard. |
| **Recurring JEs** | `MS-ACCT-004` | 📌 V1.0 NICE | No sub-tab in accounting. |
| **Credit / Debit notes** | `MS-ACCT-005`, `MS-ACCT-006` | ⚠️ V1.0 HIGH | No issuance UI. |
| **Customer write-off** | `MS-ACCT-007` | ⚠️ V1.0 HIGH | No action button. |
| **Customer statement PDFs** | `MS-ACCT-003` | ⚠️ V1.0 HIGH | No tab in customer drawer. |
| **CoA Industry Profile picker** | `MS-ACCT-002` | ⚠️ V1.0 HIGH | Onboarding gap; CoA seeded from generic template only. |
| **Cashflow report** | `MS-ACCT-001` | ⚠️ V1.0 HIGH | Reports tab shows P&L / BS only — Cashflow card is a placeholder summary. |
| **VAT codes / Tax codes management** | `MS-ACCT-011` | ⚠️ V1.0 HIGH | No settings surface. |
| **Multi-currency FX** | `MS-ACCT-010` | 🗓️ V1.1 | Defer. |
| **Accounting audit drill** | `MS-ACCT-009` | 🗓️ V1.1 | Defer. |
| **Reconciliation deep-dive** | `MS-PAY-003` | ⚠️ V1.0 HIGH | No bank-statement match workbench. |

### §2.2 — Subpages missing inside modules that DO exist

| Module | Missing tab/page | Notes |
|---|---|---|
| Dine | **Reservations** | Floor + KDS + Menu only. Reservations book is absent. |
| Dine | **Recipes / BOM** | Menu page lists items; no recipe yield/cost surface. |
| Retail | **Returns / Refunds** | Sales is read-only feed; no return flow. |
| Retail | **Stock takes / Counts** | Inventory shows on-hand; no count cycle. |
| Retail | **Purchase orders** | Suppliers tab shows on-time %; no PO list/builder. |
| HR | **Documents / Contracts** | Staff page has no contracts/passport/iqama document store. |
| HR | **Shifts / Roster** | Attendance shows live shifts; no roster planning. |
| Accounting | **Journal / Manual JEs** | No journal page at all (recurring JEs would be a sub-tab of it). |
| Accounting | **Banking / Bank statements** | No bank import or statement-line matching. |
| Accounting | **Fixed assets** | Absent. |
| Accounting | **Settings** (fiscal calendar, tax codes, FX, company profile, notifications) | Absent — Batch 1 covered these in the legacy prototype, not in `app/`. |
| Dashboard | **All real content** | Shell + 4 hardcoded KPIs + "next iteration" card. |

---

## §3 — Pages that exist but are too shallow

These render and pass the eye-test but are missing the second layer (drawers, mutations, drilldown). They will cause "this looks done but does nothing" demo bugs.

| Page | What's shallow |
|---|---|
| **DashboardPage** | 4 hardcoded SAR/count KPIs with no fetch; explicit "Detailed dashboards land in the next iteration." card. Whole page is a stub. |
| **HR / StaffPage** | List + filter only. No employee drawer, no edit, no role/branch mutation, no document store. |
| **HR / AttendancePage** | Live shifts list. No clock-in/out action, no shift detail, no week view. |
| **HR / PayrollPage** | Run list. No run detail / line items / WPS file generation / payslip preview. |
| **Retail / SalesPage** | Live POS receipt feed. No receipt drawer, no refund/void, no day-close. |
| **Retail / ProductsPage** | List + margin coloring. No product drawer, no variants, no barcode/sku edit, no category management. |
| **Retail / InventoryPage** | On-hand grid. No adjustments, no transfers, no reorder rules. |
| **Retail / CustomersPage** | List + LTV. No customer drawer (the Customer-360 gap above lives here). |
| **Retail / SuppliersPage** | List + on-time %. No supplier drawer, no POs, no payment performance. |
| **Dine / FloorPage** | Status grid. No table drawer, no order, no transfer, no merge/split. |
| **Dine / KDSPage** | Tickets with item-level dots. No bump/recall, no fire-by-course, no station filter. |
| **Dine / MenuPage** | List + margin. No item drawer, no recipe, no 86 toggle. |
| **Accounting / ReportsPage** | 3 summary cards. No period switcher, no drilldown, no export. |
| **Accounting / InvoicesPage** | List + filters. No invoice drawer, no line-items, no ZATCA QR, no payments, no Mark-paid. |
| **Accounting / BillsPage** | List + filters. No bill drawer, no payment schedule, no Pay-bill action. |
| **Accounting / VatPage** | Quarter cards. No source drilldown, no draft form, no submit. |
| **Accounting / CoaPage** | Flat list. No tree, no account drawer, no GL ledger view. |
| **Platform / SupportPage** | Drawer renders a fake conversation with hardcoded English seed copy ("POS receipt printer not detected after macOS Sonoma update…"). Functional but content is non-bilingual stub copy. |

---

## §4 — Dead buttons and actions

Buttons that render but have no `onClick` / no mutation wired. Found by scanning every `<Button>` in the modules.

### Module shell action buttons (top-right of every workspace + most platform pages)

| Page | Dead buttons |
|---|---|
| `HRPage.jsx` (shell) | **Export**, **Add employee** |
| `RetailPage.jsx` (shell) | **Export**, **New product** |
| `DinePage.jsx` (shell) | **Export**, **New order** |
| `AccountingPage.jsx` (shell) | **Export**, **New invoice** |
| `TenantsPage` | **Export**, **New tenant** |
| `SignupsPage` | **Export** |
| `OnboardingPage` | **Funnel report** |
| `PlansPage` | **Pricing history**, **New plan** |
| `BillingPage` | **Export CSV**, **Manual invoice** |
| `SupportPage` | **Macros**, **New ticket** |
| `HealthPage` | **Status page** *(Refresh works)* |
| `CompliancePage` | **Audit pack**, **Run scan** |
| `AuditPage` | **Export · 24h**, **Verify chain** |

### Non-shell dead actions

| Page | Dead button | Comment |
|---|---|---|
| `LeavePage` | (none — approve/reject wired) | |
| `KDSPage` | bump/recall ticket | not even drawn yet |
| `FloorPage` | open/close table, new order on table | not drawn |
| `InvoicesPage` | mark paid, send, void | not drawn |
| `BillsPage` | pay, schedule, attach | not drawn |
| `VatPage` | submit, file, drill | not drawn |
| `CoaPage` | open ledger, edit account | rows not clickable |

**Summary:** every module shell ships with a "primary" + "secondary" action that does nothing. This is the single highest-visibility UX bug remaining — it's the first thing a demo viewer clicks.

---

## §5 — Unused / dead components and files

Found by `grep` across `app/src/`.

| File | Why flagged | Recommend |
|---|---|---|
| `app/src/modules/_stubs/ComingSoon.jsx` | Zero imports anywhere (`grep` returns only its own definition). Was a placeholder for absent modules; all four workspace modules now use real shells. | **Delete after R10 onwards** if no module reverts to placeholder state. |
| `app/src/components/Tabs.jsx` | Removed from all four workspace modules in R5–R8 (replaced by URL-driven `NavLink` strip). Need a final confirm-grep before removal — platform pages use inline filter pills rather than `Tabs`. | **Confirm zero imports, then delete.** |
| `app/src/components/Toolbar.jsx` | Old combined search + chips + actions row. Superseded by `FilterBar` (R4). | **Confirm zero imports, then delete.** |
| `app/src/components/StatCard.jsx` | Older stat tile. Superseded by `KPI` (R4). Platform pages still import the older `KPI` from somewhere — confirm both don't co-exist. | **Confirm zero imports, then delete.** |
| `app/src/modules/_stubs/` directory | Contains only `ComingSoon.jsx`. Empty after that goes. | **Remove directory once contents deleted.** |

> **Rule per audit instructions:** do **NOT** delete in this batch. Items above are recommendations for a future cleanup pass. Run a `grep <Component>` confirm-pass before each removal.

---

## §6 — Remaining hardcoded English text

Scan limited to `app/src/modules/platform/*` (the workspace modules were swept clean during R5–R8).

### High-impact (visible on every render)

| File | Line(s) | English string |
|---|---|---|
| `platform/SignupsPage.jsx` | 82–86 | `KPI label="Total"`, `"Verified"`, `"In review"`, `"Pending"`, `"Avg score"` |
| `platform/SignupsPage.jsx` | 138 | reject reason fallback `'Not specified'` (sent to API; arguably ok but not localised) |
| `platform/SignupsPage.jsx` | 204–205 | `<ReadinessRow label="Commercial Registration (CR)" />`, `"VAT registration"` |
| `platform/SupportPage.jsx` | 78–83 | `KPI label="Open"`, `"In progress"`, `"Urgent"`, `"Breached"`, `"CSAT · 30d"`, `"First response p50"` |
| `platform/SupportPage.jsx` | 150–151 | Hardcoded conversation seed ("POS receipt printer not detected after macOS Sonoma update…", "Looking into this — could you share the printer model…") |
| `platform/BillingPage.jsx` | 73–77 | `KPI label="MRR"`, `"ARR"`, `"Paid"`, `"Overdue"`, `"Collection rate"` |
| `platform/OnboardingPage.jsx` | 52–55 | `KPI label="In progress"`, `"Stuck (≥3d)"`, `"At risk"`, `"Avg steps done"` |
| `platform/IncidentsPage.jsx` | 43–46 | `KPI label="Total · 30d"`, `"Active"`, `"SEV1/SEV2"`, `"MTTR · 30d"` |
| `platform/AuditPage.jsx` | 54–57 | `KPI label="Events · 24h"`, `"High severity"`, `"Impersonations · 24h"`, `"Unique actors · 24h"` |
| `platform/ReleasesPage.jsx` | 36–39 | `KPI label="Shipped · 30d"`, `"Rolling now"`, `"Rolled back"`, `"Change failure rate"` |

### Lower-impact

| File | Issue |
|---|---|
| `platform/SignupsPage.jsx` (filter pills l. 173) | `{o}` rendered raw — pill shows raw enum keys (`pending`, `verified`) regardless of locale. |
| `platform/SupportPage.jsx` (filter pills l. 185) | Same — `{o.replace('_', ' ')}`. |
| `platform/AuditPage.jsx` (filter pills l. 146) | Same. |
| `platform/IncidentsPage.jsx` (filter pills l. 171) | Same. |
| `platform/BillingPage.jsx` (filter pills l. 106) | Same. |
| `platform/OnboardingPage.jsx` (channel buttons l. 107) | `email`, `sms`, `whatsapp` rendered raw. |
| `dashboard/DashboardPage.jsx` | KPI labels all bilingual already; "Detailed dashboards…" card both locales. ✅ ok. |

**Pattern:** the workspace refactor (R5–R8) routed every label through `useT()`. The platform module never went through that pass — every KPI strip and every filter-pill row is raw English. Estimate: ~50 strings across 8 platform files. Mechanical fix; no design work needed.

---

## §7 — Responsive issues

Scan: every page reads as 1-column on mobile via Tailwind's default flow, but several have density / overflow problems below `md`.

| Page | Issue |
|---|---|
| **Module shells (HR/Retail/Dine/Accounting)** | Tab strip `overflow-x-auto whitespace-nowrap` works, but the right-side action buttons in `PageHeader` collide with a long title in Arabic. R4 fixed `PageHeader` to stack at < `sm`; verify with the longest Arabic kicker + title combo. |
| **Platform pages (all 11)** | Use raw `<div className="grid grid-cols-2 md:grid-cols-N gap-3">` for KPIs — works, but they're not using the new `KPIGrid` component. No mobile card-collapse on their `Table` lists either; horizontal scroll on phones. |
| **`SupportPage`** | KPI grid is `grid-cols-2 md:grid-cols-6` — on tablets between `md` and `lg`, 6 columns are cramped. Should step `1 → 2 → 3 → 6`. |
| **`AccountingPage / ReportsPage`** | 3 cards full-width on phones is fine, but card height jumps because the values inside vary in width — minor. |
| **`Dine / FloorPage`** | Table cards grouped by zone are `flex-wrap`; on very narrow viewports cards collide with zone headers. |
| **`Dine / KDSPage`** | Ticket grid is fixed-width per ticket; on phones tickets clip at 2-column. Acceptable for KDS (rarely viewed on phones) but flag. |
| **`Retail / InventoryPage`** | Per-branch on-hand columns multiply table width; no card-collapse fallback. Worst offender on mobile. |
| **All platform `Table` lists** | Predates the new `ResponsiveList`; horizontal scroll on phones. |
| **`AppShell` sidebar** | Confirm RTL flip works for both directions of the chevron in collapsed mode (out of audit scope but worth flagging). |

---

## §8 — Next safest batch (R9 candidate)

The audit's recommendation for the **lowest-risk, highest-visibility** next batch. No new modules, no new endpoints, no design system work — purely closing gaps in what already ships.

### R9 — "Workspace polish + platform parity" (recommended)

1. **Wire the dead "Export" + primary-action buttons** in the four workspace shells (`HRPage`, `RetailPage`, `DinePage`, `AccountingPage`). Either:
   - hide them (cheapest), or
   - turn them into stub-toast handlers (`toast.info("Export coming in v1.1")`), or
   - launch a "coming soon" sheet via the existing `ComingSoon` empty state.
2. **Localise the platform KPI strips and filter pills** (~50 strings, mechanical). Brings platform pages to bilingual parity with workspace pages.
3. **Migrate platform pages to `KPIGrid` + `FilterBar` + `ResponsiveList` + `Pagination`** (built in R4, unused outside the workspace modules). Removes hand-rolled grids, gets mobile card-collapse for free, gets pagination for free. Platform pages already follow the same KPI-strip → filter-bar → table shape, so this is a 1-for-1 swap per file.
4. **Replace the hardcoded English conversation seed in `SupportPage`** with a bilingual fixture pair, or hide the whole bubble area when no conversation is loaded.

### Why this batch is safe

- **No new modules, no new routes, no nav.config edits.**
- **Every change has a precedent** (R4 shipped the primitives; R5–R8 demonstrated the migration on workspace).
- **Zero backend dependency** — platform pages already hit their endpoints; we're just changing how their results render.
- **Reversible** — primitive swaps are 1-for-1 and the old grids/filter rows can be reinstated via git if anything looks off.

### Why NOT to start a new module yet

R10+ should pick **one** new module from §2.1 to build out (CRM Customer-360 is the strongest candidate — most cited cross-module gap). But starting a new module while platform pages still ship raw English KPIs and 12 dead buttons would be premature.

---

## §9 — Files recommended for cleanup (do NOT delete yet)

Per audit instructions, no deletions. List for the future cleanup pass:

1. `app/src/modules/_stubs/ComingSoon.jsx` — unused after the four workspace modules shipped; verify-grep before removing.
2. `app/src/modules/_stubs/` directory — empty once `ComingSoon.jsx` is gone.
3. `app/src/components/Tabs.jsx` — replaced by `NavLink` strips in workspace; verify no platform page imports it.
4. `app/src/components/Toolbar.jsx` — superseded by `FilterBar`; verify no imports.
5. `app/src/components/StatCard.jsx` — superseded by `KPI`; verify no imports.

---

## §10 — UX gaps to fix later

Items that are not blocking but degrade the prototype's "feels finished" quality. None of these are bugs in shipped code; they are missing affordances.

### Detail drawers (single biggest gap)

Every list in §3 needs a detail drawer. Today, every row is non-clickable in:
- HR: Staff, Attendance, Payroll
- Retail: Sales receipts, Products, Customers, Suppliers
- Dine: Tables, Tickets, Menu items
- Accounting: Invoices, Bills, COA accounts, VAT periods

This is the same gap surfaced page-by-page in §3. Treat as a single program: **"open a drawer when you click a row"** is the next big UX uplift.

### Empty / loading / error parity

`Table` and `ResponsiveList` ship a generic "Loading…" / empty fallback via `useT()`. Several lists pre-date this and have inline messages that aren't bilingual:

- `IncidentsPage` line 68: hardcoded "No incidents match the filter." with Arabic via inline `t()` — ✅ ok, false alarm.
- Most of the others use the new `ResponsiveList` — ✅ ok.
- Worth a sweep to confirm.

### Action consequences

When mutations land (R10+ on workspace), they should:
- Toast on success/failure (no toast primitive exists in `app/src/components/` — check before R10).
- Optimistically update React Query caches so the row reflects the new state before the refetch completes.
- Surface a permission-denied state explicitly when the user lacks the granular permission (today the button just no-ops).

### Right-to-left polish

- KPIs rendered with raw `+` / `−` deltas read awkwardly in Arabic — should use logical-direction signs.
- `SupportPage` conversation bubbles use `text-left` literals — won't flip in RTL until they go through a polish pass.
- `OnboardingPage` channel cards (email/sms/whatsapp) are raw lowercase English regardless of locale.

### Density / breathing room

- Module shell `PageHeader` spacing is comfortable on desktop but tight on tablet (~`md` to `lg`). Consider a tighter `kicker` line-height in the bilingual `t(en, ar)` two-line case.
- KPI tiles render differently when the value is very long (e.g. `formatSAR` on millions). `KPI` component should support a `size="sm"` variant for crowded strips.

### Filter consistency

Three different filter-pill components ship across the codebase:
- `FilterChip` / `FilterBar` (used in workspace, R4) — ✅ canonical.
- Inline `<button>` pill row in 6 platform pages — should migrate.
- The ad-hoc 2-button toggle in `PlansPage` (monthly/yearly) — should migrate too.

This is part of R9 §8.3 above.

### Keyboard nav

Not exercised anywhere — module shell tab strip is `NavLink` (keyboard-traversable), but lists and drawers have no `aria-*` or focus management. Defer to v1.1.

---

## §11 — Summary / call to action

| Question | Answer |
|---|---|
| **What's done?** | 17 routes mounted; 4 workspace modules refactored to URL-driven shells with consistent KPI/filter/table primitives; 11 platform pages render with permissions + reads. |
| **What's shallow?** | Every list in every module — clicking a row does nothing. Dashboard is a stub. |
| **What's missing?** | An entire CRM module, Loyalty, Promotions, Pay/Settlements, ATS, Org chart, Year-end close, Recurring JEs, Customer statements, CoA profile picker, Cashflow report, Tax codes, Reconciliation. (See `MISSING-SCREENS-INVENTORY.md` for the full 40+ list.) |
| **What are the dead buttons?** | At least 13 module-shell action buttons + every list-row mutation. Highest-visibility cleanup target. |
| **What unused code can go?** | `ComingSoon.jsx`, `Tabs.jsx`, `Toolbar.jsx`, `StatCard.jsx` (all pending verify-grep). |
| **Where is English still hardcoded?** | All 11 platform-page KPI strips + filter pills (~50 strings); SupportPage conversation seed. Workspace is clean. |
| **What's the safe next batch?** | R9 — wire dead module-shell buttons (or hide them), localise platform KPIs/pills, migrate platform pages to R4 primitives. No new modules. |
| **What's the first new module to consider after that?** | **CRM Customer-360** (`MS-CRM-001`) — touches Retail + Accounting, fixes the most cited cross-module gap, demos well, no new endpoints needed. |

---

*End of audit. No code, deletions, or backend changes performed in this batch.*
