KPI: read more of what the servers already keep, and three outside sources #277

Merged
cruelacid merged 1 commit from worktree-kpi-more into main 2026-10-08 11:37:03 +01:00
Owner

Task: NEC-242

More from data that already exists, with no server telemetry. Nothing new is stored on the servers, and the sync path, presence and timing are untouched.

B: columns the servers already keep, now read by /api/kpi

  • Shard
    • Per person: first and last device enrolment, installs (vaults) and those active in the last 30 days, passphrase changes, and recovery attempts.
    • Per folder: when it was last attested (still open somewhere), checkpoints, and quarantined attachments.
  • Identity
    • Per user: passkeys used in the last 30 days and the last use, passphrase changes, and recovery attempts.
    • Device sessions as bare records (platform and timestamps) for sign-outs and session lifetime.
    • Orders: the queued plan change, grace_until and provider_ref.
    • Order events by kind only. Never raw_payload: a test plants a name in it, and exporting it makes that test fail (mutation-checked).
  • docs/security-model.md: the usage-metrics bullet now names these record types.

C: optional outside sources (collector only)

Each is skipped when its token is unset, runs hourly after the core collection commits, and writes in its own transaction. Every attempt is recorded in source_runs.

  • GlitchTip: errors per day by plugin version and platform. These are counted from events, because 6.2 has no daily-by-tag endpoint. Install ids are never kept.
  • Creem: subscriptions and transactions, by id only. v_billing_reconcile flags orders whose state disagrees with Creem's.
  • GitHub traffic: views, clones and referrers for the public plugin repo. GitHub keeps 14 days, so the store keeps every day it has seen.
  • Directory rank: from the stats file the collector already reads.

Dashboard

New rows: "Accounts and devices" and "Errors, billing and discovery".

Verified

  • pnpm test, typecheck, lint, build-mirror --check and build-dashboard --check all pass.
  • Unit tests cover each source with stubbed responses: paging stops at the window, a customer object is reduced to its id, views and clones merge by day, and a failing or unset source never throws. The two key rules are mutation-checked.
  • End to end, with a real shard and identity seeded with the new records, stub GlitchTip and Creem servers, and a store upgraded from main's schema:
    • The collector ran twice.
    • Every new view returned the expected values.
    • Reconciliation flagged only the planted mismatch.
    • No address reached the store.
    • All 53 panel queries ran through Grafana.

Not included: labelling people with email addresses on the dashboard (part 0 of the plan). That is left for a separate decision.

Changelog

NONE

🤖 Generated with Claude Code

https://claude.ai/code/session_01MY63BZ4UVtMHFcADNr1jFg

Task: NEC-242 More from data that already exists, with no server telemetry. Nothing new is stored on the servers, and the sync path, presence and timing are untouched. ## B: columns the servers already keep, now read by `/api/kpi` - **Shard** - Per person: first and last device enrolment, installs (vaults) and those active in the last 30 days, passphrase changes, and recovery attempts. - Per folder: when it was last attested (still open somewhere), checkpoints, and quarantined attachments. - **Identity** - Per user: passkeys used in the last 30 days and the last use, passphrase changes, and recovery attempts. - Device sessions as bare records (platform and timestamps) for sign-outs and session lifetime. - Orders: the queued plan change, `grace_until` and `provider_ref`. - Order events by kind only. **Never `raw_payload`**: a test plants a name in it, and exporting it makes that test fail (mutation-checked). - `docs/security-model.md`: the usage-metrics bullet now names these record types. ## C: optional outside sources (collector only) Each is skipped when its token is unset, runs hourly after the core collection commits, and writes in its own transaction. Every attempt is recorded in `source_runs`. - **GlitchTip:** errors per day by plugin version and platform. These are counted from events, because 6.2 has no daily-by-tag endpoint. Install ids are never kept. - **Creem:** subscriptions and transactions, by id only. `v_billing_reconcile` flags orders whose state disagrees with Creem's. - **GitHub traffic:** views, clones and referrers for the public plugin repo. GitHub keeps 14 days, so the store keeps every day it has seen. - **Directory rank:** from the stats file the collector already reads. ## Dashboard New rows: "Accounts and devices" and "Errors, billing and discovery". ## Verified - `pnpm test`, typecheck, lint, `build-mirror --check` and `build-dashboard --check` all pass. - Unit tests cover each source with stubbed responses: paging stops at the window, a customer object is reduced to its id, views and clones merge by day, and a failing or unset source never throws. The two key rules are mutation-checked. - **End to end**, with a real shard and identity seeded with the new records, stub GlitchTip and Creem servers, and a store upgraded from `main`'s schema: - The collector ran twice. - Every new view returned the expected values. - Reconciliation flagged only the planted mismatch. - No address reached the store. - All 53 panel queries ran through Grafana. Not included: labelling people with email addresses on the dashboard (part 0 of the plan). That is left for a separate decision. ## Changelog NONE 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01MY63BZ4UVtMHFcADNr1jFg
KPI: read more of what the servers already keep, and three outside sources
All checks were successful
Release note / release-note (pull_request) Successful in 17s
CI / build (pull_request) Successful in 5m31s
CI / e2e (pull_request) Successful in 10m3s
CI / promote (pull_request) Has been skipped
Deploy site / deploy (push) Successful in 54s
CI / build (push) Successful in 5m39s
CI / e2e (push) Successful in 9m54s
CI / promote (push) Successful in 31s
0d7b61b8f4
No server telemetry: nothing new is stored on the servers and the sync path
is untouched. The /api/kpi routes read columns that already existed:

- shard: when devices were added, installs (vaults) per person, passphrase
  changes and recovery attempts, when a folder was last open (attested),
  compactions and held-back attachments
- identity: passkey use, passphrase changes, recovery attempts, device
  sessions as bare records (sign-outs and lifetime), queued plan changes,
  the provider's order reference, and order events by kind only -- never the
  webhook payload, which carries the customer's name

The collector gains optional sources, each behind its own token, run hourly
after the core collection commits and each in its own transaction: GlitchTip
(errors per day by plugin version and platform, counted from events because
6.2 cannot split daily counts by tag), Creem (subscriptions and transactions
by id, reconciled against our orders) and GitHub repository traffic. Plus the
plugin's rank among all community plugins.

Task: NEC-242

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MY63BZ4UVtMHFcADNr1jFg
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Nectenda/nectenda!277
No description provided.