- PaperComponent header with "Select all" / "Clear" buttons; onMouseDown
preventDefault keeps the popup open when clicking them
- ListboxProps overscrollBehavior: contain prevents the dropdown list's
scroll from propagating to the page when reaching top/bottom
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace native datetime-local inputs with @mui/x-date-pickers DateTimePicker
(proper dark-themed calendar popover with time picker, DD/MM/YYYY HH:mm format,
min/max constraints between pickers, 24h clock)
- Replace single-host Select with Autocomplete (multiple, disableCloseOnSelect):
checkbox per option, chip display with limitTags=2, built-in search/filter
- getAnalyticsHosts() now unions traffic event hosts WITH all configured proxy host
domains (parsed from proxyHosts.domains JSON), so every proxy appears in the list
- analytics-db: buildWhere accepts hosts: string[] (empty = all); uses inArray for
multi-host filtering via drizzle-orm
- All 6 API routes updated: accept hosts param (comma-separated) instead of host
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Analytics default interval changed to 1h
- Add 'Custom' toggle option with datetime-local pickers (pre-filled to last 24h)
- Refactor analytics-db: buildWhere now takes from/to unix timestamps instead of Interval
- Export INTERVAL_SECONDS from analytics-db for route reuse
- All 6 API routes accept from/to params (fallback to interval if absent)
- Timeline bucket size computed from duration rather than hardcoded per interval
- Fix map country click highlight: bake isSelected into GeoJSON features (data-driven)
instead of relying on Layer filter prop updates (unreliable in react-map-gl v8)
- Split highlight into countries-selected (data-driven) and countries-hover (filter-driven)
- Show tooltip at country centroid when selected via table, hover takes precedence
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>