Files
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

13 KiB
Raw Permalink Blame History

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 (~4048px rows); optional compact for power users later.
    • Cap overview KPI cards at 35 (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: Descrybes primary is majorelle blue. “Not purple AI slop” means dont 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 (15 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 (14h) if you need confirmation the fix stuck. Cap frequency (~1 survey / customer / 1430 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 15; optional comment; closed-loop on lows

Top 8 recommendations

  1. Standardize ops pages on one skeletonPageShell + 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 — 15 (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)


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.