Scheduled reports and the weekly digest #160

Merged
jcoffey-dev merged 3 commits from feature/scheduled-reports into main 2026-10-06 22:41:05 +00:00
Owner

Admin UX roadmap items 17 and 14: scheduled reports, with the weekly digest as the first one. Spec approved 2026-10-06 (inbuxa-drafts specs/scheduled-reports.md, RP-1 to RP-23). Server only; the console page comes next (inbuxa-admin).

What it does

  • A report: sections, a schedule (daily / weekly / monthly at a time in an IANA time zone, DST handled), recipients that must be accounts on this server (RP-23), optional CSV attachments.
  • Sections, built from data the server already keeps, each against the previous period and left out when empty: mail flow (incl. average delivery time), queue, spoofing (received DMARC), TLS failures, deliverability (Fail findings + what started/stopped failing since the last run, DL-21), security, storage (people at ≥90% of quota), certificates expiring within 21 days. A quiet period sends one line (Decision 6).
  • Mailed as text + HTML (links into the console when INBUXA_ADMIN_URL is set), Auto-Submitted: auto-generated, always DKIM-signed: a sender domain without a key fails the run with that reason (RP-14). New smtp::reporting::inbuxa_send::send_signed for that.
  • Weekly digest: built in, on by default (Decision 1), all sections, Mondays 07:00 UTC, to the system administrators; can be changed or turned off, not deleted.
  • Runner: every node checks once a minute; a run is claimed with KV_LOCK_TASK keyed by report + due time and recorded on the report, so it goes once per cluster; one catch-up run after downtime, not one per miss. Fork-owned loop (like inbuxa_lock_expiry), so the only schema change is two permissions.
  • Tenants: a tenant admin sees and makes only their tenant's reports, which leave out the server-wide sections; the sender settings are the server's.
  • Send now (sendNow: true on update), run history (last 20), failures in a row tracked for the dashboard (RP-17, console side).
  • Download (second commit): inbuxa:ReportExport/set create {reportId, from?, to?} builds the report for a period (default: its last full one; at most 90 days back) as a ZIP of summary.txt + section CSVs, stored as an upload, mails nobody; needs sysScheduledReportGet; tenant-scoped; audited. Doesn't move the deliverability baseline.

New: inbuxa:ScheduledReport, inbuxa:ScheduledReportSettings, inbuxa:ReportExport (/get, /set, writes in the audit log), sysScheduledReportGet / sysScheduledReportUpdate (granted once to existing admin and tenant-admin roles), privacy catalog entries + a source for the mail, SPEC.md §4 line.

