Files
descrybe/docs/admin-roles-support/13-support-ratings.md
T

91 lines
2.6 KiB
Markdown
Raw Normal View History

# 13 — Support ticket ratings / CSAT
**Owner:** agent 13
**Depends on:** agent 12 schema (`030_support_desk.sql``support_csat_ratings`)
**Status:** implemented (API + tests)
## Goal
Customers rate **resolved** or **closed** tickets once (score 15 + optional comment). Platform admins see aggregate CSAT (no PII).
## Schema (agent 12)
Table `support_csat_ratings`:
| Column | Notes |
|--------|--------|
| `ticket_id` | `UNIQUE` — one rating per ticket |
| `company_id`, `user_id` | owner + tenant |
| `score` | `SMALLINT` 15 |
| `comment` | optional, max 2000 runes (truncated) |
| `created_at` | UTC |
Ticket columns `csat_token_hash` / `csat_invite_sent_at` exist for optional public token flow (not wired in this agent).
## Rules
1. Only `created_by_user_id` may rate (others → `404`).
2. Status must be `resolved` or `closed` else `400` (`ticket not eligible for rating`).
3. Duplicate insert → `409` (`already rated`).
4. Logs: `ticket_id` + `score` only — **never** comment, email, or names.
## APIs
| Method | Path | Auth | Response |
|--------|------|------|----------|
| `POST` | `/api/support/tickets/{id}/csat` | session + company | `201` `SupportCsat` |
| `GET` | `/api/support/tickets/{id}` | customer | additive `csat` / `csat_eligible` |
| `GET` | `/api/admin/support/tickets/{id}` | support desk | includes `csat` when present |
| `GET` | `/api/admin/support/csat?from=&to=` | platform admin | aggregate |
### Customer submit body
```json
{ "score": 4, "comment": "optional" }
```
### Admin aggregate
```json
{
"total": 12,
"average": 4.25,
"distribution": { "1": 0, "2": 1, "3": 2, "4": 4, "5": 5 },
"from": null,
"to": null
}
```
`from` / `to` are optional RFC3339 bounds on `created_at` (`to` exclusive).
## Code map
| Piece | Path |
|-------|------|
| Service | `apps/api/internal/support/ratings.go` |
| Types | `CSATInput`, `CSATRating`, `CSATAggregate` in `types.go` |
| Handlers | `apps/api/internal/httpapi/support_csat_handlers.go` |
| Routes | customer POST csat; admin GET `/api/admin/support/csat` |
| Unit tests | `ratings_test.go`, `support_csat_auth_test.go` |
| Integration | `ratings_integration_test.go` (needs `DATABASE_URL` + goose) |
## Verification
```bash
cd apps/api
go test ./internal/support/ -count=1 -run 'CSAT|NormalizeCSAT|ClientErrorCSAT'
go test ./internal/httpapi/ -count=1 -run 'SupportCSAT|SupportTicketCRUDAuth'
```
With DB migrated:
```bash
go test ./internal/support/ -count=1 -run TestSubmitCSATOwnershipAndOnce
```
## Out of scope (this agent)
- Public token CSAT (`POST /api/public/support/csat`)
- User/staff UI panels (agents 1415)
- Email CSAT invite stubs