1a778e1334
- events table (kind, article_id, visitor_hash, day) with a UNIQUE key that dedups to one row per visitor-day — caps volume and makes counts mean distinct visitor-days. NO ip/ua/referrer/url. Groupings derived from article_id at query time, never stored. - POST /api/events (public): whitelisted kinds (visit/open/share_ub/copy_source/ native_share/source_click); visitor token hashed server-side (never raw). - Frontend analytics.js: random localStorage visitor token; track() via sendBeacon; visit once/day; open on article click; share_ub/copy_source/native_share from the share menu; /a landing pages fire source_click. 127 tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>