feat(shortener): public redirect + async click tracking + QR + analytics (B3-B4)#65
Conversation
…ics (B3-B4) - app/redirect.py: public GET /<short_code> → 302 to long_url (404 for unknown/ inactive/expired), destination re-validated before redirect. Click tracking is non-blocking (asyncio.create_task after the response); click_count incremented atomically. link_clicks stores ip_hash (salted SHA256, never raw IP) + UA-parsed device/browser/os + referer. - QR: GET /api/v1/urls/<id>/qr (auth + urls:read + tenant-scoped) returns on-demand PNG of the short URL (qrcode+Pillow), not stored. TODO(tiering) branded/color QR. - app/analytics.py: /analytics/urls/<id> (per-link: total, clicks-by-day, top referers) and /analytics/summary (tenant-wide totals, top links, time series), analytics:read + tenant-scoped. Basic tiers implemented; geo/device/browser breakdowns marked TODO(tiering) for the Enterprise advanced-analytics gate. - deps: qrcode, Pillow, user-agents (pinned+hashed via uv). Tests: 619 passed, 90.66% coverage — redirect/404/expiry, async click + ip_hash, QR png, analytics date-filter/pagination/tenant-isolation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Sorry @PenguinzTech, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Feature (Track B, part 2) — redirect, tracking, QR, analytics
Stacked on #63 (base =
feature/shortener-api). Targetsrelease/v0.1.x.app/redirect.py) — publicGET /<short_code>→ 302 to long_url (404 for unknown/inactive/expired); destination re-validated before redirect. Click tracking is non-blocking (asyncio.create_taskafter the response);click_countincremented atomically.link_clicksstores ip_hash (salted SHA256, never raw IP) + UA-parsed device/browser/os + referer.GET /api/v1/urls/<id>/qr(auth +urls:read+ tenant-scoped) returns an on-demand PNG of the short URL (qrcode+Pillow), not stored. Branded/color QR left as a Professional-tier TODO.app/analytics.py) —/analytics/urls/<id>(per-link: total, clicks-by-day, top referers) and/analytics/summary(tenant totals, top links, time series),analytics:read+ tenant-scoped. Basic tiers implemented; geo/device/browser breakdowns markedTODO(tiering)for the Enterprise advanced-analytics gate.qrcode,Pillow,user-agents(pinned + hashed via uv).Tests
619 passed, 90.66% coverage — redirect/404/expiry, async click + ip_hash (no raw IP), QR png bytes, analytics date-filter/pagination/tenant-isolation.
🤖 Generated with Claude Code