# Admin (backend) ⇄ Demo parity audit — NEW surfaces + style

**Date:** 2026-07-07 · **Demo:** `Navagoo_MI` v0.19 (`src/portals/admin/*`, `src/App.tsx` admin routes, `ADMIN_NAV` in `src/portals/nav.ts`) · **Ours:** `backend/` (Yii2 admin tier, `backend.navagoo.localhost`).

**Method.** Enumerated the demo admin nav + every admin route from source; drove the running demo as **USR‑1 (Super Admin)** and captured each admin page's real content (Home, Dashboard, P&L, Costs, Events, Users & Roles, Subscriptions). Mapped each against `backend/controllers/*`, `backend/views/*`, the nav (`backend/views/layouts/menu/Menu.php`) and the admin chrome (`backend/views/layouts/tailwind.php` + `_tw_admin_sidebar.php` + `_tw_admin_navbar.php`). Backend browser screenshots were **not** taken — the admin password is stale (`password_verify` = false); comparison of the backend is code/DB‑level. Say the word and I'll browser‑verify once you give me the current admin password.

---

## ✅ EXECUTION STATUS (2026-07-07) — waves 1–7 + turquoise built

The user greenlit **all waves + turquoise chrome**. Built & verified (lint + live-data
service probes + a boot-the-web-app render probe that logs in an admin without a password
and scans each route's HTML — the backend admin password is stale, so browser screenshots
are still pending the current password):

| Wave | Built | Route(s) | Verify |
|---|---|---|---|
| 1 · Costs (COGS) | `navagoo_cost` table + seed (demo DEFAULT_COST_LINES) · `NavagooCost` model · `CostController` · `views/cost/index.php` (editable register, 8 bases, add/remove/toggle) | `/cost/index` | migrate OK · 11 seed rows match demo · render 82KB |
| 2 · Platform P&L | `PlatformPnlService` (revenue = shop_earning marketing + charge processing/subscription/notifications; COGS = register × drivers; margin + compare + trend) · `AnalyticsController` · `views/analytics/index.php` (4 KPIs + statement + Chart.js) | `/analytics/index` | live probe: this-month margin **71.7%** · render 47KB |
| 3 · Dashboard BI | `PlatformBiService` (gmv/bookings/no-show/byCity/funnel/perf/flags) · `DashboardController` · `views/dashboard/index.php` (5 tabs Overview/Volumes/Performance/Financials/Flags + charts) | `/dashboard/index` | live probe sane · render 58KB |
| 4 · Home | `SubscriptionMetricsService` (MRR/at-risk/pulse) · `views/site/_subscription_pulse.php` + SiteController wiring (admin-only band + attention feed) | `/` (site/index) | render 87KB |
| 5 · Events | `TimelineEventController::actionAudit` + `actionAuditCsv` · `views/timeline-event/audit.php` (filters surface/actor/category/date + CSV) over `timeline_event` | `/timeline-event/audit` | render 82KB · CSV 17KB |
| 6 · Users & Roles | `UsersRolesController` · `views/users-roles/index.php` (Users tab + Roles & Access matrix over real RBAC — read-only; edit links to Managers) | `/users-roles/index` | render 42KB |
| 7 · Subscriptions tabs | `ShopController::actionOffers` (+activate/end) + `actionPaymentMethods` · `views/shop/{offers,payment_methods}.php` · 2 new tabs in `shop/_tabs.php` | `/shop/offers`, `/shop/payment-methods` | render 38KB / 36KB |
| 8a · Turquoise chrome | admin `bg-side/head-admin` gradients slate→indigo ⟶ **near-black→turquoise** (`#160f20→#15bccb`) + `cyanbrand #4aa6b5` (demo v0.19) | all admin | `#15bccb` present in rendered HTML |

Menu: **Home + Dashboard** top; **Platform P&L + Costs (COGS)** in the Money area; **Events + Users & Roles** in System; **Offers + Payment methods** tabs in the Shop area. Bilingual ar+en added for every new key (i18n hook green). All 8 routes render clean.

