# WireBuddy ## Purpose WireBuddy is a self-hosted WireGuard management platform ("Use WireGuard with ease!"). It is a FastAPI application (Python 3.13, MIT) with a server-rendered Bootstrap 5 UI. It manages multiple WireGuard interfaces and peers, provides an integrated Unbound DNS ad-blocker (blocklists, DoT, DNSSEC, query log), multi-node clustering, a built-in time-series DB for traffic metrics, GeoIP/ASN analysis, HTTPS/Let's Encrypt handling, and multi-user auth (roles, passkeys, TOTP). It ships as a Docker image (linux/amd64, linux/arm64). ## Key Files | File | Description | |------|-------------| | `run.py` | Local entry point: loads `.env`, then hands over to `app/server.py` (config, DB schema, uvicorn, HTTPS plus the port-80 ACME listener when built-in TLS is active). Not shipped in the Docker image | | `pyproject.toml` | Single source of truth for the release version and Python dependencies (runtime + `dev`/`docs` extras); also read by the Docker build | | `setup.conf` | Personal dev/deploy cheat sheet (venv setup, dev server, docker buildx). Local only and git-ignored, not tracked. Contains secrets/credentials: never copy its values into docs, commits or output | | `.trivyignore` | Trivy exceptions for the image scan in `docker-build.yml`; each entry needs a reason and an `exp:` date (file kept even when empty) | | `Caddyfile` | Reverse-proxy/HTTPS configuration | | `CHANGELOG.md` | Release notes; update for user-visible changes | | `README.md` | Public project overview and feature list | | `LICENSE` | MIT | ## Subdirectories | Directory | Purpose | |-----------|---------| | `app/` | The application: API, DB layer, DNS, node sync, scheduled tasks, UI assets (see `app/AGENTS.md`) | | `docker/` | Dockerfile, entrypoint and compose files (see `docker/AGENTS.md`) | | `docs/` | User/developer documentation site sources (see `docs/AGENTS.md`) | | `tests/` | pytest suite for the backend plus the `tests/e2e/` browser drivers (see `tests/AGENTS.md`) | | `tools/` | Developer tooling: the Playwright-based UI linter, a standalone Stylelint setup for the CSS, plus two helpers, `pyproject-deps.py` (CI) and `ci-seed-admin.py` (local audit seeding) (see `tools/AGENTS.md`) | | `.github/` | CI workflows (PR gate, release, docs), screenshots and agent prompt files (see `.github/AGENTS.md`) | ## For AI Agents ### Working In This Directory - Python files are indented with **tabs** and start with the standard header block (file path, copyright, SPDX `MIT`); keep that style. `ruff format` (`indent-style = "tab"`, line length 160, double quotes) produces exactly this layout and the tree is formatted with it; never re-indent with spaces. - Persistent data lives in `data/` (SQLite + TSDB, git-ignored). Never commit `*.db`, `*.mmdb`, `.env` or `BUILD_INFO`. - Backup/restore (v2, since 1.5.2) includes schema **and** configuration (+ optional TSDB metrics); an empty restore is a bug. - Do not add Claude co-author / "Generated with Claude Code" attribution to commits or PR descriptions (user preference). - Start the dev server with `python run.py` inside the venv (see `setup.conf` for the exact steps); requires `WIREBUDDY_SECRET_KEY`. ### Testing Requirements - Backend: `pytest` from the repo root (tests in `tests/`). Gated on every PR by `.github/workflows/ci.yml`. - Lint: `ruff check .`; format: `ruff format .`, checked by `ruff format --check .` in CI. The **full** configured rule set gates every PR and the tree is at zero findings. Deliberate exemptions live in `pyproject.toml` with the reasoning beside each one; narrower cases carry a per-line `# noqa` naming the reason. Fix rather than exempt, and if a rule genuinely does not apply, annotate the line instead of widening the ignore list. - Container: `bash -n docker/entrypoint.sh` and `docker build --check -f docker/Dockerfile .`. Both gate PRs, because the image itself is only built from a release tag. - Frontend/UI (preferred): browser checks run against an isolated throwaway instance with the central toolset, `PLAYWRIGHT_DIR=/opt/ux-test-tools PYTHON=.venv/bin/python node tests/e2e/.mjs ` (`ui_lint_isolated.mjs`, `live_resize.mjs`, `ios_viewport_audit.mjs`; `PLAYWRIGHT_BROWSER`/`COLOR_SCHEME` select the matrix cell). See `tests/e2e/AGENTS.md`; Lightpanda is for fast non-visual DOM checks. Drivers are not part of `pytest`. - Frontend/UI (manual): the Playwright audit needs a running instance, its own `npm install` and credentials from the environment — `cd tools/ui-lint && npm install && npm run install:browsers`, then `UI_LINT_USERNAME=... UI_LINT_PASSWORD=... npm run audit`. `run-ui-lint.mjs` aborts if either variable is unset; never hard-code them. On a fresh database seed the account first with `tools/ci-seed-admin.py`, or the first-boot bootstrap gate leaves every view unreachable — `tools/AGENTS.md` has the full recipe. See `tools/ui-lint/AGENTS.md` for the `UI_LINT_*` list. UX/UI audits run only locally; no CI workflow runs them. ### Common Patterns - FastAPI routers in `app/api/`, data access in `app/db/sqlite_*.py`, cross-cutting helpers in `app/utils/`, background jobs in `app/tasks/`. - Jinja2 templates in `app/templates/`, static assets (CSS design system, vanilla JS) in `app/static/`. ## Dependencies ### Internal - `app/` is the only runtime package; `docker/` packages it, `tests/` and `tools/` verify it. ### External - FastAPI + uvicorn, SQLite, Unbound, WireGuard tools, MaxMind GeoLite2, Bootstrap 5, Leaflet, Playwright (ui-lint only).