feat: add privacy-preserving click analytics and a /privacy page - #29
feat: add privacy-preserving click analytics and a /privacy page#29viganogabriele wants to merge 2 commits into
Conversation
Introduces the test harness (vitest, an in-memory Postgres via pg-mem, and `test`/`test:watch` scripts) with no real DB or secrets required, so future features can ship with unit tests. Included a UrlService smoke-test suite covering existing create/read/update/delete/search/sort/click-count behavior as the first consumer of the harness. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds aggregate-only click analytics per URL: hourly/daily/monthly click buckets, country-level breakdowns (via trusted edge/CDN headers only, never third-party IP geolocation), and a same-day unique-visitor estimate derived from a rotating HMAC hash. No raw IP address, User-Agent, or per-click timestamp is ever stored — the hash itself is purged within ~24-48h. New REST endpoint GET /urls/:shortCode/analytics, an "Analytics" dialog with hand-rolled bar charts (no charting dependency), and a /privacy page disclosing exactly what is and isn't collected. Scoped down from vigab.cc's version: that implementation also tracked per-alias analytics scopes (this repo has no alias/custom-domain concept), so this port is a single scope per URL — a later alias feature can extend the schema with a scope column if needed, rather than carrying unused complexity now. The privacy page's data-controller contact and hosting section use PoliNetwork placeholders (marked with TODOs) since only PoliNetwork can confirm the real contact address and infrastructure providers — do not treat this page as a complete legal disclosure until those are filled in. Builds on the vitest/pg-mem test infrastructure branch for its test suite. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 32 minutes Limit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (21)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
click_analytics_buckets,click_country_analytics,daily_unique_click_dedup) — never raw IP, User-Agent, or per-click timestamps.cf-ipcountry, Vercelx-vercel-ip-country, or a configurableGEO_COUNTRY_HEADER) — no third-party geolocation lookups.ANALYTICS_HASH_SECRET) that rotates every UTC day, so it can't track a visitor across days or links; the hash rows are purged after ~24-48h (opportunistic purge on ~2% of clicks, since serverless has no long-lived cron).GET /urls/:shortCode/analytics; an "Analytics" button/dialog on each URL row shows total clicks, today's unique estimate, top countries, a recent-trend sparkline, and hour/day/month bar charts (hand-rolled, no charting dependency added)./privacypage disclosing exactly what is and isn't collected, linked from the analytics dialog.next/server'safter()so it never delays or breaks the redirect; failures are logged generically (no IP/UA ever logged).Scope decisions
info@polinetwork.org, marked with aTODO(PoliNetwork)) and the "Hosting" section (deliberately generic — I don't know PoliNetwork's actual infrastructure providers, unlike vigab.cc's Vercel/Cloudflare-specific version) need PoliNetwork to confirm/fill in before this page is relied on as a complete legal disclosure. Flagging this explicitly rather than fabricating specifics.ANALYTICS_HASH_SECRETis a required new env var (min 16 chars) — vigab.cc falls back to itsNEXTAUTH_SECRET(an auth secret this repo doesn't have), so a dedicated required secret is the cleaner fit here. Documented in.env.example.Dependency
Builds on #27 (vitest + pg-mem test infra), same as #28 (tagging) — both add tests that need that harness. If #27 hasn't merged yet, this branch includes its commit; rebase onto
mainonce #27 merges.Test plan
pnpm test— 25 tests pass (analytics bucketing/dedup/purge logic, geo header parsing)pnpm check(biome) passespnpm buildsucceeds/privacy