**✅ VISUAL QA DONE (2026-07-07).** User authorised a local-dev admin password reset (`admin` / `NavAdmin!2026`, id 1). Logged into `backend.navagoo.localhost`, screenshotted all 8 surfaces — every page renders correctly on the **turquoise chrome** with live data: Home (MRR SAR 0 / at-risk SAR 251.25 + attention feed 18), Dashboard (6 KPIs + deltas + trend chart + 5 working tabs), P&L (**margin 71.7%** + full statement), Costs (interactive register, basis toggles, On/Off), Events (filters + CSV + colored surface badges + real signup events), Users & Roles (admin=All / manager=0 matrix), Offers (Eid 5% / Founding Partner 10% · 1/50 enrolled), Payment methods (Card + Bank transfer).
- **BUG CAUGHT & FIXED:** the Dashboard inline `<script>` had a missing `}` in the overview chart config → the whole IIFE silently failed (no chart, dead tabs). The HTML-only render probe missed it; caught by browser + `node --check`. **New verify step:** `node --check` every view's inline JS (extract `<script>`, strip `<?= ?>`). All 8 views now pass.

**⏳ REMAINING (optional, teed up):**
- **8b — move backend admin off the Tailwind Play CDN to a built bundle.** A proper infra task (backend tailwind src + content globs over all admin views + build script + swap the CDN `<script>`). Now visually verifiable, but sizeable + orthogonal to parity — recommend as a dedicated follow-up.
- **8c — nav section headers** (Operations/Money/Growth/System). Items are already placed contextually + reachable; a full IA reorg of the permission-gated `Menu.php` is cosmetic + risky. Optional.

---

## Verdict

The backend admin is **broad and already ~90% Tailwind‑reskinned** (51 of 55 controllers render in the new slate/indigo `tailwind` layout; only `Backend/Contact/Helper/SignIn` are still AdminLTE). Almost every demo admin surface has a real backend counterpart. The gap is a **coherent net‑new financial‑BI cluster** the demo added and we have **zero** of:

> **Costs (COGS) → Platform P&L → Gross‑Margin BI → subscription‑aware Home.**

Plus 3 surfaces that exist but in an **older/split shape** (Events, Users & Roles, Subscription‑Plans tabs), and a handful of **style deltas** (chrome accent, still‑on‑CDN, nav IA).

---

## 1 · Nav parity matrix (17 demo admin items)

Demo `ADMIN_NAV` order → backend counterpart. Legend: ✅ have · ⚠️ partial/older shape · ❌ missing.

| # | Demo admin | Backend counterpart | Status |
|---|---|---|---|
| 1 | **Home** (KPI + attention landing) | `SiteController::actionIndex` → `views/site/index.php` (Tailwind dashboard) | ⚠️ overlaps, but no MRR/subs‑pulse or attention‑feed framing |
| 2 | **Dashboard** (Platform BI, 5 tabs) | same `site/index.php` (single dashboard, range filter) | ⚠️ has GMV/earnings/booking‑summary/refunds/transfers; **no COGS/margin, no tabs, no compare‑delta** |
| 3 | Shops `[Operations]` | `ShopController` | ✅ |
| 4 | Bookings | `BookingController` + `ExtendedBookingController` | ✅ |
| 5 | People | `AgentController` (specialists) + `UserController` (customers) | ✅ (split) |
| 6 | Finance `[Money]` (5 tabs) | `FinanceController`/`AdminFinance`/`Withdrawal`/`AdminInvoice`/`AdminCharge`/`CommercialConfig` | ✅ (built to demo tabs) |
| 7 | **P&L** (Analytics — Revenue − COGS) | — | ❌ **MISSING entirely** |
| 8 | **Costs** (COGS register) | — | ❌ **MISSING entirely** |
| 9 | Subscription Plans (4 tabs) | `ShopController::plans` + `::subscriptions` | ⚠️ Plans + Subs built; **no Offers tab, no Payment‑methods tab** in the admin surface |
| 10 | Catalogue | `ShopCategoryController::catalogue` + `Category`/`Service`/`Skill` | ✅ |
| 11 | Notifications | `NotificationTriggerController` + `PushNotificationController` | ✅ |
| 12 | Geography | `GovernmentController` + `CityController` + `DistrictController` | ✅ |
| 13 | Marketing `[Growth]` | `MarketingController` + `AdsController` + `PromoCodeController` | ✅ |
| 14 | Support & Content | `FaqController` + `PageController` + `ContactUsController` + `TechnicalSupportController` + `QuestionsController` | ✅ |
| 15 | **Events** `[System]` (unified audit log) | `TimelineEventController` + `SystemLogController` (two separate) | ⚠️ split; no surface/actor/target filters + CSV in one log |
| 16 | **Users & Roles** (access matrix) | `UserController` + `ManagersController` (+ `checkMenuPermissions`, RBAC) | ⚠️ per‑manager CRUD form; **no role catalogue / permission matrix UI** |
| 17 | Settings | `SettingsController` | ✅ |

