docs: document the activity feed, actor/target and usage spend

Covers what the previous commits changed: the actor_id / target_id split and
the system actors, the data-plane events, the merged Activity feed and its
export, and the new usage and per-user spend endpoints.

Also corrects "there is no UI for these events yet" in the OIDC login
auditing section, which is no longer true.
This commit is contained in:
arc53-machine committed 2026-09-22 10:35:17 +01:00
1 parent a56f9df122
commit f6f8af8cef
2 files changed
+47 -8

No files matched your search

+33 -4
View File
@@ -72,7 +72,7 @@ If your IdP only exposes groups via the userinfo endpoint, DocsGPT backfills the
## Admin dashboard
Admins get a dashboard backed by a REST surface under `/api/admin` (every endpoint requires the admin role). All mutating actions are written to the `auth_events` audit log with the acting admin recorded in the metadata.
Admins get a dashboard backed by a REST surface under `/api/admin` (every endpoint requires the admin role). All mutating actions are written to the `auth_events` audit log with the acting admin recorded as the event's `actor_id`.
| Method | Path | Description |
| --- | --- | --- |
@@ -84,8 +84,12 @@ Admins get a dashboard backed by a REST surface under `/api/admin` (every endpoi
| `DELETE` | `/api/admin/users/<id>/role` | Revoke the admin role. |
| `POST` | `/api/admin/users/<id>/revoke-sessions` | Force-logout a user. |
| `GET` | `/api/admin/admins` | List current admins. |
| `GET` | `/api/admin/usage` | Token-usage series and top users. |
| `GET` | `/api/admin/audit` | Authentication/admin audit feed. |
| `GET` | `/api/admin/usage` | Usage series with tokens and spend, per-model split, latency percentiles, top users. Takes `days`, `bucket` and `group_by=model\|agent\|source`. |
| `GET` | `/api/admin/users/<id>/usage` | One user's spend: daily series plus a split by model and by flow. |
| `GET` | `/api/admin/activity` | [Merged activity feed](#activity-feed) across all three audit journals. |
| `GET` | `/api/admin/activity/events` | The `(event, category)` pairs this instance has recorded, for the filter UI. |
| `GET` | `/api/admin/activity/export` | The filtered feed as `format=csv` or `format=ndjson`. |
| `GET` | `/api/admin/audit` | Authentication/admin audit feed (`auth_events` only). |
| `GET` | `/api/admin/devices/audit` | Remote-device audit feed. |
| `GET` | `/api/admin/teams` | Instance-wide oversight of all teams. |
| `GET` `PUT` `DELETE` | `/api/admin/quotas/...` | [Usage quotas](/Deploying/Usage-Quotas) for the instance, teams and users. |
@@ -142,7 +146,32 @@ Sharing rules:
## Audit log
Access-control actions are appended to the `auth_events` table alongside the [authentication events](/Deploying/OIDC-SSO#login-auditing). This includes admin actions — `admin_user_activated` / `admin_user_deactivated`, `admin_sessions_revoked`, `role_granted` / `role_revoked` (with `metadata.source` = `manual` or `oidc_group`), `quota_policy_set` / `quota_policy_deleted` — and team events (`team.create`, `team.member_add`, `team.member_role`, `team.member_remove`, `team.share`, `team.unshare`, `team.transfer_owner`, `team.delete`). The acting admin is recorded in the event metadata.
Access-control actions are appended to the `auth_events` table alongside the [authentication events](/Deploying/OIDC-SSO#login-auditing). This includes admin actions — `admin_user_activated` / `admin_user_deactivated`, `admin_sessions_revoked`, `role_granted` / `role_revoked` (with `metadata.source` = `manual` or `oidc_group`), `quota_policy_set` / `quota_policy_deleted` — and team events (`team.create`, `team.member_add`, `team.member_role`, `team.member_remove`, `team.share`, `team.unshare`, `team.transfer_owner`, `team.delete`).
Data-plane actions are recorded too: `source.created` / `source.deleted` / `source.reingested`, `agent.created` / `agent.updated` / `agent.deleted` / `agent.key_regenerated`, and `conversation.deleted` / `conversation.deleted_all`.
Every row carries `actor_id` (who did it) and `target_id` (the user it was done to, or `NULL` when the event is not about a user), so "everything this admin did" is a single query:
```sql
SELECT created_at, event, target_id, metadata
FROM auth_events
WHERE actor_id = 'the-admin'
ORDER BY created_at DESC;
```
### Activity feed
The **Admin → Activity** tab merges three append-only journals into one timeline:
| Journal | Category | What it records |
| --- | --- | --- |
| `auth_events` | `identity`, `access`, `config`, `data` | Sign-ins, provisioning, role and account changes, quota changes, resource mutations. |
| `device_audit_log` | `device` | Every remote-device command dispatch and its verdict. |
| `guardrail_events` | `safety` | Every guardrail decision on a request. |
Filter by category, event name, actor, affected user, a time window, or a free-text search that reaches into each row's detail payload, then export the filtered feed as CSV or NDJSON. Exports stream and are capped at 100,000 rows — take a database dump for a full history.
Two guardrail columns are deliberately never projected into the feed or the export: `api_key` (a raw agent key) and `matched_value` (unredacted source text). Admin-gating is not a reason to widen what a list response carries.
## Related
+14 -4
View File
@@ -185,7 +185,12 @@ SCIM identifies users by `userName`, which DocsGPT matches against its user id
## Login auditing
Authentication activity is recorded in `auth_events`, an append-only Postgres table carrying the user id, event name, IP address, user agent, a JSONB `metadata` column, and a timestamp:
Authentication activity is recorded in `auth_events`, an append-only Postgres table carrying the event name, IP address, user agent, a JSONB `metadata` column, a timestamp, and two attribution columns:
- `actor_id` — who performed the action. Never empty.
- `target_id` — the user the action was performed on, or `NULL` when the event is not about a user (a team change, an instance-wide policy).
They differ whenever someone acts on someone else: an admin deactivating an account is `actor_id = <the admin>`, `target_id = <the account>`. For self-service events such as a login they are the same user. Automated actors are named `system:oidc` (a group-driven role change at login) and `system:scim` (provisioning).
| Event | Recorded when |
| --- | --- |
@@ -197,14 +202,19 @@ Authentication activity is recorded in `auth_events`, an append-only Postgres ta
| `role_granted` / `role_revoked` | The admin role is granted/revoked (`metadata.source` is `manual` or `oidc_group`). |
| `admin_user_activated` / `admin_user_deactivated` | An admin activates/deactivates a user. |
| `admin_sessions_revoked` | An admin force-logs-out a user. |
| `pat_created` / `pat_revoked` / `pat_regenerated` | Personal access token lifecycle. |
| `quota_policy_set` / `quota_policy_deleted` | A [usage quota](/Deploying/Usage-Quotas) is changed. |
| `team.*` | Team management — `team.create`, `team.member_add`, `team.member_role`, `team.member_remove`, `team.share`, `team.unshare`, `team.transfer_owner`, `team.delete`. |
| `source.*` | `source.created`, `source.deleted`, `source.reingested`. |
| `agent.*` | `agent.created`, `agent.updated`, `agent.deleted`, `agent.key_regenerated`. |
| `conversation.*` | `conversation.deleted`, `conversation.deleted_all`. |
The acting admin is recorded in the event metadata. See [Access Control, Roles & Teams](/Deploying/Access-Control) for the admin and team features that emit these events.
`agent.updated` records the names of the fields that changed, never their values — an agent's fields carry prompts and credentials.
There is no UI for these events yet — query the table directly:
See [Access Control, Roles & Teams](/Deploying/Access-Control#activity-feed) for the admin Activity view that reads these events, and for the two other journals it merges them with. To query the table directly:
```sql
SELECT created_at, event, user_id, ip, metadata
SELECT created_at, event, actor_id, target_id, ip, metadata
FROM auth_events
ORDER BY created_at DESC
LIMIT 50;