# Support console

The /support pages: inbox, ticket detail with the agent run and approvals, customer practice and the audit log.

The support console is where support staff work tickets from customer practices. Every page reads from Postgres through the `support.*` and `harness.*` procedures; the components hold no data. All practices, people and tickets are fictional demo data.

## Routes [#routes]

| Route | Page | What it shows |
| --- | --- | --- |
| `/support` | `support.inbox.page.tsx` | KPI strip, facet pills (status, category, priority) with counts, search, sort, a table from 768 px and cards below, pagination |
| `/support/tickets/$ticketId` | `support.ticket.page.tsx` → `support.ticket.view.tsx` | Message and reporter, triage, "Agent starten" with engine switch, live trace, diagnosis with evidence, plan with decisions, reply draft, ticket audit |
| `/support/praxen/$practiceId` | `support.practice.page.tsx` | Master data, integration health, configuration with who/when, accounts, KV exports, log viewer, open tickets |
| `/support/audit` | `support.audit.page.tsx` | Audit table with event filter, before/after drawer, "Kette prüfen" |

The inbox URL carries `status`, `kategorie`, `prio`, `q`, `sortierung` (`neueste`, `aelteste`, `prioritaet`) and `seite`; the audit URL carries `ereignis` and `seite`. Both are validated in the route with the schemas in `support.search.ts`.

## Ticket detail [#ticket-detail]

- **Layout.** From 1024 px two columns: ticket, triage and the agent with its trace on the left; diagnosis, plan, reply and audit on the right. Below that the sections stack and a sticky bottom bar holds the next step (start the agent, or jump to the actions that wait for a decision).
- **Engine.** "Automatisch" uses the AI engine and falls back to the rules; "Nur Regeln" runs the deterministic engine. Without a configured key "Automatisch" is disabled and the page says why. The run shows its engine badge and the fallback reason as text.
- **Trace.** `useStartRun` polls the run while it executes; the trace announces progress in a polite live region.
- **Evidence.** Each piece of evidence links to `#schritt-<seq>`; clicking it opens the step, scrolls it into view (instantly under reduced motion), moves focus there and outlines it briefly.
- **Decisions.** "Freigeben und ausführen" and "Ablehnen" open a dialog with an optional note (stored with the decision and shown on the card). The dialog traps focus; after a decision focus moves to the action's heading because the buttons are gone.
- **Approval rules.** `useTicketAgent().approveBlock(action)` returns why the current user may not approve: `four_eyes_member` (a member on a four-eyes action), `four_eyes_self` (the lead requested it) or `dependency` (the action it depends on has not run). Approve stays visible but disabled, described by the reason text; reject stays available.

## States [#states]

Every page has a skeleton while loading, an alert with "Erneut versuchen" on error, and a designed empty state (empty inbox, no match for the filters, no plan yet, no open tickets, no audit entries). Status, category, priority, health, export state and log level are always text + icon + tint (`platform/agent/agent.labels.ts`, `support.labels.ts`).

## Tests [#tests]

`support.*.test.tsx` render each page with fixture data: one `h1`, no skipped heading level, chips carry text, empty and error states, the four-eyes and dependency reasons, the disabled "Automatisch" option and the evidence anchor. `filterLogs` is tested as a pure function.

## Known gaps [#known-gaps]

- The log viewer filters the last 50 events on the client; `support.practices.get` has no server-side log filter.
- Audit drawer links go to the ticket and the harness run; there is no direct link to the trace step.

