# Admin (backend) ⇄ Demo-admin content parity sweep — v0.28

**Date:** 2026-07-16 · **Demo:** `Navagoo_MI` **v0.28.0** (`src/portals/admin/*`) · **Ours:** `backend/` (Yii2 admin tier).
**Ask:** review all backend admin content and align it to the demo **admin** portal (not the shop portal).
**Method:** 6 parallel code-level reviewers (demo React source ↔ backend controllers/views), + live demo screenshots (admin, `ceo@navagoo.sa`) + live backend screenshots (`admin`). Every finding is re-verified against source before acting (the first pass had one misread — see §Corrections).

Supersedes the surface list in `ADMIN_PORTAL_PARITY_AUDIT_2026_07_07.md` (that was v0.19). Waves 1–8 there are still built; this doc is the **v0.19→v0.28 delta + content-depth gaps**.

---

## Corrections to the raw review
- **Admin Home is NOT contaminated by shop content.** `backend/views/site/index.php` is an `if(!$isShopOwner)…else…` — admins see **only** `_admin_home.php` (line 198–210); the large block at 211–643 is the mutually-exclusive **shop-owner** branch. No bleed. (A reviewer misread the `if/else` as sequential.)

---

## New admin nav items since v0.19 (whole-page gaps)
| Demo | Backend | Note |
|---|---|---|
| **Live chat** (`LiveChat.tsx`) | none | Demo is itself a **"coming soon" preview stub** (amber "Preview" badge). `Conversation`/`Message` controllers are customer↔specialist per-booking chat — a *different* concept, do not repurpose. → add a matching stub page + nav item, OR record as deliberately deferred. |
| **Invitations** (`Invitations.tsx`) | `CustomerInvitationCampaignController` exists | Backend has the approve/reject queue but as ONE flat table; demo splits **Pending approval / History**, expandable per-recipient rows, per-status count badges. |

---

## Prioritized waves

### Wave 1 — Verified safe content fixes (backend views only · no schema · no API)
1. **Home attention feed** — ✅ **DONE 2026-07-16.** `flags()` returns int counts; the partial expected `title`/`description` → 4 blank rows + always-"4 flags" pill. Now `SiteController::buildAttentionItems()` emits titled, deep-linked, severity-sorted rows filtered to count>0; pill shows real total. Verified live (pill "17 items need attention", row "Open refund cases").
2. **Finance / Transfer Requests** — restore fee-breakdown columns (Earned, Tips, Marketing, Processing, Notifications, Fee VAT, Amount Paid); add Tips(+) & Notifications(−) to settle FormulaStrip. `views/admin-finance/transfer-requests.php`, `_settle_modal.php`.
3. **Finance / Shop Balances** — add "Invoiced due" column; confirm `shop-ledger.php` waterfall. `views/admin-finance/shop-balances.php`.
4. **Finance / Charges** — Export CSV + Print PDF + "Pending" status filter + reversal caption. `views/admin-charge/index.php`.
5. **Finance / Commercial Config** — add Subscription-grace-days + Default-trial-days fields. `views/commercial-config/index.php`.
6. **Finance shell** — drop the duplicate per-page h1/subtitle under the single "Finance" header. `_tabs.php` + each tab.
7. **Shops** — branch badge + "branch of {parent}" on shop rows + requests queue; bilingualize the `عملاء المتجر` Type header. `views/shop/index.php`.
8. **Bookings** — add the page subtitle. `views/booking/index.php`.
9. **People** — surface the classification `reason` badge + Classifications card title. `views/user/people.php`.
10. **Notifications** — per-channel status badges + "Shop picks channel / In-app only" label. `views/notification-trigger/_row.php`.
11. **Settings / Workflow** — add 5 missing fields (onTimeStartGraceMin, onTimeFinishGraceMin, customerRescheduleLimit, customerRescheduleFullZoneOnly, packageCancellationsAllowed). `views/settings/workflow.php` + `actionWorkflow`.
12. **Events** — text search + target filter + page-size selector (+ expandable JSON payload row). `views/timeline-event/audit.php`.
13. **Marketing** — add "Shops" push audience. `views/push-notification/index.php`.
14. **Subscription Plans / Payment methods** — make the two toggles real (persist to config) with "≥1 must stay enabled" guard. `views/shop/payment_methods.php`.
15. **Subscription Plans / header copy** — retitle to "Subscription Plans" / "Plans, offers, subscriptions & payment methods". `_tabs.php`.
16. **Catalogue** — Women/Men branch segmented filter + header copy. `views/shop-category/catalogue.php`.

