Reporting
Overview
Reporting is the read side of the events AuditFlow’s sinks stored: metrics, event lists and traces from ClickHouse, and archived bodies from S3. A tenant’s backend calls it on behalf of one of its customers, and each customer sees its own rows only. AuditFlow itself keeps no database and has no query API, by design: this module is where reads belong.
Status: alpha. The contract can still change. Browsers and customers never reach this service directly; the backend that authenticated them does.
Capabilities
| Capability | Description |
|---|---|
| Metric catalogue | One YAML file per tenant, validated at start. A metric is a reviewed definition: adding one adds a catalogue entry, not an endpoint. |
| No client SQL | A request picks names from the catalogue. Every value is a bound parameter. |
| Two-layer isolation | Every query filters on the caller’s scope, and a ClickHouse row policy applies the same scope to a query that forgot. |
| Groups and history | The backend translates a plan into groups and days of history. The service knows no plan names. |
| Events and traces | Events paged by cursor, newest first, and every event of one correlation ID. |
| Bodies from S3 | An event’s archived request and response, read by a key computed from its row. Optional, limited to a group. |
Architecture
sequenceDiagram
autonumber
participant B as Your backend
participant G as API Gateway
participant R as Reporting
participant C as ClickHouse
participant S as S3
B->>G: POST + token + X-Reporting-Scope, -Groups, -History-Days
G->>R: authorized, X-Auth-Tenant and X-Auth-Scopes set
R->>R: tenant selects the catalogue, group and history checked
R->>C: catalogue SQL + bound values, as the reader, SQL_scope set
C-->>R: rows of that scope only
R-->>S: bodies by computed key (only with the bodies group)
R-->>B: JSON
Caller contract
| Value | From | Rule |
|---|---|---|
| Tenant | X-Auth-Tenant, set by the gateway from the token | Selects the catalogue; none is a 403 |
| Delegation | X-Auth-Scopes must hold reporting:read-delegated | Give this role to your backend alone; otherwise 403 |
| Scope | X-Reporting-Scope | Required, ^[A-Za-z0-9_.:-]{1,128}$, otherwise 400 |
| Groups | X-Reporting-Groups | Comma list; a metric outside it is a 403 |
| History | X-Reporting-History-Days | Limits how far back a caller reads, unless a metric says fullHistory |
API
Every operation is POST, under /reporting/api/v1.
| Operation | Purpose |
|---|---|
/metrics/list | The metrics this caller may see |
/metrics/query | A series: range, interval, up to two dimensions, filters |
/events/search, /events/get | Events, cursor paged; one event |
/traces/get | Every event of one correlation ID |
/events/body | An event’s archived bodies |
/status | How fresh the data is |
A store that does not answer gives a 503 with Retry-After; bodies past their retention give a 404.
Quick start
The module README starts the service next to a ClickHouse with a demo tenant, with Docker only.
Deploying
Install the reporting chart. You bring:
- A ClickHouse with a reader user: a settings profile with
readonly = 2and query limits,SELECTon the tables a catalogue names, and a row policyUSING <scope column> = getSetting('SQL_scope')on each. The umbrella chart can run one node (clickhouse.enabled). - A catalogue per tenant, mounted at
/etc/labs64/reporting/catalogue/<tenant>.yaml. A tenant with no file gets a403. - The reader’s password as
CLICKHOUSE_PASSWORD. - Optionally S3 read access to one prefix, and
REPORTING_BODIES_BUCKET.
Limits
The row policy protects against bugs in this service, not against code running inside it: the reader may change SQL_scope, so a compromised pod can set any scope. Schedules, exports, alerts and further query backends are not part of it yet.