Files

146 lines
6.7 KiB
Markdown
Raw Permalink Normal View History

# Admin roles, legacy plans & support desk
End-to-end work from the **20-agent** `admin-roles-support` swarm: legacy (A1) limited nav, platform staff roles, admin panel polish, support assign/claim + CSAT ratings.
**Runtime rule (tenant features):**
```
effective(feature) = plan_allows(feature)
AND global_section_enabled(section(feature))
AND global_feature_enabled(feature)
```
Staff access is **orthogonal** to plan features: `users.staff_role` + `is_platform_admin` gate `/admin` and the support desk.
---
## Doc map (agents 119)
| Doc | Owner | What it covers |
|-----|-------|----------------|
| [01-ux-research.md](./01-ux-research.md) | 1 | Admin / permissions / support UX patterns |
| [02-current-inventory.md](./02-current-inventory.md) / [02-extension-points.json](./02-extension-points.json) | 2 | Pre-change inventory |
| [03-roles-matrix.md](./03-roles-matrix.md) / [`.json`](./03-roles-matrix.json) | 3 | Legacy allow-list + role→feature matrix |
| [04-contract.md](./04-contract.md) / [`.json`](./04-contract.json) | 4 | Unified plan + staff contract |
| [05-legacy-seed.md](./05-legacy-seed.md) | 5 | Legacy profile seed / A1 detection |
| [06-staff-roles.md](./06-staff-roles.md) | 6 | `admin` / `developer` / `support_staff` backend |
| [07-admin-shell.md](./07-admin-shell.md) | 7 | Admin layout / nav chrome |
| [08-permissions-ui.md](./08-permissions-ui.md) | 8 | Billing → Permissions panel |
| [09-admin-billing-ui.md](./09-admin-billing-ui.md) | 9 | Plans list / assign polish |
| [10-admin-orgs-ui.md](./10-admin-orgs-ui.md) | 10 | Users/companies + staff role grant |
| [11-support-design.md](./11-support-design.md) / [11-support-api-contract.json](./11-support-api-contract.json) | 11 | Support desk design |
| [12-support-backend.md](./12-support-backend.md) | 12 | Tickets / claim / assign API |
| [13-support-ratings.md](./13-support-ratings.md) | 13 | CSAT 15 ratings |
| [14-support-staff-ui.md](./14-support-staff-ui.md) | 14 | Staff inbox + assign UI |
| [15-user-support-ui.md](./15-user-support-ui.md) | 15 | Customer support + rate UI |
| [16-legacy-nav.md](./16-legacy-nav.md) | 16 | A1 image-nav gating |
| [17-security.md](./17-security.md) | 17 | AuthZ / IDOR / CSRF pass |
| [18-performance.md](./18-performance.md) | 18 | Indexes / list bounds |
| [19-defaults-alignment.md](./19-defaults-alignment.md) | 19 | Ladder + Legacy + staff defaults |
Related: [`../plan-permissions/README.md`](../plan-permissions/README.md) (feature keys + admin Permissions API).
---
## Schema (goose)
| Version | File | Purpose |
|---------|------|---------|
| 026 | `apps/api/sql/schema/026_plan_features.sql` | `plans.features` + global gates |
| 027 | `027_capabilities_support_perf.sql` | Capabilities + support queue indexes |
| 028 | `028_plan_is_legacy.sql` | `plans.is_legacy` + name backfill |
| 029 | `029_staff_roles.sql` | `users.staff_role` |
| 030 | `030_support_desk.sql` | CSAT table, claim queue cols, notification kinds |
Apply (Windows):
```powershell
.\scripts\migrate.ps1
# or from apps/api with DATABASE_URL set:
go run github.com/pressly/goose/v3/cmd/goose@v3.24.3 -dir sql/schema postgres $env:DATABASE_URL up
```
Strip UTF-8 BOM from new SQL if goose errors on `\ufeff-- +goose Up`.
---
## Code map
| Concern | Paths |
|---------|--------|
| Legacy detect/seed | `apps/api/internal/billing/legacy_plan*.go` |
| Staff roles | `apps/api/internal/auth/staff*.go`, `httpapi/middleware.go`, `admin_staff_handlers.go` |
| Support desk | `apps/api/internal/support/{desk,ratings,agents,tickets}.go`, `httpapi/support_*.go` |
| Admin shell | `AdminNav.svelte`, `admin-nav-ui.svelte.ts`, root `+layout.svelte` |
| Permissions UI | `PlanPermissionsPanel.svelte`, `admin-plan-permissions.ts` |
| Orgs / staff grant | `routes/admin/users/+page.svelte`, `admin-orgs.ts` |
| Legacy nav | `Nav.svelte`, `plan-capabilities.ts`, `PlanRouteGuard.svelte` |
| Staff inbox | `routes/admin/support/**` |
| User rate | `SupportTicketRating.svelte`, `routes/support/**` |
---
## Manual verify checklist
### A1 / Legacy nav
- [ ] `goose`**30**; `seed-demo` (or `EnsureDefaultPlans`) so **Local Demo Co** is on plan **Legacy** (`is_legacy=true`)
- [ ] Restart API after migrate/seed
- [ ] Login as demo → Local Demo Co → sidebar shows only: Dashboard, Products, Feeds, Export Feeds, Categories, Attributes, Standard Fields, Usage & Billing, Settings
- [ ] No Background Tasks / Processing, Stores, Campaigns, Brand, SEO (no empty **More** unless Platform admin)
- [ ] `GET /api/billing/capabilities`: `processing.monitor` / `stores.hub` / `marketing.*` → false; nav parents → true
- [ ] Deep link `/processing` → upgrade panel
### Admin panel polish
- [ ] `/admin` shell: sidebar groups Monitor / Manage, dark content, mobile drawer
- [ ] `/admin/billing` → Permissions: profiles (incl. Legacy one-click), section toggles
- [ ] `/admin/users`: companies + assign plan + staff role dialog
### Support assign + rate
- [ ] Customer: create ticket → staff reply → resolve → rate 15 (`SupportTicketRating`)
- [ ] Staff: `/admin/support?scope=unassigned` → Claim → Mine; Unassign returns to queue
- [ ] Full admin: ticket detail → Assign to staff → Apply
- [ ] API: support routes under `RequireSupportDesk`; billing mutations still `RequirePlatformAdmin`
### Staff role access
- [ ] Grant `support_staff` from Users → that user sees Support (+ Overview redirects to Support), not Billing/Settings
- [ ] `GET /api/admin/billing` (or plans) → **403** for support_staff
- [ ] `admin` / `developer` / legacy `is_platform_admin` + NULL role → full console
- [ ] Cannot PATCH own `staff_role`
---
## Verify commands
```powershell
.\scripts\migrate.ps1
cd apps\api
go test ./internal/billing/ ./internal/auth/ ./internal/support/ -count=1
go test ./internal/httpapi/ -count=1 -run "Staff|Support|PlanFeature|PlanGate|AdminAuth|RequirePlatform|CSAT|Csat"
cd ..\web
npm run check
```
Optional demo alignment:
```powershell
cd apps\api
go run ./cmd/seed-demo -postgres $env:DATABASE_URL
```
---
## Integration notes (agent 20)
- Merged duplicate `028_*` legacy SQL into `028_plan_is_legacy.sql`; renumbered staff → **029**, support desk → **030**.
- `/admin` Overview: `support_staff` redirected to `/admin/support` (nav still shows Overview).
- `seed-demo` / `EnsureLegacyDefaults` assigns **Legacy** to Local Demo Co / A1 cohort (not Enterprise all-ON).
### Remaining blockers / non-goals
1. Not every tenant mutation is `AssertFeature`'d (same as plan-permissions agent 10) — UI + critical writes first.
2. Live browser QA of admin polish + CSAT requires a running `npm run dev` session and staff test user.
3. OpenAPI public fragment may still omit some support/staff paths (session docs in plan-permissions / support contract JSON).