2026-05-15 — Consolidate api/, adopt uv, bump Python 3.12, retire Functions¶
Scope: top-level layout, packaging, runtime.
Motivation¶
The repo carried two parallel backends:
api/— retired Azure Functions v2 + Durable Functions tree, no longer the deploy target after the move to Azure Container Apps.api_app/— the new FastAPI + Celery backend, in active use.
Two trees with overlapping module names (services/, routes/, …) cost
agent time on every search and made from services.X style imports break in
subtle ways. Bring them into one tree, name it api/, and at the same time
unify on uv + Python 3.12 so every developer / CI / Docker image runs on
the same exact toolchain.
User-facing change¶
None — this is a structural cleanup. The deployed /api/* surface is
unchanged.
API / IaC diff summary¶
Layout¶
api_app/→api/(git mv, history preserved).api/(legacy Functions tree) →legacy/functionapp/.infra/legacy/→legacy/infra/.scripts/cloud-init/→legacy/cloud-init/.scripts/dev/{bootstrap-local,deploy-api,generate-client-secret,setup-keyvault,start-azurite,teardown-local}.sh→legacy/scripts/dev/.
Dead code removed¶
api/services/compute.py— VM lifecycle helpers, 0 callers in active routes.api/services/ssh_exec.py— paramiko helper, onlycompute.pyimported it.api/_http_utils.py— Functions-shaped helpers (func.HttpResponse); would crash at import in the Container Apps image becauseazure-functionsis intentionally not inpyproject.toml.infra/modules/platform.bicep— orphan, byte-identical duplicate oflegacy/infra/platform.legacy.bicep.docs/ui-proposals/(6 HTML prototypes, ~125 KB) — zero references in the active codebase.
Packaging — uv + pyproject¶
- New
pyproject.toml[project]with the full dependency set + a[dependency-groups].devfor pytest / pytest-asyncio / ruff / mypy. uv.lock(1297 lines) is now the source of truth..python-versionpins 3.12.api/requirements.txtremoved.api/Dockerfilerewritten as a 2-stage build usingghcr.io/astral-sh/uv:0.9-python3.12-bookworm-slimto materialise the locked venv, thenpython:3.12-slimruntime — nopiporuvin the final image.terminal/Dockerfile:ubuntu:22.04+ deadsnakes PPA →ubuntu:24.04with nativepython3.12(PPA dependency dropped).
Tooling consistency¶
.vscode/launch.json+.vscode/tasks.json: every command goes throughuv run …; removed manualVIRTUAL_ENVexports..vscode/settings.json:python.defaultInterpreterPath+python.testing.pytestEnabled.scripts/dev/preflight-check.sh:uvadded to required-tool list.scripts/dev/setup-app-registration.sh: dropped the legacyapi/local.settings.jsonwriter + OBOAPI_CLIENT_SECRETnext-steps;web/.env.localdefaultVITE_API_BASE_URL→http://localhost:8080.web/vite.config.ts: dev proxy default →http://localhost:8080.pytest.initestpaths = api/tests;pyproject.tomlsrc = ["api"],target-version = "py312",mypy.python_version = "3.12",extend-exclude += "legacy"..dockerignore: dropapi/.python_packagesreference, prunelegacy/.
Docs¶
docs/container-apps-migration.mdretitled "Container Apps Architecture Reference"; trimmed migration narrative (Phase 0–5, Cutover, Rollback, Risks, Open Decisions, First Slice, Route Migration Map, Cost Comparison to prior plans, frontend SWA Old-vs-New table). 1327 → ~940 lines.docs/auth.md: every "Function App" / "system-assigned MI" → "api sidecar" / shared user-assigned MIid-elb-control; deleted Remote Terminal VM MI section + §4 "Virtual Machines" table; corrected Bicep modules table; rewrote §6 Security Notes (Storage actually Disabled, not Enabled).README.md: walkthrough section (295 lines) extracted tolegacy/walkthrough.md; dashboard preview / Architecture Planning / Roadmap / Authentication sections retoned for the sidecar model. 537 → 236 lines.
Validation¶
uv sync --all-groupscreates.venvon Python 3.12.10.uv run pytest -q api/tests→ 45 passed (after this commit; further tests added in the next two commits bring the count to 56).- 25-module import smoke clean (
api,api.main,api.celery_app,api.services.*,api.routes.*). uv run ruff check apibaseline: 125 (pre-existing style; no regressions).uv run uvicorn api.main:app --host 127.0.0.1 --port 8080→/api/health200,/api/docs200.az bicep build infra/main.bicepexit 0 (5 pre-existingno-hardcoded-env-urlswarnings; unrelated).
Cross-repo consistency¶
AGENTS.md (added in commit 3) records the active-vs-retired layout for
future agents.