224 lines
13 KiB
Markdown
224 lines
13 KiB
Markdown
# UX research: Admin, roles/plans, support desk
|
||||
|
|
|
|||
|
|
**Product:** Descrybe — product feed / AI catalog SaaS (Go API + SvelteKit admin).
|
|||
|
|
**Scope:** Clean ops panels, plan/role permission matrices, support queue with assignment + CSAT.
|
|||
|
|
**Date:** 2026-08-05
|
|||
|
|
**Method:** Web research (admin tables, RBAC/entitlements, support SLA/CSAT) + codehelper skim of existing admin UI.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Existing Descrybe surface (baseline)
|
|||
|
|
|
|||
|
|
| Area | What exists today | Paths / symbols |
|
|||
|
|
| --- | --- | --- |
|
|||
|
|
| Admin chrome | Fixed left nav, dark shell (`.dark`), brand “Descrybe” + Admin pill | `AdminNav.svelte` |
|
|||
|
|
| Page frame | `PageShell` → title + description + actions; `max-w-7xl` | `PageShell.svelte` |
|
|||
|
|
| Tables | `TableShell` = bordered `bg-card` + scroll; row hover `muted/40` | `TableShell.svelte` |
|
|||
|
|
| Support queue | Status chip filters, search, Badge status map, click-through rows | `/admin/support`, `listAdminSupportTickets` |
|
|||
|
|
| Ticket model | status, priority, category, `assignee_admin_user_id`, message thread | `support/admin-api.ts` |
|
|||
|
|
| Plan features | Package select + section filter + search; checkbox matrix; package Badges | `PlanPermissionsPanel.svelte` |
|
|||
|
|
| Tokens | Majorelle primary, russian-violet ink, slate-friendly cards; semantic Badge variants | `layout.css` (`--primary` 247°, success/warning Badges) |
|
|||
|
|
|
|||
|
|
**Implication:** Do not invent a second admin visual system. Extend `PageShell` + `Card` + `TableShell` + `Badge` + filter chips already used on Support. Prefer semantic tokens (`border-border`, `bg-primary/15`, `text-muted-foreground`) over one-off `slate-*` where the rest of admin already uses tokens (Support does; PlanPermissions still hardcodes some slate).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## A) Clean admin / ops panels
|
|||
|
|
|
|||
|
|
### Patterns to apply
|
|||
|
|
|
|||
|
|
1. **Job-first hierarchy (3 levels)**
|
|||
|
|
- L1: entity/queue purpose + critical alerts + primary actions (Refresh, Assign, Resolve).
|
|||
|
|
- L2: filters + operational table.
|
|||
|
|
- L3: audit / history / advanced settings on demand (drawer or sub-route).
|
|||
|
|
Source pattern: SaaS admin hierarchy guides (Taqwah, PyColors).
|
|||
|
|
|
|||
|
|
2. **Density as a tool, not a vibe**
|
|||
|
|
- Ops tables: comfortable default (~40–48px rows); optional compact for power users later.
|
|||
|
|
- Cap overview KPI cards at **3–5** (admin overview already leans summary + tool grid — keep that restraint).
|
|||
|
|
- Sticky table headers; freeze identity column (subject / company name) when horizontal scroll appears.
|
|||
|
|
|
|||
|
|
3. **Queue-shaped tables**
|
|||
|
|
Useful traits: strong status, workflow filters, clear row entry, stable column order.
|
|||
|
|
Weak traits: ambiguous state, decorative charts instead of work, actions buried in kebab menus for primary work.
|
|||
|
|
|
|||
|
|
4. **Filter UX**
|
|||
|
|
- Removable filter chips + result count (“12 of 240 · status open · priority high”).
|
|||
|
|
- Global search + a few workflow filters (status / assignee / plan tier / SLA risk) — not a filter drawer per column on day one.
|
|||
|
|
- Persist key filters in URL (`?status=open`) — Support already does this; extend to assignee/SLA.
|
|||
|
|
|
|||
|
|
5. **Layout zones for ticket / user detail**
|
|||
|
|
Entity header (state + plan + SLA) → primary thread/table → side sheet for assignment / meta → audit strip.
|
|||
|
|
Prefer split pane or side sheet over full-page form for assignment so the queue context stays visible.
|
|||
|
|
|
|||
|
|
### DO / DON'T — avoiding the “ugly admin” look (Descrybe-native)
|
|||
|
|
|
|||
|
|
| DO | DON'T |
|
|||
|
|
| --- | --- |
|
|||
|
|
| Reuse `PageShell`, `Card`, `TableShell`, Lucide icons at `h-4`/`h-5` | New dashboard kits, glassmorphism, neon charts, multi-shadow cards |
|
|||
|
|
| Use majorelle **sparingly**: active nav, selected filter, primary CTA | Purple-to-indigo hero gradients, glow rings, “AI sparkle” chrome on every control |
|
|||
|
|
| Semantic status via `Badge` (`warning`/`success`/`secondary`) | Rainbow row backgrounds or emoji status columns |
|
|||
|
|
| One composition per page: title → filters → table | KPI strip + chart wall + three card grids above every queue |
|
|||
|
|
| Tabular nums + truncate with tooltip for IDs/emails | Wrapping every cell; monospace walls of UUID |
|
|||
|
|
| Destructive actions visually separate + confirm | Red “Delete” next to “Reply” without consequence copy |
|
|||
|
|
| Match admin dark shell tokens from `layout.css` | Flat gray Bootstrap admin or cream/serif “editorial” admin |
|
|||
|
|
|
|||
|
|
Brand note: Descrybe’s primary *is* majorelle blue. “Not purple AI slop” means **don’t decorate** — use brand as selection/affordance, not as atmosphere.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## B) Plan / role permission matrices
|
|||
|
|
|
|||
|
|
### Model (separate two axes)
|
|||
|
|
|
|||
|
|
Research consensus (Stripe-style entitlements + B2B RBAC UX):
|
|||
|
|
|
|||
|
|
| Axis | Question | Descrybe mapping |
|
|||
|
|
| --- | --- | --- |
|
|||
|
|
| **Role** | What can this *person* do? | Platform admin vs company admin vs member; future scoped ops roles |
|
|||
|
|
| **Plan / entitlement** | What has this *account* bought? | Plans + `PlanPermissionsPanel` feature catalog + feature gates |
|
|||
|
|
| **Scope** | Where does it apply? | Company / catalog / feed — keep visible if multi-tenant ops act across companies |
|
|||
|
|
| **Lifecycle** | Trial, past_due, suspended, custom deal | Already surfaced in billing helpers (`billing-display`, package Badges) |
|
|||
|
|
|
|||
|
|
**Never blur** “member can export” (role) with “Advanced export is on Enterprise” (plan). UI should explain *which* layer blocked an action.
|
|||
|
|
|
|||
|
|
### Matrix UX patterns
|
|||
|
|
|
|||
|
|
1. **Read matrix for audit; edit via focused builder**
|
|||
|
|
Full checkbox grids are good for platform ops (current Plan features panel). For end-customer role assignment, prefer named roles + plain-language summary, not a wall of toggles.
|
|||
|
|
|
|||
|
|
2. **Group by task domain**
|
|||
|
|
Sections already in `PLAN_FEATURE_SECTIONS` — keep section headers, global gate Badge (“Globally disabled”), and search. Add “affected companies / seats” count before bulk enable/disable.
|
|||
|
|
|
|||
|
|
3. **Honest gating states**
|
|||
|
|
Hide vs disable vs upgrade CTA vs “ask admin” — pick per feature. Support/billing should show *why* (plan vs role vs lifecycle).
|
|||
|
|
|
|||
|
|
4. **Role chips**
|
|||
|
|
Compact chips: plan name, `is_custom`, trial, platform-admin. Use `Badge variant="outline"` for ladder defaults and `secondary` for custom deals (already started in PlanPermissionsPanel). Avoid inventing 8 near-identical admin role names.
|
|||
|
|
|
|||
|
|
5. **Exceptions expire**
|
|||
|
|
Support overrides and custom deals need owner, reason, expiry, audit — otherwise Support becomes the policy engine.
|
|||
|
|
|
|||
|
|
### DO / DON'T — permissions UI
|
|||
|
|
|
|||
|
|
| DO | DON'T |
|
|||
|
|
| --- | --- |
|
|||
|
|
| Label packages in customer language (Free / Pro / Enterprise / Custom deal) | Internal flags as the only label (`is_custom` alone) |
|
|||
|
|
| Show count enabled / total; section + search filters | Unfiltered 80-row checkbox dump with no scan path |
|
|||
|
|
| Confirm bulk “Disable all” with blast radius | Silent global section flips |
|
|||
|
|
| Log who changed plan features | Toggles with no success/error feedback (panel already alerts — keep it) |
|
|||
|
|
| Separate “AI roles” (provider keys) from user RBAC | Mixing `admin-ai-roles` (LLM slots) into the human permission matrix naming |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## C) Support desk: assignment, queues, SLA, CSAT
|
|||
|
|
|
|||
|
|
### Current hooks
|
|||
|
|
|
|||
|
|
- Queue: status filters + search; columns subject/status/priority/company/requester/updated.
|
|||
|
|
- API update already allows `assignee_admin_user_id` / `clear_assignee`.
|
|||
|
|
- Priorities: `low | normal | high`. Categories: `billing | bug | account | other`.
|
|||
|
|
- Gap vs research: no SLA timers, no assignee column/filter, no CSAT fields, no “my queue” / unassigned views.
|
|||
|
|
|
|||
|
|
### Ticket queue patterns
|
|||
|
|
|
|||
|
|
1. **Ownership model**
|
|||
|
|
Default for B2B SaaS: route by **product area / category** + **customer plan tier**, then assign.
|
|||
|
|
Assignment modes to support:
|
|||
|
|
- Unassigned pool → claim
|
|||
|
|
- Round-robin / load-balance for general
|
|||
|
|
- Skill / category for billing vs bug
|
|||
|
|
- VIP / Enterprise bypass for high impact
|
|||
|
|
|
|||
|
|
2. **Queue views (filters, not separate apps)**
|
|||
|
|
- All open · Unassigned · Mine · SLA at risk · Waiting on customer (`pending`)
|
|||
|
|
Keep chip style from Support page (`border-primary bg-primary/15` when active).
|
|||
|
|
|
|||
|
|
3. **Row information hierarchy**
|
|||
|
|
Primary: subject + company. Secondary: status Badge, priority, assignee avatar/initials, last message age. Tertiary: category under subject (already). Add SLA countdown only when defined.
|
|||
|
|
|
|||
|
|
4. **SLA as timers + events**
|
|||
|
|
- Tier by priority (and optionally plan): first response + resolution targets.
|
|||
|
|
- States: on track → **at risk** (e.g. 80% elapsed) → breached.
|
|||
|
|
- Pause when waiting on customer.
|
|||
|
|
- UI: subtle text for on-track; `Badge variant="warning"` at risk; `destructive` only for breach — not red rows.
|
|||
|
|
|
|||
|
|
5. **Assignment UX**
|
|||
|
|
- Inline assignee control on detail header; optional bulk assign from queue.
|
|||
|
|
- Show workload (open count) in assignee picker.
|
|||
|
|
- Reassignment reason for misroutes (feeds quality metrics).
|
|||
|
|
|
|||
|
|
### CSAT patterns
|
|||
|
|
|
|||
|
|
1. **One rating question + optional comment** (1–5 or Good/Neutral/Bad). Extra questions kill response rate.
|
|||
|
|
2. **Ask in-thread or embed in resolution email** — avoid “click this survey link” as primary path.
|
|||
|
|
3. **Timing:** immediate on resolve for highest response; optional short delay (1–4h) if you need confirmation the fix stuck. Cap frequency (~1 survey / customer / 14–30 days).
|
|||
|
|
4. **Closed loop:** rating ≤2 → auto follow-up task for lead/manager within 24h; do not only score the agent.
|
|||
|
|
5. **Ops dashboard:** weekly CSAT trend, by category and by assignee — not a vanity gauge on every ticket list row (show star only when rated).
|
|||
|
|
|
|||
|
|
### DO / DON'T — support UX
|
|||
|
|
|
|||
|
|
| DO | DON'T |
|
|||
|
|
| --- | --- |
|
|||
|
|
| Explicit assignee + unassigned queue | Tickets that only change status with no owner |
|
|||
|
|
| Concrete priority definitions (impact × urgency) | “High” used for every billing question |
|
|||
|
|
| Pair speed (FRT/SLA) with CSAT / reopen rate | Optimize SLA alone until quality collapses |
|
|||
|
|
| Internal notes distinct from customer replies | Agents accidentally sending notes to customers |
|
|||
|
|
| Macros that sound human; show company plan on ticket | Generic AI purple assist panel auto-replying without gate (`support` AI role stays off until product gate) |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Concrete patterns checklist (build against this)
|
|||
|
|
|
|||
|
|
| Pattern | Apply on |
|
|||
|
|
| --- | --- |
|
|||
|
|
| Density | Support + Users + Billing tables via shared table cell padding |
|
|||
|
|
| Hierarchy | PageShell title → chip filters → TableShell → detail |
|
|||
|
|
| Tables | Sticky header; identity first; Badge for state; truncate + title |
|
|||
|
|
| Filters | Chips + URL params + count; search left-icon Input |
|
|||
|
|
| Role / plan chips | Badge outline vs secondary; plan name humanized |
|
|||
|
|
| Ticket queues | Unassigned / Mine / At risk views; assignee column |
|
|||
|
|
| SLA | Timer + at-risk Badge; pause on `pending` |
|
|||
|
|
| Ratings | Post-resolve 1–5; optional comment; closed-loop on lows |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Top 8 recommendations
|
|||
|
|
|
|||
|
|
1. **Standardize ops pages on one skeleton** — `PageShell` + filter chip bar + `TableShell` + empty/forbidden/unavailable states (copy Support; retire ad-hoc slate-only cards where tokens suffice).
|
|||
|
|
|
|||
|
|
2. **Ship assignee-centric queues next** — column + filter + “Unassigned / Mine”; wire existing `assignee_admin_user_id` before adding SLA or CSAT chrome.
|
|||
|
|
|
|||
|
|
3. **Keep plan entitlements and human roles as two panels** — extend `PlanPermissionsPanel` for packages; separate company/platform RBAC; never merge with `admin-ai-roles` LLM slots in the same matrix.
|
|||
|
|
|
|||
|
|
4. **Permission matrix = grouped sections + search + blast-radius confirms** — preserve section gates and package Badges; add “who is affected” on enable/disable all.
|
|||
|
|
|
|||
|
|
5. **Add SLA as a thin operational layer** — first-response + resolution by priority (optionally × plan tier); show at-risk/breach Badges; pause on `pending`.
|
|||
|
|
|
|||
|
|
6. **CSAT: one click in the resolution path** — 1–5 (or 3-point) in ticket UI / resolution email; optional comment on low scores only; frequency cap; manager follow-up automation for ≤2.
|
|||
|
|
|
|||
|
|
7. **Visual discipline = brand as signal, not decoration** — majorelle for selection/CTA only; semantic Badges for state; no gradient dashboards, glow, or decorative KPI walls.
|
|||
|
|
|
|||
|
|
8. **Measure ops health with a short metric set** — FRT, SLA at-risk/breach, misroute/reassign rate, reopen rate, CSAT weekly by category — surface on Support overview, not as chart spam on the queue.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Sources (web)
|
|||
|
|
|
|||
|
|
- [SaaS Admin Panel Design — hierarchy & density](https://taqwah.agency/blog/saas-admin-panel-design-guide)
|
|||
|
|
- [Admin tables & queues](https://pycolors.io/guides/saas-admin-panels)
|
|||
|
|
- [Data table density, chips, sticky headers](https://www.setproduct.com/blog/data-table-ui-design)
|
|||
|
|
- [Permission matrix as product surface (roles vs entitlements)](https://0r8it.com/blog/the-permission-matrix-is-a-product-surface)
|
|||
|
|
- [Multi-role B2B SaaS — role / plan / scope](https://dardesign.io/blog/multi-role-b2b-saas-ux-roles-permissions-flows)
|
|||
|
|
- [Support triage, routing, SLA events](https://thinkbot.agency/blog/support-ticket-automation-playbook-triage-routing-slas-knowledge-qa)
|
|||
|
|
- [Queue strategy & SLA milestones](https://www.supportbench.com/support-queue-strategy-triage-routing-ownership/)
|
|||
|
|
- [CSAT timing, one-question surveys, closed loop](https://supp.support/blog/how-to-set-up-csat-surveys)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Open follow-ups (out of scope for this note)
|
|||
|
|
|
|||
|
|
- Exact SLA targets (minutes/hours) per priority × plan — needs ops decision.
|
|||
|
|
- Whether CSAT is in-app only, email-embedded, or both.
|
|||
|
|
- Company-side roles matrix vs platform-admin-only for v1.
|