74 lines
3.9 KiB
Markdown
74 lines
3.9 KiB
Markdown
# CLAUDE.md
|
||
|
||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
||
## Development Commands
|
||
|
||
```bash
|
||
# Local setup
|
||
python -m venv .venv
|
||
source .venv/Scripts/activate # Windows Git Bash
|
||
pip install -r requirements.txt
|
||
cp .env.example .env # fill in values
|
||
|
||
# Run locally (pick any free port; earlier dev sessions may occupy 8080–8094)
|
||
uvicorn app.main:app --reload --port 8080
|
||
|
||
# Skip Authentik login entirely during local dev
|
||
AUTH_DISABLED=true uvicorn app.main:app --reload --port 8080
|
||
|
||
# Docker
|
||
docker build -t qwe-salus:latest .
|
||
docker compose up
|
||
```
|
||
|
||
There are no tests and no linter configured.
|
||
|
||
## Architecture
|
||
|
||
### Request flow
|
||
|
||
```
|
||
Browser → FastAPI (main.py)
|
||
├── auth.py – Authentik OIDC + session management
|
||
├── omada.py – Omada Controller API client (singleton)
|
||
└── database.py – SQLAlchemy / SQLite audit log
|
||
```
|
||
|
||
Templates extend `base.html` (nav, footer, toast system). TailwindCSS is loaded from CDN — no build step.
|
||
|
||
### Critical: module-level `os.getenv()` ordering
|
||
|
||
`app/main.py` calls `load_dotenv()` **before** any `from app.*` imports. `omada.py` and `auth.py` read their config via `os.getenv()` at module load time, so `.env` must be loaded first. Moving `load_dotenv()` below those imports silently breaks all env var config.
|
||
|
||
### OmadaClient (`app/omada.py`)
|
||
|
||
A module-level singleton (`omada_client`). Key behaviour:
|
||
|
||
- **Two separate `httpx.AsyncClient` instances**: `_get_client()` carries the web session cookie (`TPOMADA_SESSIONID`); `_get_openapi_client()` is cookie-free. Mixing them causes 401s on the OpenAPI token endpoint.
|
||
- **Auth flow**: `_fetch_omadac_id()` → `_login()` (username/password → CSRF token + session cookie) → `_fetch_sites()`. `_ensure_ready()` gates all public methods.
|
||
- **Sites are fetched from** `GET /api/v2/users/current` → `result.privilege.sites[]`, not `/api/v2/sites` (which requires root admin and returns empty for regular admins).
|
||
- **Devices list**: `GET /{omadacId}/api/v2/sites/{siteKey}/devices` filtered by `type == "ap"`. There is no `/aps` endpoint in v6.x.
|
||
- **Reboot**: `POST /{omadacId}/api/v2/sites/{siteKey}/cmd/devices/{mac}/reboot` via the web session client. Response `errorCode: -39009` with `"Rebooting... Please wait."` is the success response — treat it as non-error alongside `0`. OpenAPI client credentials (`OMADA_CLIENT_ID`/`OMADA_CLIENT_SECRET`) are no longer used for reboot.
|
||
- **Session expiry** is handled in `_request_with_retry`: error codes `-1006`, `-1003`, `-30109` trigger automatic re-login.
|
||
- **Uptime safety check**: `reboot_ap()` re-fetches live uptime before issuing the command; it raises if `uptimeLong < 300` seconds (5 minutes). The UI also disables the reboot button client-side for the same condition.
|
||
|
||
### Authentication (`app/auth.py`)
|
||
|
||
Authentik OIDC Authorization Code Flow. The JWT `id_token` is decoded **without signature verification** (Authentik is a trusted internal IdP). User dict `{username, email, name, sub}` is stored in the Starlette signed-cookie session.
|
||
|
||
`AUTH_DISABLED=true` injects a hardcoded `DEV_USER` on `/auth/login` — no Authentik required.
|
||
|
||
All POST API endpoints (`/api/reboot`, `/api/reboot-bulk`) validate a CSRF token stored in the session and echoed in the JSON request body.
|
||
|
||
### Database (`app/database.py`)
|
||
|
||
Single table `reboot_log` written on every reboot attempt (success and error). `DB_PATH` defaults to `/data/audit.db` (Docker volume mount). Override to `./audit.db` for local dev.
|
||
|
||
### Deployment
|
||
|
||
- Docker exposes port `8080`; `docker-compose.yml` maps it to host port `8098`.
|
||
- Uvicorn runs with `--proxy-headers --forwarded-allow-ips=*` to trust `X-Forwarded-Proto` from Nginx Proxy Manager.
|
||
- The `/health` endpoint is used by the Docker healthcheck.
|
||
- `/debug/sites` is a diagnostic endpoint that lists all accessible Omada sites — useful for verifying credentials without touching the UI.
|