97 lines
3.7 KiB
Markdown
97 lines
3.7 KiB
Markdown
# 15 — User-facing Support Center UI
|
||||
|
|
|
|||
|
|
**Agent:** 15/20
|
|||
|
|
**Date:** 2026-08-05
|
|||
|
|
**Scope:** Customer `/support` surfaces — list, create, thread, CSAT rating.
|
|||
|
|
**Contract:** [11-support-design.md](./11-support-design.md) §5 / §9.1 (`POST /api/support/tickets/{id}/csat`).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Outcome
|
|||
|
|
|
|||
|
|
Polished, accessible user Support Center that:
|
|||
|
|
|
|||
|
|
1. Lists the caller’s tickets with status chips + URL `?status=` persistence.
|
|||
|
|
2. Creates tickets (subject, category, priority, body) when `support.ticket_create` allows.
|
|||
|
|
3. Shows a threaded conversation with quiet polling (visibility-aware).
|
|||
|
|
4. Prompts CSAT (1–5 + optional comment) when status is `resolved` or `closed` and no rating yet.
|
|||
|
|
5. Respects plan feature keys via existing `PlanRouteGuard` + `FeatureGate` / `planCapabilities.can`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Surfaces
|
|||
|
|
|
|||
|
|
| Route | Feature key | Notes |
|
|||
|
|
|-------|-------------|-------|
|
|||
|
|
| `/support` | `support.center` | Status filter chips, clickable rows, count |
|
|||
|
|
| `/support/new` | `support.ticket_create` | Priority + char counters; upgrade panel if denied |
|
|||
|
|
| `/support/[ticketId]` | `support.ticket_thread` | Thread + CSAT banner/form |
|
|||
|
|
|
|||
|
|
Legacy plans: if the matrix turns `support.*` off (see `03-roles-matrix`), `PlanRouteGuard` shows the upgrade panel. When keys are absent (pre-cutover), `CORE_ALWAYS_ON` keeps basic support available.
|
|||
|
|
|
|||
|
|
CSAT is **not** a separate feature key — it rides on `support.ticket_thread` once the ticket is resolved/closed (design §5).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Client API
|
|||
|
|
|
|||
|
|
| Helper | Path |
|
|||
|
|
|--------|------|
|
|||
|
|
| `listSupportTickets` / `getSupportTicket` / `createSupportTicket` / `replySupportTicket` | `apps/web/src/lib/support/api.ts` |
|
|||
|
|
| `submitSupportCsat` → `POST …/csat` `{ score, comment? }` | same |
|
|||
|
|
| `canRateTicket` / `canReplyToTicket` | same |
|
|||
|
|
| Types `SupportCsat`, `SubmitSupportCsatInput` | `apps/web/src/lib/support/types.ts` |
|
|||
|
|
| UI | `SupportTicketRating.svelte` |
|
|||
|
|
|
|||
|
|
**Graceful backend lag:** if agent 13’s CSAT route is not mounted yet, `isSupportUnavailable` / 404–503 surfaces a clear message without breaking the thread. Duplicate ratings (`409`) show “already rated”.
|
|||
|
|
|
|||
|
|
**ASSUMPTION:** Response may be a full ticket (with `csat`) or a CSAT object; UI merges `csat` onto the in-memory ticket either way.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## UX / a11y / perf
|
|||
|
|
|
|||
|
|
- Status filters: `aria-pressed` chip group (matches admin queue pattern).
|
|||
|
|
- Rows: keyboard activatable (`Enter` / `Space`), `role="link"`.
|
|||
|
|
- CSAT: `role="radiogroup"` star buttons with explicit `aria-label`s; comment encouraged for scores ≤2.
|
|||
|
|
- Thread: `role="log"` + `aria-live="polite"`; capped scroll region; auto-scroll on new messages.
|
|||
|
|
- Polling: 20s interval skipped when `document.visibilityState === "hidden"`; refresh on focus.
|
|||
|
|
- No extra cards in hero chrome — reuse `PageShell` + existing tokens.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Files touched
|
|||
|
|
|
|||
|
|
- `apps/web/src/lib/support/types.ts`
|
|||
|
|
- `apps/web/src/lib/support/api.ts`
|
|||
|
|
- `apps/web/src/lib/components/SupportTicketRating.svelte` (new)
|
|||
|
|
- `apps/web/src/routes/support/+page.svelte`
|
|||
|
|
- `apps/web/src/routes/support/new/+page.svelte`
|
|||
|
|
- `apps/web/src/routes/support/[ticketId]/+page.svelte`
|
|||
|
|
- `apps/web/src/lib/plan-capabilities.ts` (upgrade titles for create/thread)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Verification
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cd apps/web && npm run check
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Manual:
|
|||
|
|
|
|||
|
|
1. `/support` — filter chips update URL; empty + list states.
|
|||
|
|
2. `/support/new` — create with priority; gated plan shows upgrade.
|
|||
|
|
3. Resolved ticket — CSAT form appears; after submit, “Your rating” card; reply still reopens when allowed.
|
|||
|
|
4. Legacy matrix with `support.center=false` — route guard upgrade panel.
|
|||
|
|
|
|||
|
|
**Depends on:** agent 13 mounting `POST /api/support/tickets/{id}/csat` and optional `csat` on GET. UI is ready ahead of that mount.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Out of scope (other agents)
|
|||
|
|
|
|||
|
|
- Schema / CSAT backend (12–13)
|
|||
|
|
- Staff assign / claim UI (14)
|
|||
|
|
- Admin CSAT aggregates
|