Files

98 lines
3.9 KiB
Markdown
Raw Permalink Normal View History

# 08 — Staff auto / AI assist UI
**Agent:** 8/10 · **Status:** Implemented
**Coordinates with:** `02-contract` (fields), `05-ticket-detail` (schema + PATCH), `03`/`04` (match + AI drafts), `14-support-staff-ui` (desk shell)
---
## PROBLEM
Staff need to see auto-match / AI assist outcomes on a ticket, approve or edit `draft_only` AI drafts, disable further auto per ticket, and filter the queue for `needs_human` / `ai_draft` — without elevating `support_staff` beyond the existing desk gate.
---
## WHAT SHIPPED
### Access (least privilege preserved)
| Actor | Surfaces |
|-------|----------|
| `support_staff` | `/admin/support/**` only via `requireSupportDesk` / `RequireSupportDesk` |
| Full admin | Same desk + assign picker (unchanged) |
- New endpoints mount under the **same** `RequireSupportDesk` group as claim/reply.
- Approve/discard/get still call `staffMayAccessTicket` (support_staff: own claim or unassigned open/pending; cross-assignee → 404 / 409).
- No KB/settings/billing routes exposed to support_staff.
### Queue (`/admin/support`)
- Filter chips: **Any auto state** · **Needs human** · **AI draft** (`?flag=`).
- Persisted in URL with existing `scope` / `status`.
- **Auto** column: status badge or “Auto off”.
- API: `GET /api/admin/support/tickets?flag=needs_human|ai_draft`
- `ai_draft``auto_reply_status = ai_draft`
- `needs_human``handed_off|failed|skipped`
### Ticket detail (`/admin/support/[id]`)
- **Auto-match / AI assist** panel: status, last attempt, disable / re-enable auto (`PATCH { auto_reply_disabled }`).
- When `auto_reply_status=ai_draft`: edit draft body → **Approve & send** or **Discard draft**.
- Thread bubbles label auto/KB/AI messages; drafts stay internal-note style.
- Client falls back to public reply + disable if approve/discard routes are not yet mounted (404/501).
### API client
`$lib/support/admin-api.ts` + `$lib/support/auto-assist.ts`
| Method | Path |
|--------|------|
| list (+ `flag`) | `GET …/tickets` |
| update (incl. `auto_reply_disabled`) | `PATCH …/tickets/{id}` |
| approve draft | `POST …/tickets/{id}/ai-draft/approve` |
| discard draft | `POST …/tickets/{id}/ai-draft/discard` |
Domain: `apps/api/internal/support/staff_auto.go` (`ApproveAIDraft`, `DiscardAIDraft`, `ApplyQueueFlag`).
---
## FILES
| Area | Path |
|------|------|
| Helpers | `apps/web/src/lib/support/auto-assist.ts` |
| Client | `apps/web/src/lib/support/admin-api.ts` |
| Queue UI | `apps/web/src/routes/admin/support/+page.svelte` |
| Detail UI | `apps/web/src/routes/admin/support/[id]/+page.svelte` |
| Domain | `apps/api/internal/support/staff_auto.go`, `types.go` (`ListFilter.Flag`), `errors.go` |
| List filter | `apps/api/internal/support/tickets.go` (`ApplyQueueFlag`) |
| HTTP | `support_handlers.go`, `server.go` (approve/discard mounts) |
---
## VERIFICATION
```text
cd apps/web && npm run check
cd apps/api && go test ./internal/support/ ./internal/httpapi/ -count=1
```
Manual:
1. As `support_staff`: open `/admin/support?flag=needs_human` and `?flag=ai_draft` — no billing/settings nav.
2. Ticket with FAQ/AI outcome: panel shows status; **Disable auto** sticks across refresh.
3. `ai_draft` ticket: edit draft → Approve & send → customer-visible agent reply; draft queue clears.
4. Discard → `handed_off` / auto disabled; ticket remains claimable.
5. Ticket assigned to another agent → get/approve → 404/409 (not full admin leak).
---
## ASSUMPTIONS
- ASSUMPTION: Ticket auto columns come from agent 5 migration `031_support_ticket_detail` (+ agent 3 `032` KB). UI tolerates missing fields as empty/`none`.
- ASSUMPTION: `draft_only` AI posts internal notes with `is_auto_reply` + `auto_source=ai` and sets `auto_reply_status=ai_draft` (agent 4).
- ASSUMPTION: Public staff reply already sets `auto_reply_disabled` (existing `ReplyAsAgent`).
## ROLLBACK
Revert staff UI/client + `staff_auto.go` + approve/discard routes + `ListFilter.Flag`. Leave schema migrations in place.