Adds visitor dashboard and related features
This commit is contained in:
@@ -26,6 +26,30 @@ See [README.md](README.md) for a full architecture map. Key files:
|
||||
- `backend/app/main.py` — FastAPI entry point (CORS, router registration)
|
||||
- `backend/app/models.py` — SQLAlchemy ORM (Show, Event, StationConfig)
|
||||
|
||||
### Admin dashboard — visitor stats (implemented)
|
||||
|
||||
Nginx access logs → shared volume → FastAPI log parser → PostgreSQL → admin dashboard. No extra services.
|
||||
|
||||
**How it works:**
|
||||
1. Nginx writes structured JSON access logs to **daily log files** on a shared mount: `/logs/access-YYYY-MM-DD.log`. A `map` directive in [nginx.conf.template](nginx.conf.template) extracts the date from the ISO timestamp, so Nginx rotates to a new file at midnight.
|
||||
2. FastAPI ([backend/app/log_parser.py](backend/app/log_parser.py)) maintains a **"last parsed date"** (at most yesterday) persisted in PostgreSQL via the `LogParseState` model. On each run it scans `/logs/` for unprocessed daily files, enriches entries with IP geolocation (MaxMind GeoLite2 City), and stores aggregates.
|
||||
3. Aggregates are persisted in `visitor_stats_daily` (unique visitors per day) and `visitor_stats_geo` (country/city breakdown) tables.
|
||||
4. Admin dashboard (Angular) reads from stats API endpoints in [backend/app/api/stats.py](backend/app/api/stats.py).
|
||||
|
||||
**Key files:**
|
||||
- `backend/app/log_parser.py` — log file parsing + geo enrichment + `process_unparsed_logs()`
|
||||
- `backend/app/api/stats.py` — stats API endpoints (summary, timeseries, geo, parse trigger)
|
||||
- `backend/app/models.py` — `VisitorStatDaily`, `VisitorStatGeo`, `LogParseState` ORM models
|
||||
- `backend/inject_test_logs.py` — test data injector (writes test log entries for yesterday)
|
||||
- `nginx.conf.template` — JSON log format (`kmtn_json`) with daily rotation via `$log_date` map
|
||||
- `backend/geo/GeoLite2-City.mmdb` — MaxMind geolocation database
|
||||
|
||||
**Why daily files:** The currently-being-written file is never read — no partial lines, no race conditions, no file locking. Stats have a minimum one-day lag.
|
||||
|
||||
**Deployment context:** Single-node minikube, `hostPath` PersistentVolume with `ReadWriteMany`, or docker-compose named volume mounted in both pods.
|
||||
|
||||
**Injecting test data:** Run `backend/inject_test_logs.py` (or the inline docker compose command in README.md) to write test log entries for yesterday, then trigger parsing via `GET /api/parse`.
|
||||
|
||||
## Common tasks
|
||||
|
||||
- **Re-skin:** Edit colors in `_variables.scss` only.
|
||||
|
||||
Reference in New Issue
Block a user