**Score:** 10 ✅ · 5 ⚠️ · **2 ❌ net‑new missing** (P&L, Costs).

---

## 2 · The net‑new cluster (build target)

These four form one feature: define platform **costs**, subtract them from **revenue** for a **P&L**, surface **gross margin** on the dashboard, and frame **Home** around subscription health. Backend has **none** of the COGS/margin dimension because it has no cost register.

### 2a · Costs (COGS) — `#/admin/costs` — ❌ MISSING
> *"Navagoo's cost of goods sold. Drives the platform P&L; never touches charges billed to shops."*
- Editable **cost register**: each line has a **basis** that scales into a period cost — `Fixed/month`, `Fixed/year`, `Per booking`, `Per SMS`, `Per WhatsApp`, `Per online txn (% + fixed)`, `Per bank transfer`, `Per active shop/month`.
- Add cost / Save costs; lines flagged **"assumed"** until a real backend feed replaces the estimate.
- **Needs a new table** (see §5). Admin/back‑office only — does **not** touch the shared `api/` tier.

### 2b · Platform P&L — `#/admin/analytics` — ❌ MISSING
> *"Revenue minus cost of goods sold (COGS). Read‑only."*
- KPIs (demo live values): **Revenue SAR 19,284.74** · **COGS SAR 8,505.38** · **Gross Margin +SAR 10,779.36** · **Margin 55.9%**, each with a period‑over‑period delta.
- **P&L statement** table — revenue lines (Marketing fees, Payment processing, Notifications SMS/WA, **Subscriptions**, Total) and cost lines (Paymob processing, SMS, WhatsApp, Google Maps API…), + a trend chart.
- Pure **read‑only aggregation** over the existing ledger (`shop_earning`, `charge`, `invoice`, subscriptions) **minus** the §2a cost register — **no schema change**.

### 2c · Dashboard → Platform BI — ⚠️ upgrade `site/index.php`
- Demo tabs: **Overview / Volumes / Performance / Financials / Flags**; period ranges + **compare‑to‑prior** deltas.
- KPIs incl. **Gross Margin** and **No‑show rate ≤ 5% target**; **Flags** queue (freeze list, past‑due/expired subs, open refund cases, pending settlement requests) — a work‑queue we partly have as separate cards.
- Ours already computes Platform GMV, Navagoo Earnings, realised fees, active shops, booking‑status summary, refund cases, transfer requests → add COGS/margin + the tab shell + compare‑delta.

### 2d · Home → subscription‑aware — ⚠️ upgrade `site/index.php`
- Demo Home adds a greeting + digest line + **MRR / at‑risk MRR / subs‑pulse**, settlement liability, outstanding receivables, Navagoo earnings MTD, money‑in‑motion, top‑shops‑this‑week, and an **attention feed** ("8 items need attention").
- Ours has the money KPIs; missing the **subscription** framing + attention feed.

