60 lines
2.3 KiB
Markdown
60 lines
2.3 KiB
Markdown
# Contract: Reporting API
|
|||
|
|
|
||
|
|
All four routes require a valid staff session with role `ADMIN` (`requireRole('ADMIN')`), the
|
||
|
|
same gate every admin-only surface uses since 010-identity-auth. All return the standard
|
||
|
|
envelope: `{ success: true, data: <shape>, meta: null }` on success, `{ success: false, error:
|
||
|
|
{code, message, details} }` on failure — no change to this codebase's existing response
|
||
|
|
convention.
|
||
|
|
|
||
|
|
## `GET /admin/reports/management`
|
||
|
|
|
||
|
|
**Query**: `from?`, `to?` (ISO dates).
|
||
|
|
|
||
|
|
**200**: `ManagementDashboard` (data-model.md).
|
||
|
|
|
||
|
|
**400** `VALIDATION_ERROR`: `from` is after `to`.
|
||
|
|
|
||
|
|
**401/403**: missing/invalid session, or a non-`ADMIN` role.
|
||
|
|
|
||
|
|
## `GET /admin/reports/product/:externalProductId`
|
||
|
|
|
||
|
|
**Path**: `externalProductId` — the SaaS-facing product identifier (same convention every other
|
||
|
|
admin product-scoped route already uses, e.g. `GET /admin/products/:externalProductId/knowledge`
|
||
|
|
from 004-product-knowledge).
|
||
|
|
|
||
|
|
**Query**: `from?`, `to?`.
|
||
|
|
|
||
|
|
**200**: `ProductDashboard`.
|
||
|
|
|
||
|
|
**404** `NOT_FOUND`: no product with that `externalProductId` (FR-006 — never an empty-but-200
|
||
|
|
response for an unknown product).
|
||
|
|
|
||
|
|
**400** `VALIDATION_ERROR`: `from` is after `to`.
|
||
|
|
|
||
|
|
## `GET /admin/reports/support`
|
||
|
|
|
||
|
|
**Query**: `from?`, `to?` (applies only to the performance figures — workload/SLA-risk/breached
|
||
|
|
are always current, per data-model.md's `SupportDashboard.generatedAt`).
|
||
|
|
|
||
|
|
**200**: `SupportDashboard`.
|
||
|
|
|
||
|
|
## `GET /admin/reports/ai`
|
||
|
|
|
||
|
|
**Query**: `from?`, `to?`.
|
||
|
|
|
||
|
|
**200**: `AiDashboard`.
|
||
|
|
|
||
|
|
## Guarantees
|
||
|
|
|
||
|
|
1. Every rate/average field is `number | null` — `null` means no qualifying data existed in the
|
||
|
|
requested range (FR-007). A consumer must never see `NaN` or a silently-substituted `0` for
|
||
|
|
"no data."
|
||
|
|
2. Every count field is a plain `number`, always present, `0` is a legitimate, meaningful value
|
||
|
|
for a count (distinct from the `null`-for-no-data rule above, which applies only to
|
||
|
|
rates/averages).
|
||
|
|
3. `from`/`to` in every response echo the *resolved* range actually used (including the default,
|
||
|
|
when omitted) — a caller never has to separately know what "the default" was.
|
||
|
|
4. No route in this contract mutates any data — a repeated identical request returns the same
|
||
|
|
shape (though not necessarily identical figures, since the underlying data can change between
|
||
|
|
requests) with no side effect.
|