# 08 — Admin UI: plan features & global section switches (agent 8/10) > **Superseded for the admin-roles wave:** see [`../admin-roles-support/08-permissions-ui.md`](../admin-roles-support/08-permissions-ui.md) (agent 8/20) — profiles, Legacy/A1 one-click, real APIs, shell tokens. **Owns:** Admin frontend only — package feature checklist + global section masters. **Entry:** `/admin/billing` → **Permissions** tab (nav: Platform billing). **Design system:** Same cards/tabs/badges/checkboxes as existing admin billing & settings. --- ## UI entry paths | Path | Role | |------|------| | `/admin/billing` | Platform billing admin (gate: `requirePlatformAdmin`) | | Tab **Permissions** | Plan feature matrix + global section controls | | Plans table → **Edit features** | Jumps to Permissions tab | | `AdminNav` → Platform billing | `apps/web/src/lib/components/AdminNav.svelte` | ### Source files | File | Intent | |------|--------| | `apps/web/src/routes/admin/billing/+page.svelte` | Hosts Permissions tab | | `apps/web/src/lib/components/admin/PlanPermissionsPanel.svelte` | Checklist UI | | `apps/web/src/lib/admin-plan-permissions.ts` | Admin API client + defaults | | `apps/web/src/lib/plan-feature-catalog.ts` | Catalog from `01-feature-keys.json` | --- ## Features delivered 1. **Per-plan checklist** — all catalog keys grouped by section; toggle each feature. 2. **Enable all / Disable all** — for the selected plan. 3. **Global section controls** — enable/disable a section for all plans; optional “section + features”. 4. **Default vs custom** — badges: Default ladder / Default · custom flag (Enterprise) / Custom deal / Client deal + `is_custom` / Standard. 5. **Saved state** — optimistic toggle with revert on error; clear loading (“Saving…”) and success/error alerts. 6. **API wiring** — contract paths from `03-permission-contract.md`; stub/in-session fallback when agent 5 routes are 404/501. i18n: admin surfaces use plain English (no `__()` in existing admin pages) — matched that pattern. --- ## API contract used (agent 5 / agent 3) | Method | Path | Use | |--------|------|-----| | `GET` | `/api/admin/plans` | List plans; read `features` / `resolved_features` when present | | `POST` | `/api/admin/plans` | Upsert plan including `features` override map | | `GET` | `/api/admin/feature-gates` | Global `sections` + `features` masters | | `PUT` | `/api/admin/feature-gates` | Replace global maps | | `PUT` | `/api/admin/feature-gates/sections/{section}` | Body `{ enabled, apply_features? }` | | `POST` | `/api/admin/plans/{id}/features/enable-all` | Convenience (optional; falls back to upsert all-true) | | `POST` | `/api/admin/plans/{id}/features/disable-all` | Convenience (optional; falls back to upsert all-false) | **ASSUMPTION:** Until agent 5 mounts feature fields/gates, UI shows client-side default matrix (contract §4) and keeps toggles in-session when APIs return 404/501. Info banner explains stub mode. --- ## Manual verify 1. Sign in as platform admin → `/admin/billing`. 2. Open **Permissions**. 3. Select Free vs a custom plan — badges and default checklist differ. 4. Toggle one feature; Enable all / Disable all. 5. Flip a global section; try “Disable section + features”. 6. When backend ready: reload page and confirm persisted state. --- ## Blockers / notes for siblings - Agent 5 must return `features` / `resolved_features` on admin plans and mount `/api/admin/feature-gates*`. - Agent 4 must add `plans.features` + `platform_feature_gates`. - Agent 9 consumes effective features for dashboard gating (not this UI).