Files
descrybe/docs/admin-roles-support/08-permissions-ui.md
T
greeneclipse 8580c996c3 Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
2026-08-09 22:47:43 +02:00

97 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 08 — Admin Permissions UI (agent 8/20)
**Owns:** Admin → Billing → **Permissions** tab (`PlanPermissionsPanel` + `admin-plan-permissions` client).
**Entry:** `/admin/billing` → Permissions.
**Docs home:** [`README.md`](./README.md) (when present) · prior matrix: [`../plan-permissions/`](../plan-permissions/).
---
## PROBLEM
Make plan feature editing clean and usable: named profiles (Legacy / Free / Starter…), bulk section toggles, search/filters, clear default vs custom, and one-click Legacy for A1-like plans — wired to real admin APIs (no stub mode).
---
## Features delivered
1. **Plan profiles** — Legacy, Free, Starter, Growth, Business, Enterprise/all-on. Apply writes a full override matrix via `PUT /api/admin/plans/{id}/features`.
2. **Legacy (A1)** — Allowlist nav (Dashboard, Products, Feeds, Export Feeds, Categories, Attributes, Standard Fields, Billing, Settings). `processing.monitor` and stores/marketing/integrations/support extras stay **OFF**. Prominent **Apply Legacy (A1)** when the selected plan is A1-like (`A1*`, name contains `legacy`, or `is_legacy`).
3. **Bulk section toggles** — Per-plan Enable/Disable section (all keys in that section). Global section masters stay in the right rail (optional “+ features” updates global feature-gate rows).
4. **Search / filters** — Text (key or label), section filter, state filter (all / enabled / disabled / differs from plan-name default).
5. **Default vs custom** — Badges: Legacy / Default ladder / Custom deal; **Defaults** vs **Custom overrides**; profile chip shows ✓ when the resolved matrix matches a named profile; **Clear overrides** sends `{}`.
6. **Real APIs** — No 404 stub / in-session-only path. Mutations use feature endpoints; errors surface in alerts.
---
## Source files
| File | Intent |
|------|--------|
| `apps/web/src/lib/components/admin/PlanPermissionsPanel.svelte` | Permissions checklist UI |
| `apps/web/src/lib/admin-plan-permissions.ts` | Profiles, Legacy detect, API client |
| `apps/web/src/lib/plan-feature-catalog.ts` | Catalog / sections (shared) |
| `apps/web/src/routes/admin/billing/+page.svelte` | Hosts Permissions tab |
---
## API contract used
| Method | Path | Use |
|--------|------|-----|
| `GET` | `/api/admin/plans` | List packages |
| `GET\|PUT` | `/api/admin/plans/{id}/features` | Load / replace overrides |
| `POST` | `/api/admin/plans/{id}/features/enable-all` | Full ON |
| `POST` | `/api/admin/plans/{id}/features/disable-all` | Full OFF |
| `GET\|PUT` | `/api/admin/feature-gates` | Global masters |
| `PUT` | `/api/admin/feature-gates/sections/{section}` | Global section switch |
Auth: session + platform admin + CSRF.
---
## Legacy allowlist (summary)
Canonical ON set matches [`03-roles-matrix.md`](./03-roles-matrix.md) / `legacy_user` — including AI titles/descriptions, API keys, and `capability.ai_processing` / `api_access`. Shell skips `shell.support_notifications`; dashboard skips `dashboard.store_reconnect`.
OFF (among others): `processing.monitor`, all `stores.*`, all `marketing.*`, integrations, support tickets, campaign/email/brand/SEO/BYOK capabilities.
Machine source: `LEGACY_FEATURE_ALLOWLIST` in `admin-plan-permissions.ts`. Backend seed (agent 5) should align; UI Apply Legacy persists even if seed lags.
---
## Visual language
Uses admin shell tokens (`border-border`, `bg-card`, `text-muted-foreground`, `bg-primary/15` active chips) — same vocabulary as `AdminNav` / agent 7 shell — not hard-coded slate cards.
---
## Manual verify
1. Platform admin → `/admin/billing`**Permissions**.
2. Select **Free** → profile chip should show Free ✓ (or Apply Free). Toggle one key → **Custom overrides** + Differs badge.
3. Select **A1** (or create an A1-named deal) → **Apply Legacy (A1)**`processing.monitor` off; Products/Feeds on. Reload → persisted.
4. Section **Enable section** / **Disable section** on Catalog for the selected plan only.
5. Flip a **Global section** switch; confirm tenant capabilities respect it (agent 9/16).
6. **Clear overrides** → Defaults badge; resolved view matches plan-name defaults (Legacy-like names still resolve Legacy on the client when empty).
---
## Coordination
| Agent | Touchpoint |
|-------|------------|
| 3 / 4 | Roles matrix + contract — profiles follow Legacy allow-nav |
| 5 | Backend Legacy seed / `is_legacy` — UI already detects A1 + `is_legacy` |
| 7 | Admin shell tokens — Permissions uses the same |
| 9 | Plans table → Edit features deep-link (unchanged prop `selectedPlanId`) |
| 16 | User nav gating consumes capabilities after Legacy apply |
| 19 | Defaults alignment — keep `LEGACY_FEATURE_ALLOWLIST` in sync with seeds |
---
## ASSUMPTIONS
1. **ASSUMPTION:** Empty `plans.features` means “use defaults”; Apply Profile always writes an explicit full map.
2. **ASSUMPTION:** Until agent 5 seeds Legacy on the API, A1 empty overrides may resolve all-ON server-side; **Apply Legacy** is the reliable admin path.
3. Global “Off + features” updates **global feature masters**, not every plans overrides.