Skip to content

Reports

A state, not an execution log

This is the distinction that structures everything else:

A daily report is a state of the fleet, not an account of the day's executions.

Not every device is scheduled every day. A device backed up on Monday and looked at on Thursday is healthy: the report shows that its last backup went well and that it is three days old. It does not flag it as missing.

Each device's state is therefore computed from three elements, never from the last run's status alone:

  • the date of the last successful backup;
  • the status of the last run, successful or not;
  • the expected cadence, deduced from the schedule.

See Staleness tolerance for the detail of the computation.

Exception view

A report's default view is the exception. Out of two thousand devices, eight of them in trouble, the report presents the eight.

A report of two thousand correct lines is not read, and the eight that matter get lost in it. The complete inventory stays available on explicit request, in the same structure: view=all.

The dashboard in exception view: only the devices calling for action

Devices are ranked by decreasing severity: failing, then never backed up and stale, then compliant.

A collection failure is a first-class category. It is never treated as an absence of change, and the age of the last successful backup appears explicitly, device by device. Without that, a device unreachable for three weeks would show as “no change” — the failure mode nobody wants.

Two formats, one single source

Format For whom
Formatted PDF the customer, the operator, the monthly review
JSON monitoring, billing, an AI agent, anything that consumes

Both are produced from the same source. A PDF re-issued six months later says exactly what the one sent to the customer said: it is the JSON kept on file that governs.

backup report --tenant acme                 # exception view, in the terminal
backup report --tenant acme --view all      # complete inventory
backup report --pdf /tmp/consolidated.pdf   # all customers, as PDF
backup report --tenant acme --json          # raw JSON

Also via the API. This is the entry point to wire into monitoring, or to hand to an agent.

# One customer's report, exception view (default)
curl -s "$BASE/api/reports/daily?tenant=$CUSTOMER" -H "Authorization: Bearer $TOKEN"

# Complete inventory
curl -s "$BASE/api/reports/daily?tenant=$CUSTOMER&view=all" -H "Authorization: Bearer $TOKEN"

# Consolidated report, all customers — without the “tenant” parameter
curl -s "$BASE/api/reports/daily" -H "Authorization: Bearer $TOKEN"

# The same, as PDF
curl -s -OJ "$BASE/api/reports/daily?tenant=$CUSTOMER&format=pdf" \
  -H "Authorization: Bearer $TOKEN"

Structure of the JSON

The fields useful to whoever consumes the report:

Field Content
day report date
kind tenant or consolidated
summary counters: devices, ok, exceptions, failing, stale, coverage_pct, changed, transport_fallbacks
exceptions the devices calling for action, ranked by severity
by_tenant one section per customer; contains devices in all view
agents each agent's state, including lab_mode and staging_used_pct

Each device row carries in particular state (ok, never, stale, failing), last_success_at, last_success_age_label, last_error, transport_used, transport_fell_back, schedule and next_run_label.

lab_mode deserves particular attention: an agent in lab mode produces backups that correspond to no real device. Monitoring that consumes this report must treat that flag as an alarm, not as a detail.

Freezing a report

A report can be kept as it stood on a given day:

curl -s -X POST "$BASE/api/reports/daily/persist?tenant=$CUSTOMER" \
  -H "Authorization: Bearer $TOKEN"

# The reports kept on file
curl -s "$BASE/api/reports?tenant=$CUSTOMER&limit=30" -H "Authorization: Bearer $TOKEN"

That is what makes it possible to re-issue, six months later, exactly the document sent to the customer — and not a recomputation over data that has changed since.

What coverage measures

coverage_pct is the share of devices in the compliant state across the whole perimeter. A fleet at 100% is one where every device has a successful backup within its staleness tolerance — not one where everything was backed up today.

Audit log

The log covers views, not only modifications. It is the counterpart to the provider's staff having global access to every customer's data.

The audit log, filterable, with the cross-customer access review

The cross-customer filter is the access-review view: who, among the provider's staff, read which customer's data, and when.

Also via the API.

# The last 200 events
curl -s "$BASE/api/audit?tenant=$CUSTOMER" -H "Authorization: Bearer $TOKEN"

# Only staff access to a customer's data
curl -s "$BASE/api/audit?cross_tenant_only=true&limit=1000" \
  -H "Authorization: Bearer $TOKEN"

# Filter on a kind of action
curl -s "$BASE/api/audit?action=config.download&limit=500" \
  -H "Authorization: Bearer $TOKEN"
Requires audit:read. Every event carries the timestamp, the actor, their role, the action, the object, the customer concerned, the address and a structured detail.

The log is append-only: the application role holds neither the update right nor the delete right on that table, which makes the guarantee verifiable by an auditor rather than promised by the code.

Storage compliance

Settings → Storage compliance genuinely queries the object store and reports the state of versioning, of locking and of the service accounts, customer by customer. An auditor asks for the proof, not the intention.

Also via the API.

curl -s "$BASE/api/compliance/storage" -H "Authorization: Bearer $TOKEN"
Answers 503 if the storage is unreachable — an absence of answer is information, not a success.