Sets up the project skeleton: - FastAPI app factory with lifespan, request-id middleware, and RFC 9457 problem+json error handlers - Async SQLAlchemy 2.0 over MySQL (asyncmy), with a constraint naming convention in place before the first migration and async Alembic - Keycloak as a pure resource server: OIDC discovery, cached JWKS with rotation-aware refresh, and require_roles dependencies - Devcontainer running MySQL 8.4 and Keycloak 26.7 as compose siblings, with the realm (clients, roles, test users) imported on first boot - Test suite covering the endpoints plus the token validator itself, exercised against a locally generated RSA keypair - uv packaging, ruff, mypy --strict, pre-commit, Gitea CI, prod Dockerfile Two Keycloak-in-containers traps are handled explicitly and documented in the README: the issuer/internal-URL split (the browser sees localhost:8080, the API sees keycloak:8080) and the audience mapper that stops Keycloak issuing tokens with aud=account. The devices resource is a placeholder proving the routing -> auth -> ORM -> migration path end to end; replace it with the real domain. Co-Authored-By: Claude Opus 5 <[email protected]>
61 lines
1.8 KiB
Makefile
61 lines
1.8 KiB
Makefile
.DEFAULT_GOAL := help
|
|
.PHONY: help install dev migrate revision downgrade test lint fmt typecheck check shell db up down reset kc-export
|
|
|
|
help: ## Show this help
|
|
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
|
|
| awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-12s\033[0m %s\n", $$1, $$2}'
|
|
|
|
install: ## Sync the virtualenv from uv.lock
|
|
uv sync --frozen
|
|
|
|
dev: ## Run the API with autoreload on :8000
|
|
uv run uvicorn v2x_server.main:app --host 0.0.0.0 --port 8000 --reload
|
|
|
|
migrate: ## Apply migrations up to head
|
|
uv run alembic upgrade head
|
|
|
|
revision: ## Autogenerate a migration: make revision m="add widgets"
|
|
@test -n "$(m)" || (echo 'Usage: make revision m="description"' && exit 1)
|
|
uv run alembic revision --autogenerate -m "$(m)"
|
|
|
|
downgrade: ## Roll back one migration
|
|
uv run alembic downgrade -1
|
|
|
|
test: ## Run the test suite
|
|
uv run pytest
|
|
|
|
lint: ## Lint (no changes written)
|
|
uv run ruff check .
|
|
uv run ruff format --check .
|
|
|
|
fmt: ## Format and autofix
|
|
uv run ruff check --fix .
|
|
uv run ruff format .
|
|
|
|
typecheck: ## Static type check
|
|
uv run mypy
|
|
|
|
check: lint typecheck test ## Everything CI runs
|
|
|
|
shell: ## Python REPL with the app importable
|
|
uv run python
|
|
|
|
db: ## Open a MySQL shell on the dev database
|
|
mysql -h mysql -u v2x -pv2xpassword v2x
|
|
|
|
up: ## Start the backing services (outside the devcontainer)
|
|
docker compose up -d
|
|
|
|
down: ## Stop the backing services
|
|
docker compose down
|
|
|
|
reset: ## Destroy all data and start clean
|
|
docker compose down -v
|
|
docker compose up -d
|
|
|
|
kc-export: ## Re-export the realm after editing it in the Keycloak console
|
|
docker compose exec keycloak /opt/keycloak/bin/kc.sh export \
|
|
--realm v2x --file /tmp/realm-v2x.json --users realm_file
|
|
docker compose cp keycloak:/tmp/realm-v2x.json ./docker/keycloak/realm-v2x.json
|
|
@echo "Exported. Review the diff before committing -- exports include volatile fields."
|