### Wave 2 — Larger UI builds (no schema)
- **Dashboard tabs to parity** — Volumes (KPI row + composed chart + new-vs-returning donut + by-city bar + GMV treemap), Performance (on-time/ABV KPIs + utilization gauges + quality radar + cancel/marketing mix), Financials (KPI row + revenue stacked-area + line-share donut + margin gauge + net-contribution bar + 4 stat tiles), Flags (aging bar + dormant-shops table + money tiles); Overview sparklines + flags strip + refresh control. `views/dashboard/index.php`.
- **Subscription Dashboard** — 3 KPI cards (MRR / Subscribed shops / Offer uptake) + Pending-verifications card (bank-transfer sub invoices → Verify) + Offer & History columns. `views/shop/subscriptions.php`.
- **Offers** — create/edit/delete (OfferModal) + rate-discount charge types on card. `views/shop/offers.php`.
- **Support & Content** — add Policies tab (privacy/terms × customer/business) + FAQ customer/shop audience + expand Contact to 7 channels, editable. `views/faq/support.php`.
- **Invitations** — Pending/History split + expandable recipient rows + per-status count badges.
- **Users & Roles** — interactive permission matrix + Shop/Last-active columns (or keep read-only by explicit decision).
- **Live chat** — preview stub page + nav item (matches the demo stub).

### Wave 3 — ⚠️ SCHEMA / API — FLAG BEFORE BUILDING (per CLAUDE.md)
- **Subscription Plans structured model** — migration on `navagoo_subscription_plan`: add `tier`, `specialist_min/max`, `sms_included`, `wa_included`, `most_popular`, `auto_deactivate_on_expiry`, `six/twelve_month_discount_pct`; replace free-text `features` with an enum-key **Feature matrix** (rows × plans, toggle-to-save). Admin-only table → **needs `api-impact` check** (likely portal-only, but the shop portal reads plans).
- **Geography bilingual + active** — migration: `city.name_ar`, `city.active`, `district.name_ar`; inline district add/remove-as-chips in the city modal; delete-confirm with shop-usage count. **`city`/`district` are read by the shared `api/` tier → mobile-app contract risk → MUST flag before migrating.**

---

## ✅ EXECUTION COMPLETE (2026-07-16/17)

All of Wave 1 + Wave 2 built and browser-verified on `backend.navagoo.localhost` (admin).
Schema items: Plans model needed **no migration** (columns already existed); Geography + 3 small
additive/nullable columns migrated (all api-impact-checked — the mobile `api/` uses explicit
`fields()` allowlists, so **no mobile contract change**).

| Area | Result | Verified |
|---|---|---|
| **Home** attention feed | flags→titled deep-linked severity rows; real pill count | ✓ "17 items need attention" + real rows |
| **Finance** | TR fee-breakdown cols, settle strip Tips/Notif, Balances Invoiced-due, Charges CSV/PDF/Pending, Commercial-Config grace/trial, shell dedup | ✓ TR/Charges/Commercial-Config |
| **Shops/Subscriptions** | branch badge, Plans tier cards + **Feature matrix** + PlanModal, Offers CRUD, **real Payment-method toggles + guard**, Subscription-dashboard KPIs + pending-verifications + Offer/History/Payment cols | ✓ Plans, Payment toggles, Sub-dashboard |
| **Bookings/People/Notifications/Events** | subtitle; classification reason badge; per-channel badges; **Events search/target/page-size + expandable JSON payload** | ✓ Events expand works |
| **Settings/Marketing/Catalogue/Geography** | 5 workflow fields; push "Shops" audience; Catalogue **Women/Men filter**; Geography bilingual + **active toggle** + delete-confirm | ✓ City toggle (AJAX), Catalogue filter |
| **Support & Content** | **Policies tab** (Page CRUD) + Contact 7 channels editable + FAQ audience col | ✓ 3 tabs incl. Policies |
| **Invitations** | Pending/History split + expandable recipient rows + count badges | ✓ (smoke) |
| **Users & Roles** | Shop + Last-active columns (kept read-only by decision) | ✓ (smoke) |
| **Live chat** | NEW preview stub page + nav item (matches demo "coming soon" stub) | ✓ perfect match |
| **Dashboard BI** | Overview sparklines + flags strip + Refresh; **Volumes/Performance/Financials/Flags** full chart builds (Chart.js core; treemap→bar, gauges via doughnut) | ✓ all 5 tabs, 24 canvases render |

**Migrations run this session** (all additive/nullable, api-safe): `m260716_100000` geography bilingual+active · `m260716_150000` commercial_config grace/trial · `m260717_120000` commercial_config payment-method flags · `m260717_120000` settings.tiktok + faq.audience.

**Pre-existing bug fixed in passing:** `shop-category/catalogue.php` 500'd on `$parent->name_ar` (a MultiLanguageBehavior virtual attr only exposed on admin_routes) — guarded.

**Follow-up to flag (mobile API):** once FAQs get tagged `audience=shop`, the mobile FAQ endpoint should filter to `audience=customer` (today all rows default to customer, so nothing breaks yet). Not changed — flagged per the shared-API rule.

**Uncommitted** — awaiting user review/commit.

## Notes
- Chrome (turquoise) already aligned in the v0.19 wave; this sweep is **content**.
- Bilingual (`ar`+`en`) mandatory for every new `Yii::t` key.
- Rebuild admin bundle (`npm run build:css:admin`) after any backend class change.
