--- type: session date: 2026-05-28 tags: - unifi-access-dashboard - refactor - multi-controller - access - mpm --- # 2026-05-28 — UniFi Access Dashboard: multi-controller refactor ## Context Single-controller Flask app needed to support a client whose on-site server has LAN reach to multiple UniFi Access controllers. They want one dashboard showing badge events from all of them. ## Decisions made - Per-controller webhook URLs (`/api/unifi-access/`), legacy alias kept for back-compat. - Auto-register webhooks from the UI when adding a controller (drops the manual Python snippet from the old README). - **No admin auth, plaintext tokens in SQLite** — Jason explicitly chose LAN-only trust over the recommended Fernet + ADMIN_PASSWORD setup. Documented in [[unifi-access-dashboard]] so it doesn't get re-litigated. - Skipped CSV export for now (recommended bundle but Jason declined). - Auto-sync interval shortened from 6h to 1h late in the session. ## Files changed `app.py` (major rewrite), `static/index.html` (controllers modal + Source column + filter), `requirements.txt` (+pytz), `README.md` (UI-driven setup flow), `.env.example`, deleted `static/uad-landing.html`. ## Folded-in fixes - `datetime.utcnow()` → `datetime.now(timezone.utc)` - Cutoff string-compare bug (now sanitized to `HH:MM`) - Pinned `pytz` (was imported but undeclared) ## Not committed End of session: changes are on `main` working tree only. No commit or push. Run `docker compose up -d --build` to deploy. ## Open items - Existing webhook on Access side won't be cleaned up if user removes the seeded Default controller and re-adds via UI → duplicate events. Covered in project notes as a known gotchas. - Cross-controller identity merge (same human across sites) is explicitly out of scope.