# ADR-001: SQLite as the Application Database ## Status Accepted ## Context BanGUI needs a database to store application state: configuration, session records, blocklist sources, import logs, and ban history archives. ## Decision Use **SQLite** (via `aiosqlite`) as BanGUI's application database, persisted to a volume mounted from the host or a named Docker volume. ## Rationale ### Why SQLite over PostgreSQL? - **Zero-infrastructure:** No separate DB server process, no connection pooling, no credentials to manage. Ships in the Docker container with no additional configuration. - **Fail2ban-compatible:** The fail2ban database itself is SQLite. BanGUI already depends on SQLite; adding a second database engine would increase operational complexity for no benefit. - **Single-instance deployment:** BanGUI runs as a single service with one background scheduler (enforced by `BANGUI_WORKERS=1`). Horizontal scaling is not a design goal. - **Async I/O:** `aiosqlite` provides full async support, avoiding blocking I/O in the FastAPI async request handlers. ### Why not PostgreSQL? - Requires a separate service or sidecar container. - Adds connection overhead (TCP, connection pools, auth). - Over-engineered for a single-instance web app. ### Trade-offs - **Not suitable for multi-worker deployments.** SQLite's file-level locking means only one process can write at a time. This is explicitly enforced: `BANGUI_WORKERS=1` is validated at startup, and `scheduler_lock` prevents duplicate schedulers in restarts. - For future multi-instance deployments, BanGUI would need to migrate to PostgreSQL or add a distributed lock layer (Redis + job store). ## Consequences - Application database is a single file (`bangui.db`) in the container's data volume. - Backup is a file copy. No `pg_dump` equivalent needed. - Schema migrations managed via `app/startup.py` startup DAG.