---

## 3 · Exists but older/different shape

- **Events** (⚠️). Demo = one **read‑only platform audit log**: filters (surface: admin/shop/customer/specialist/system · actor · shop · target · date range) + **Export CSV**, columns `TIME/SURFACE/ACTION/ACTOR/TARGET/MESSAGE`. Ours = two separate legacy screens (`TimelineEvent`, `SystemLog`). Consolidation, not net‑new data.
- **Users & Roles** (⚠️). Demo = **Users** tab (add user, inline role dropdown, deactivate, last‑active) + **Roles & Access** tab (built‑in + custom roles: Super Admin/Admin/Finance/Support/Owner/Manager/Front Desk, **permission matrix**, users‑per‑role). Ours = `ManagersController` CRUD `_form` + `checkMenuPermissions` + Yii RBAC — functional but **no role catalogue / matrix UI**.
- **Subscription Plans** (⚠️). Demo tabs: **Subscription Plans / Offers / Subscription Dashboard / Payment methods**. Ours has Plans + Subscription Dashboard; **Offers** (`navagoo_offer` exists in DB from the shop wave!) and **Payment methods** are not surfaced admin‑side yet.

---

## 4 · Style comparison (chrome + tokens)

Both sides share the same design system (brand/accent/ink/radii/shadows/fonts ~identical, exactly like the shop audit). Real deltas:

| Dimension | Demo admin | Backend admin | Delta |
|---|---|---|---|
| **Chrome accent** | dark slate → **turquoise/cyan** rail+header (`bg-side/head-admin`: `#160f20 → #244257 → #15bccb`; accent `cyanbrand #4aa6b5`) | dark slate → **indigo** (`#1e293b → #3730a3 → #4f46e5`) | **Different accent hue** — demo went cyan/turquoise; we're indigo. Pick one and align. |
| **CSS delivery** | built Tailwind v4 (`@theme`) | **Tailwind Play CDN** (`cdn.tailwindcss.com`) — layout header literally says *"PROD: swap the CDN for a built stylesheet"* | ❗ Shop already ships a real minified `tailwind.css`; **admin still on the dev CDN** — perf + prod‑blocker. |
| **Content typography** | headers `text-2xl font-bold text-slate-900`, subtitles `text-sm text-slate-500` (slate‑neutral) | brand‑purple `text-ink` / `text-ink-muted` | Minor: demo admin content is slate‑neutral; ours tints purple. |
| **Nav IA** | clean sections **Operations / Money / Growth / System** with a flat, curated item list | legacy AdminLTE tree (`Shop Details`, `Users`, `Category settings`…) re‑rendered in Tailwind from `Menu.php` | Different information architecture; demo groups by business area. |
| **Page shell** | `PageHeader` (title + subtitle) + `TabNav` + `CardHeader(title, subtitle)` + `DataTable` | mixed per‑surface Tailwind panels | Demo has a stricter shared page grammar. |

---

## 5 · ⚠️ Data‑model flag (read before building)

Only **one** new table is required, and it's **admin/back‑office only** — it does **not** touch the shared `api/` tier, so **no mobile‑app risk**:

- **`navagoo_cost`** (or `platform_cost`) — the COGS register: `id, label, basis (enum), amount, pct, fixed, active, sort, assumed (bool), updated_at`. Everything else (P&L, Dashboard BI, Home) is **read‑only aggregation** over existing tables + this register — no other schema change.
- `navagoo_offer` / `shop_offer_enrollment` already exist (built in the shop Navagoo‑Plans wave) → the admin **Offers** tab just needs a surface, no migration.

Per CLAUDE.md I'm flagging this before writing it. Nothing here changes an API contract.

---

## 6 · Recommended waves (if you greenlight the build)

