3.8 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Commands
# Format
make reformat # uv run ruff format src/ tests/
# Lint (with auto-fix)
make lint # uv run ruff check src/ tests/ --fix
# Type checking
make typecheck # uv run ty check src/
# Tests
make test # uv run python -m pytest -v
uv run pytest tests/test_foo.py::test_specific # single test
# All checks
make check
# Dev server
OIDC_OP_ISSUER=http://localhost:8000 OIDC_OP_DEBUG=true \
uv run uvicorn porchlight.app:create_app \
--factory --host 127.0.0.1 --port 8000 --reload --reload-dir src
End-to-end tests (Playwright/Node)
# One-time setup
cd tests/e2e && npm install && npm run setup && cd ../..
# Run e2e tests (starts/stops the server automatically)
./tests/e2e/run.sh
# Run a specific spec
./tests/e2e/run.sh tests/e2e/login.spec.js
# Run with visible browser
E2E_HEADLESS=0 ./tests/e2e/run.sh
Architecture
Porchlight is an OpenID Connect (OIDC) Provider + user management app built on FastAPI with idpyoidc for the OIDC protocol layer. UI is server-side Jinja2 templates with HTMX for interactivity. Storage defaults to SQLite via aiosqlite.
Request flow
Browser/RP → FastAPI routes → Service classes → Repository layer → SQLite
↕
idpyoidc (OIDC protocol)
Module layout
src/porchlight/app.py— FastAPI app factory (create_app()), lifespan, middleware stacksrc/porchlight/config.py— Settings loaded from env vars (OIDC_OP_*prefix) and optional TOML filesrc/porchlight/models.py— Pydantic domain models (User,WebAuthnCredential,MagicLink,Consent)src/porchlight/validation.py— Form-validation models (ProfileUpdatewith email/phone/URL validation)src/porchlight/dependencies.py— FastAPI dependency injection helperssrc/porchlight/csrf.py— Synchronizer-token CSRF middleware (exempt:/token,/userinfo)src/porchlight/authn/— Password (argon2) and WebAuthn (fido2) authentication services + routessrc/porchlight/manage/— Authenticated user credential & profile management routessrc/porchlight/admin/— Admin user management routes (user list, invite creation, profile editing)src/porchlight/invite/— Magic-link invitation service (proquint tokens, time-limited)src/porchlight/oidc/— OIDC endpoints (discovery, JWKS,/authorization,/token,/userinfo)src/porchlight/store/— Repository pattern:protocols.pydefines interfaces;sqlite/has the concrete implementation;mongodb/is a stubsrc/porchlight/cli.py— Typer CLI (create-invite,initial-admin)
Storage layer
store/protocols.py defines UserRepository, CredentialRepository, MagicLinkRepository, and ConsentRepository as Protocol classes. The SQLite implementation lives in store/sqlite/repositories.py. Migrations run automatically on startup from store/sqlite/migrations/*.sql.
Configuration
All settings use the OIDC_OP_ env-var prefix (see config.py). Key vars:
| Variable | Notes |
|---|---|
OIDC_OP_ISSUER |
Required. Must match the public-facing URL. |
OIDC_OP_SESSION_SECRET |
Session signing key |
OIDC_OP_DEBUG |
Enables Swagger UI |
OIDC_OP_SQLITE_PATH |
DB file path (default data/oidc_op.db) |
OIDC_OP_CONFIG_FILE |
Optional TOML file for clients and advanced config |
OIDC relying parties (clients) are defined in the TOML config file under [clients.<id>].
Test fixtures
tests/conftest.py provides:
settings— in-memory SQLite, test issuerclient— asynchttpx.AsyncClientwith ASGI transport- CSRF token extraction helper
Unit and integration tests use in-memory SQLite; e2e tests use a seeded file-based DB (tests/e2e/setup_db.py).