Andrey Antukh f17fbbf546 🎉 Add telemetry anonymous event collection
When the :telemetry flag is ON and :audit-log is OFF, frontend and
backend events are stored anonymously in the audit_log table and
shipped in compressed batches by the existing telemetry task.

Stored rows strip props and ip-addr but preserve the profile-id, since
Penpot profile UUIDs are already anonymous random identifiers with no
PII attached. Timestamps are truncated to day precision to avoid leaking
exact event timing. Only a safe subset of context fields is preserved:

- Backend events: initiator, version, client-version, client-user-agent
- Frontend events: browser, os, locale, screen metrics and event-origin

Backend (app.loggers.audit):
- Store backend telemetry events with source='telemetry', the safe
  context subset described above, and timestamps truncated to day
  precision via ct/truncate.

Frontend RPC (app.rpc.commands.audit):
- Add filter-safe-context to retain only the allowed frontend context
  fields.
- Add xf:map-telemetry-event-row transducer that anonymises frontend
  events before inserting them.
- push-audit-events now accepts events when telemetry is active.

Telemetry task (app.tasks.telemetry):
- gc-telemetry-events: enforces a 100,000-row safety cap by dropping
  the oldest rows first.
- collect-and-send-audit-events: loop that fetches up to 10,000 rows
  per iteration, encodes and sends each page, deletes it on success,
  and stops immediately on failure leaving remaining rows for retry.
- send-event-batch: POSTs a fressian+zstd batch (base64-encoded via
  blob/encode-str) to the telemetry endpoint, including instance-id
  and profile-id per event.
- delete-sent-events: deletes successfully shipped rows by id.

Blob utilities (app.util.blob):
- Add blob/encode-str and blob/decode-str: convenience wrappers that
  combine blob encoding with base64 for JSON-safe string transport.

Database:
- Add index on audit_log (source, created_at ASC) to support efficient
  queries for telemetry batch collection.

Tests (backend-tests.tasks-telemetry-test):
- 21 tests, 94 assertions covering all code paths: disabled/enabled
  telemetry, no-events no-op, happy-path batch send and delete, failure
  retention, payload anonymity, context stripping, timestamp day
  precision, batch encoding round-trip, multi-page iteration, GC cap
  enforcement.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-04-21 14:47:43 +02:00
..
2026-04-21 14:47:43 +02:00