explore lives at /u/{handle}/athlete/explore/ — was classified as
profile. Add path-contains check so it's detected correctly.
Add community (/community/) which was falling into the feed catchall.
Extend feature map tuples to (host, startswith, contains, label).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
resample("D") produces midnight-aligned bins; reindexing against a
range built from a raw timestamp (not midnight) caused all values to
be 0. Also switched the logins panel from daily to weekly to match the
feature usage panel — less noisy for a small app.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
scripts/usage_stats.py: standalone script (PEP 723, runs via uv run)
that parses all nginx access.log files, filters bots, maps Referer
headers to feature labels, and produces a 3-panel matplotlib figure:
daily logins + 7-day rolling mean, hour×weekday API heatmap, and
weekly feature usage stacked area. Output saved to
/var/bincio/stats/latest.png. Intended for a weekly cron job.
bincio/serve/routers/admin.py: GET /api/admin/stats serves the PNG
via the existing _require_admin() check — no new auth logic or nginx
changes needed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>