- Use Popup component for map-anchored tooltips (moves with lat/lng)
- Use filter+highlight layer for hover instead of feature state
- fitBounds to [-168,-56,168,74] to trim polar dead zones
- Country no-data color #1e293b vs ocean #0a1628 — clear contrast
- Visible borders rgba(148,163,184,0.18)
- Add 1h and 12h interval buttons to analytics UI
- formatTs handles 1h/12h with time-only format
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Parse Caddy access logs every 30s into traffic_events SQLite table
- GeoIP country lookup via maxmind (GeoLite2-Country.mmdb)
- 90-day retention with automatic purge
- Analytics page with interval (24h/7d/30d) and per-host filtering:
- Stats cards: total requests, unique IPs, blocked count, block rate
- Requests-over-time area chart (ApexCharts)
- SVG world choropleth map (d3-geo + topojson-client, React 19 compatible)
- Top countries table with flag emojis
- HTTP protocol donut chart
- Top user agents horizontal bar chart
- Recent blocked requests table with pagination
- Traffic (24h) summary card on Overview page linking to analytics
- 7 authenticated API routes under /api/analytics/
- Share caddy-logs volume with web container (read-only)
- group_add caddy GID to web container for log file read access
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>