1. **Costs (COGS)** — migration `navagoo_cost` + `NavagooCost` model + `CostController` + register view (mirror the demo bases). *(needs the §5 table — your OK)*
2. **Platform P&L** — `AnalyticsController` + P&L statement view; pure aggregation (ledger − costs). *(no schema)*
3. **Dashboard BI** — add COGS/Gross‑Margin KPIs + Overview/Volumes/Performance/Financials/Flags tabs + compare‑delta to `site/index.php`. *(no schema)*
4. **Home** — subscription‑aware KPIs (MRR/at‑risk) + attention feed. *(no schema)*
5. **Events** — one filterable audit log (+CSV) consolidating `TimelineEvent`+`SystemLog`.
6. **Users & Roles** — role catalogue + permission‑matrix tab over existing RBAC.
7. **Subscriptions** — surface **Offers** + **Payment methods** tabs admin‑side.
8. **Style** — decide chrome accent (turquoise vs indigo), **move admin off the Play CDN to a built bundle**, align nav IA to Operations/Money/Growth/System.

Waves 1–4 are the high‑value net‑new cluster; 5–8 are consolidation + polish. Each is backend‑only and independently shippable.

---

## 7 · Revenue‑mapping validation (C2) + Finance carry‑overs (C3)

**C2 — the P&L revenue mapping is validated (2026‑07‑07).** Reconciled component‑by‑component
against the live DB (all‑time):

| Line | Source | Amount |
|---|---|---|
| Marketing | Σ `shop_earning.navagoo_marketing_fees` | 566.27 |
| Payment processing | Σ `charge.base_amount` type=`processing_fee` (¬reversed/¬pending) | 991.50 |
| Subscriptions | Σ `charge.base_amount` type=`subscription` | 3,015.00 |
| Notifications | Σ `charge.base_amount` type∈`sms,whatsapp` | 0.00 |
| **Total revenue** | | **4,572.77** |

This equals `PlatformPnlService::pnl(all_time).revenue` exactly. Crucially, **`marketing_fee`
charge rows = 0** in the ledger → marketing lives ONLY in `shop_earning`, so reading it there
plus the charge lines is **non‑overlapping (no double‑count)**. The mapping is sound. `per_online_txn`
(Paymob cost) uses online‑paid booking collections (`payment_mode ∈ online,deposit`) + subscription
charges — the intended gateway‑cost basis.

**C3 — shop‑finance carry‑overs (from the earlier Finance review of cash walk‑in booking 980).**
These are SHOP‑portal finance‑display items, distinct from this admin BI build; documented here with
a recommendation rather than changed blind (they touch the tested settlement ledger / a business rule):
1. **Settlement row shows Value 120 / Charges SAR 0.00 / Net −6.00** — doesn't visually reconcile
   because the marketing fee accrues in `shop_earning` and isn't surfaced in the Charges column until
   settlement. *Fix:* surface the accrued marketing fee in the settlement Charges column (display‑only;
   safe once confirmed against the demo).
2. **Walk‑in booking labelled "100% Online"** — a display mislabel for `walk_in_*` bookings. *Fix:*
   label by `booking_method` (display‑only, safe).
3. **Marketing fee charged on a walk‑in booking** — a **business decision**: should Navagoo take a
   marketing commission on a customer who walked in directly (not sourced via Navagoo)? The demo's
   behaviour should be confirmed; if walk‑ins are exempt, that's a `FinanceLedgerService` rule change
   (settlement‑math — needs the owner's call, not a silent edit).

---

*Cross‑refs: existing per‑surface parity specs live in `ai_specs/07_DEMO_PARITY/admin-*` (business/logic/parity/ui). This audit adds the surfaces those folders don't yet cover: **admin‑costs, admin‑analytics(P&L), admin‑events, admin‑users‑roles, admin‑subscriptions, admin‑home**. Shop‑side companion: `SHOP_PORTAL_DESIGN_PARITY_AUDIT.md`.*
