Files
beardrive/internal/webapp
6f0f474903 feat(hub): count file changes and headless users server-side (#164)
The frontend's PostHog tracker sees everything a person clicks, but a
device syncing through /store/* never loads a page — so an agent editing
files all day was invisible, and "number of file changes" and "daily
active users" both undercounted by however much of the product runs
headless.

One event, files_changed, from every write door: sync, upload (relay and
direct commit), remove, restore. Its distinct_id is the same email
analytics.ts identifies with, so a person on a laptop and a browser is
one user, and its puts/deletes properties sum to the change count.

The count comes from ops the hub has not stored before, not from the
request body: a device PUTs its WHOLE journal every cycle, so counting
the body would re-report the device's entire history every ten seconds
and the metric would climb while nobody edited anything.
journalKeepsItsOps already parsed the stored journal for the append-only
check and threw the sequence away; it returns storedMax now, so this
costs no extra read. Blob PUTs are deliberately not change events —
content-addressed storage skips a blob it already holds, so blob writes
undercount edits while ops are exact.

No SDK: posthog-go would ship a tracker inside every self-hoster's
binary, which is the exact thing the frontend avoids by loading
posthog-js from a CDN only when a key is configured. Capture is one JSON
POST, on its own goroutine, that does nothing when Analytics.Key is
empty — an OSS hub still contacts nobody.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 14:50:25 -07:00
..