Pages (register, reset-password, invites) now redirect to bincio.org
like login already did. Admin user-state ops (reset-password-code,
suspend, unsuspend, delete account) are proxied to bincio-auth via
httpx so they write to the correct DB. Adds BINCIO_AUTH_API env var.
When --jwt-secret / BINCIO_AUTH_JWT_SECRET is set, auth is validated
locally by decoding the bincio-auth-issued JWT — no DB session lookup.
Falls back to existing DB-based session lookup when the flag is absent,
so standalone deployments keep working without any config change.
Changes:
- deps.py: add jwt_secret global, _decode_jwt helper, wire into
_current_user and _require_auth
- cli.py: add --jwt-secret option; log active auth mode on startup
- pyproject.toml: add PyJWT>=2.8 to serve and dev extras
New /api/admin/garmin-sync (GET) and /api/admin/garmin-sync/run (POST)
endpoints mirror the Strava equivalents, reading _garmin_sync_status.json
per user and exposing a run-now button. Admin page shows the Garmin table
below the Strava one, with auth_error/api_error/ok badges and live polling
while a sync is running.
serve/server.py is now 69 lines — app factory, middleware, and router
registration only.
New modules:
deps.py (168 lines) — module-level globals + auth dependency functions
models.py (85 lines) — all Pydantic request/response models
tasks.py (136 lines) — background workers and job tracker
routers/ — one file per domain (10 routers, ~2750 lines total)
auth.py, me.py, admin.py, activities.py, uploads.py,
segments.py, strava.py, garmin.py, ideas.py, feed.py
cli.py updated to set globals on deps instead of server.
88 new regression tests in tests/serve/ cover auth guards and key
behaviours for every router; 294 total passing after the split.