wiregui/CLAUDE.md
Stefano Bertelli 0546b44507
Some checks failed
CI / test (push) Failing after 26s
CI / release (push) Has been skipped
CI / docker (push) Has been skipped
feat: initial WireGUI implementation — full VPN management platform
Complete Python/NiceGUI rewrite of the Wirezone (Elixir/Phoenix) VPN
management platform. All 10 implementation phases delivered.

Core stack:
- NiceGUI reactive UI with SQLModel ORM on PostgreSQL (asyncpg)
- Alembic migrations, Valkey/Redis cache, pydantic-settings config
- WireGuard management via subprocess (wg/ip/nft CLIs)
- 164 tests passing, 35% code coverage

Features:
- User/device/rule CRUD with admin and unprivileged roles
- Full device config form with per-device WG overrides
- WireGuard client config generation with QR codes
- REST API (v0) with Bearer token auth for all resources
- TOTP MFA with QR registration and challenge flow
- OIDC SSO with authlib (provider registry, auto-create users)
- Magic link passwordless sign-in via email
- SAML SP-initiated SSO with IdP metadata parsing
- WebAuthn/FIDO2 security key registration
- nftables firewall with per-user chains and masquerade
- Background tasks: WG stats polling, VPN session expiry,
  OIDC token refresh, WAN connectivity checks
- Startup reconciliation (DB ↔ WireGuard state sync)
- In-memory notification system with header badge
- Admin UI: users, devices, rules, settings (3 tabs), diagnostics
- Loguru logging with optional timestamped file output

Deployment:
- Multi-stage Dockerfile (python:3.13-slim)
- Docker Compose prod stack (bridge networking, NET_ADMIN, nftables)
- Forgejo CI: tests → semantic versioning → Docker registry push
- Health endpoint at /api/health
2026-03-30 16:53:46 -05:00

5.2 KiB

WireGUI

Project Overview

WireGUI is a Python rewrite of the Wirezone VPN management platform (Elixir/Phoenix). Original source: /home/stefanob/PycharmProjects/personal/wirezone

Tech Stack

  • UI Framework: NiceGUI (reactive server-side UI over WebSocket)
  • ORM/Models: SQLModel (SQLAlchemy + Pydantic)
  • Database: PostgreSQL (via asyncpg)
  • Cache/Sessions: Valkey (Redis-compatible)
  • Migrations: Alembic
  • REST API: FastAPI (built into NiceGUI)
  • Auth: authlib (OIDC), python-jose (JWT), pyotp (TOTP), webauthn, bcrypt
  • VPN: subprocess calls to wg and ip commands
  • Firewall: python-nftables or subprocess nft
  • Python: 3.13
  • Package Manager: uv

Development Setup

uv sync                          # Install dependencies
docker compose up -d             # Start PostgreSQL and Valkey
alembic upgrade head             # Run migrations
uv run python -m wiregui.main    # Start the application

Project Structure

wiregui/
├── main.py              # NiceGUI entrypoint, mounts FastAPI, starts background tasks
├── config.py            # pydantic-settings: Settings class
├── db.py                # async SQLAlchemy engine + sessionmaker
├── redis.py             # Valkey connection pool
├── models/              # SQLModel table definitions
│   ├── user.py
│   ├── device.py
│   ├── rule.py
│   ├── mfa_method.py
│   ├── oidc_connection.py
│   ├── api_token.py
│   ├── connectivity_check.py
│   └── configuration.py
├── schemas/             # Pydantic request/response schemas (non-table)
├── auth/                # Authentication modules
│   ├── passwords.py     # bcrypt hashing
│   ├── jwt.py           # JWT create/verify
│   ├── session.py       # NiceGUI session middleware
│   ├── oidc.py          # authlib OIDC
│   ├── saml.py          # python3-saml
│   ├── mfa.py           # TOTP + WebAuthn
│   └── api_token.py     # API token auth
├── api/v0/              # REST API routers
│   ├── users.py
│   ├── devices.py
│   ├── rules.py
│   └── configuration.py
├── pages/               # NiceGUI page definitions
│   ├── layout.py        # shared sidebar/header
│   ├── login.py
│   ├── devices.py       # user device CRUD
│   ├── account.py       # user account/MFA
│   ├── mfa_challenge.py
│   └── admin/           # admin pages
│       ├── users.py
│       ├── devices.py
│       ├── rules.py
│       ├── settings.py
│       └── diagnostics.py
├── services/            # Core services
│   ├── wireguard.py     # WG interface management
│   ├── firewall.py      # nftables rule management
│   ├── events.py        # DB → WG/firewall bridge
│   ├── notifications.py # in-memory notification queue
│   └── email.py         # aiosmtplib
├── tasks/               # Background tasks
│   ├── vpn_session.py   # expire VPN sessions
│   ├── stats.py         # poll WG stats
│   ├── connectivity.py  # WAN connectivity checks
│   └── oidc_refresh.py  # refresh OIDC tokens
└── utils/               # Utilities
    ├── crypto.py        # keypair gen, Fernet encrypt/decrypt
    ├── network.py       # IP allocation, CIDR validation
    └── validators.py    # shared validators
alembic/
├── env.py
├── script.py.mako
└── versions/

Commands

  • uv sync — install/update dependencies
  • uv run python -m wiregui.main — run the app
  • alembic revision --autogenerate -m "description" — create migration
  • alembic upgrade head — apply all migrations
  • alembic downgrade -1 — rollback last migration
  • docker compose up -d — start local Postgres + Valkey
  • docker compose down — stop local services
  • pytest — run tests

Conventions

  • Use SQLModel for all database models (combines SQLAlchemy table + Pydantic validation)
  • Use async database sessions with asyncpg
  • Place all NiceGUI pages in wiregui/pages/
  • Place all SQLModel table models in wiregui/models/
  • Place Pydantic request/response schemas in wiregui/schemas/
  • Use Alembic autogenerate for migrations
  • Background tasks use asyncio (create_task + while/sleep pattern)
  • WireGuard/nftables managed via subprocess (asyncio.create_subprocess_exec)
  • DB is source of truth; WG/firewall state is reconciled on startup

Logging — MANDATORY

  • Use loguru for ALL logging and messages. No print() statements allowed anywhere in this project.
  • Import: from loguru import logger
  • Use logger.info(), logger.warning(), logger.error(), logger.debug(), etc.
  • Loguru is configured in wiregui/logging.py via setup_logging()
  • When WG_LOG_TO_FILE=true (default), timestamped log files are written to logs/ in the project root
  • The logs/ directory is gitignored

Testing

  • Tests live in tests/ mirroring the wiregui/ structure
  • Run with uv run pytest
  • Use pytest-asyncio for async tests
  • Test database: uses same Postgres instance, separate wiregui_test database