Checked locally: model tests (schedule incl. a DST gap and the October clock change, validation, tenant sections), runner tests (CSV quoting, failing-fact keys, the quiet-week mail), system test system::scheduled_reports: digest present and undeletable, validation (outside recipient, bad zone, unknown section), create/update/delete, Send now refused without a DKIM key and sent signed with one, tenant scoping, sender settings, Download (ZIP with summary.txt, sha256, a 2020 period refused, a tenant refused another's report). CI's cargo build -p inbuxa --locked and cargo test --workspace --locked --no-run; every fork check (name, notice, context, privacy, expr-schema, tool tests); lib tests of registry, common, jmap.

Not run: the full system suite (it races on timing on every variant), and the scheduled path end to end at a real due time (the runner waits 90 s after start, then minute ticks; Send now exercises the same build and send).

Admin UX roadmap items 17 and 14: scheduled reports, with the weekly digest as the first one. Spec approved 2026-10-06 (inbuxa-drafts `specs/scheduled-reports.md`, RP-1 to RP-23). Server only; the console page comes next (inbuxa-admin). **What it does** - A report: sections, a schedule (daily / weekly / monthly at a time in an IANA time zone, DST handled), recipients that must be accounts on this server (RP-23), optional CSV attachments. - Sections, built from data the server already keeps, each against the previous period and left out when empty: mail flow (incl. average delivery time), queue, spoofing (received DMARC), TLS failures, deliverability (Fail findings + what started/stopped failing since the last run, DL-21), security, storage (people at ≥90% of quota), certificates expiring within 21 days. A quiet period sends one line (Decision 6). - Mailed as text + HTML (links into the console when `INBUXA_ADMIN_URL` is set), `Auto-Submitted: auto-generated`, **always DKIM-signed**: a sender domain without a key fails the run with that reason (RP-14). New `smtp::reporting::inbuxa_send::send_signed` for that. - **Weekly digest**: built in, on by default (Decision 1), all sections, Mondays 07:00 UTC, to the system administrators; can be changed or turned off, not deleted. - **Runner**: every node checks once a minute; a run is claimed with `KV_LOCK_TASK` keyed by report + due time and recorded on the report, so it goes once per cluster; one catch-up run after downtime, not one per miss. Fork-owned loop (like `inbuxa_lock_expiry`), so the only schema change is two permissions. - **Tenants**: a tenant admin sees and makes only their tenant's reports, which leave out the server-wide sections; the sender settings are the server's. - Send now (`sendNow: true` on update), run history (last 20), failures in a row tracked for the dashboard (RP-17, console side). - **Download** (second commit): `inbuxa:ReportExport/set` create `{reportId, from?, to?}` builds the report for a period (default: its last full one; at most 90 days back) as a ZIP of `summary.txt` + section CSVs, stored as an upload, mails nobody; needs `sysScheduledReportGet`; tenant-scoped; audited. Doesn't move the deliverability baseline. **New**: `inbuxa:ScheduledReport`, `inbuxa:ScheduledReportSettings`, `inbuxa:ReportExport` (`/get`, `/set`, writes in the audit log), `sysScheduledReportGet` / `sysScheduledReportUpdate` (granted once to existing admin and tenant-admin roles), privacy catalog entries + a source for the mail, SPEC.md §4 line. **Checked locally**: model tests (schedule incl. a DST gap and the October clock change, validation, tenant sections), runner tests (CSV quoting, failing-fact keys, the quiet-week mail), system test `system::scheduled_reports`: digest present and undeletable, validation (outside recipient, bad zone, unknown section), create/update/delete, Send now refused without a DKIM key and **sent signed** with one, tenant scoping, sender settings, Download (ZIP with summary.txt, sha256, a 2020 period refused, a tenant refused another's report). CI's `cargo build -p inbuxa --locked` and `cargo test --workspace --locked --no-run`; every fork check (name, notice, context, privacy, expr-schema, tool tests); lib tests of registry, common, jmap. Not run: the full system suite (it races on timing on every variant), and the scheduled path end to end at a real due time (the runner waits 90 s after start, then minute ticks; Send now exercises the same build and send).
jcoffey-dev added 1 commit 2026-10-06 21:41:57 +00:00
Scheduled reports and the weekly digest
ci / fork-checks (pull_request) Skipped
ci / build (pull_request) Skipped
github/ci (branch) GitHub Actions
ci / github (pull_request) Successful in 7m25s
ff5480cb55
An administrator picks sections, a schedule (daily, weekly or monthly,
at a time in a time zone) and recipients, who must be accounts on this
server. Every node looks for due reports once a minute; a run is claimed
with the task lock, keyed by report and due time, and recorded on the
report, so it goes once. The report is built from what the server
already keeps: mail flow, the queue, spoofing from received DMARC
reports, TLS failures, deliverability findings and what changed since
the last run, security counters, people near their quota, and expiring
certificates. It is mailed as text and HTML with optional CSV
attachments, DKIM-signed; a sender domain without a key fails the run
with that reason instead of sending unsigned.

The weekly digest is a built-in report on every server, on by default:
every section, Mondays 07:00 UTC, to the system administrators. It can
be changed or turned off, not deleted. A tenant administrator makes and
sees only their own tenant's reports, which leave out server-wide
sections.

New: inbuxa:ScheduledReport and inbuxa:ScheduledReportSettings, the
sysScheduledReportGet and sysScheduledReportUpdate permissions (granted
once to existing administrator roles), privacy catalog entries, and a
system test. Spec: inbuxa-drafts specs/scheduled-reports.md.
jcoffey-dev added 1 commit 2026-10-06 22:24:37 +00:00
Scheduled reports: Download, a report for a period as a ZIP
ci / fork-checks (pull_request) Skipped
ci / build (pull_request) Skipped
github/ci (branch) GitHub Actions
ci / github (pull_request) Canceled after 1m19s
09ccad4b4b
inbuxa:ReportExport/set creates {reportId, from?, to?}: the report built
for that period (its last full one by default, at most 90 days back, as
far as metrics are kept) as a ZIP of summary.txt and the section CSVs,
stored as an upload, mailing nobody. Reading needs sysScheduledReportGet,
as seeing the report does; a tenant administrator downloads only their
own; every download is in the audit log. A download doesn't move the
deliverability baseline the next mail compares with.
jcoffey-dev added 1 commit 2026-10-06 22:25:47 +00:00
Scheduled reports: a Management › Reports › Scheduled menu link
ci / fork-checks (pull_request) Skipped
ci / build (pull_request) Skipped
ci / github (pull_request) Successful in 8m45s
github/ci (branch) GitHub Actions
43b9f93ff7
The console's page for scheduled reports, first under Reports; the
mail's footer points there.
jcoffey-dev merged commit dc4525fee7 into main 2026-10-06 22:41:05 +00:00
jcoffey-dev deleted branch feature/scheduled-reports 2026-10-06 22:41:05 +00:00
Sign in to join this conversation.