# Connections Dashboard with Background Health Checks ## Context Users currently access Evotor connection via a dedicated `/evotor` page linked from the navbar. As more integrations are planned, we need a unified **Connections** page where users can see all their connections at a glance, with real-time status indicators powered by background health checks. ## Plan ### 1. Model Changes — `web/models.py` Add to `EvotorConnection`: - `is_online` (Boolean, default=False, server_default="0") - `last_checked_at` (DateTime, nullable) ### 2. Alembic Migration Generate migration for the two new columns on `evotor_connections` table. ### 3. Config Addition — `web/config.py` Add `HEALTH_CHECK_INTERVAL_SECONDS: int = 600` (10 minutes default). ### 4. Background Health Checker — `web/health_checker.py` (new) - `check_evotor_connection(access_token) -> bool` — async, calls `GET https://api.evotor.ru/stores` with Bearer token, returns True if 200 - `run_health_checks()` — queries all `EvotorConnection` rows using its own `SessionLocal()`, checks each, updates `is_online` and `last_checked_at` - `health_check_loop(interval)` — infinite loop with `asyncio.sleep`, calls `run_health_checks()` ### 5. Wire Background Task — `web/main.py` Add FastAPI lifespan context manager: - On startup: `asyncio.create_task(health_check_loop(...))` - On shutdown: cancel the task - Register new connections router ### 6. Connections Route — `web/routes/connections.py` (new) `GET /connections` — requires auth, builds a list of connection descriptors: ```python connections = [{ "name": "Эвотор", "icon": "bi-shop", "connected": bool, "is_online": bool, "last_checked_at": datetime | None, "details": store_name, "connect_url": "/evotor", "disconnect_url": "/evotor/disconnect", }] ``` Future connections just append another dict — template stays generic. ### 7. Connections Template — `web/templates/connections.html` (new) Card per connection showing: - Icon + name + optional details (store name) - Status: green `bi-circle-fill` (online), red `bi-circle-fill` (offline), grey `bi-circle` (not connected) - Action button: "Подключить" (link to connect_url) or "Отключить" (POST form to disconnect_url) - Card footer with last check timestamp ### 8. Navbar Update — `web/templates/base.html` Replace "Эвотор" link with "Подключения" → `/connections`. ### 9. Evotor Callback Update — `web/routes/evotor.py` On successful OAuth callback, set `is_online=True` and `last_checked_at=func.now()`. ### 10. Evotor Template Back Link — `web/templates/evotor.html` Change "Вернуться в личный кабинет" → "Вернуться к подключениям" linking to `/connections`. ## Files Summary | File | Action | |------|--------| | `web/models.py` | Modify — add 2 fields | | `web/config.py` | Modify — add interval setting | | `web/main.py` | Modify — lifespan + router | | `web/routes/evotor.py` | Modify — set online on callback | | `web/routes/connections.py` | Create | | `web/health_checker.py` | Create | | `web/templates/connections.html` | Create | | `web/templates/base.html` | Modify — navbar | | `web/templates/evotor.html` | Modify — back link | | Alembic migration | Create | ## Verification 1. Run `alembic upgrade head` to apply migration 2. Start the app, verify background task logs appear 3. Visit `/connections` — should show Evotor as disconnected (grey) 4. Connect Evotor via `/evotor` — should redirect back, connections page shows green status 5. Disconnect — status returns to grey 6. Wait for health check interval or trigger manually — verify `is_online` and `last_checked_at` update