# AGENTS.md — IDRS API server Project conventions and operational gotchas for agents working in this repo. ## Layout - `app/main.py` — FastAPI app: public endpoints `GET /api/getTokenInfo`, `GET /api/version/android`, `GET /img/token/`; mounts `/static`; startup calls `db.init_db()`. - `app/admin.py` — sqladmin panel: `TokenAdmin` (custom WTForms form, `on_model_change`), `VersionAdmin`, `create_admin(app)`. Upload icons saved under `app/static/icons/token/` with `iconUrl = {IDRS_PUBLIC_URL}/img/token/`. - `app/models.py` — SQLAlchemy `Token`/`Version`, engine, `SessionLocal`, `ICON_DIR`, `DB_PATH` (env `IDRS_DB_PATH`). - `app/db.py` — seed from `tokenList.json`/`versionAndroid.json` (once, empty DB only). - `app/auth.py` — `AdminAuthBackend`, fail-closed creds. - `tokenList.json` / `versionAndroid.json` — seed source (read-only after seed). ## Environment / secrets - `.env` (gitignored) → `ADMIN_USERNAME`, `ADMIN_PASSWORD`, `IDRS_PUBLIC_URL` (default `https://idrs.databisnis.id`). Test creds `admin`/`testpass123` — change before exposure. - `.session_secret` (gitignored, auto-generated 0600) if `IDRS_SESSION_SECRET` unset. - NEVER bake `.env` into the Docker image; pass via `--env-file` / `-e`. - Untracked, never commit: `.env`, `.session_secret`, `idrs.db*`, `venv/`, `app/static/icons/*`. ## Run (local) - `./run.sh` loads `.env` then `uvicorn app.main:app --host 127.0.0.1 --port 8000`. - Start detached: `setsid nohup ./run.sh < /dev/null > /tmp/opencode/idrs.log 2>&1 & disown` (plain `&` hangs). - Sanity-import: `./venv/bin/python -c "from app import main; print('IMPORT_OK')"`. ## Docker - `docker build -t idrs-api .` - Run with volumes: `-v idrs-data:/app/data -v idrs-icons:/app/app/static/icons`, env via `--env-file .env`. - MUST use a single uvicorn worker (in-memory starlette sessions → `--workers >1` breaks login). - DB + uploaded icons persist in the volumes across container recreate; code changes need an image rebuild. ## Verification - curl login: `POST /admin/login` with `-c/-b` cookie jar; then curl admin endpoints / uploads with the jar. - Assert `/img/token/` returns `image/png`; HTML/oversize uploads rejected (400). ## Operation gotchas - NEVER `pkill -f uvicorn` broadly — a separate user process runs uvicorn on port 7000. Kill only the port-8000 PID (`ps -ef | grep "uvicorn app.main:app --host 127.0.0.1 --port 8000"`). - Local server binds 127.0.0.1:8000. Host ports 8080/8100 are taken by other services. ## Spec - Canonical invariants and task status live in `SPEC.md` (§V invariants, §T tasks, §B bug log). Keep it updated when behavior changes; check §V before modifying.