Containerize the API with a persistent volume #183

Member

Task d45cc3d2-fc99-4d8a-a9b0-7b3f55b53261 (Feature 17 - API Deployment and Identity).

Why

The API deployable had no packaging of its own: its runtime deps lived only in the integration's dev group, so there was no way to deploy the service without dragging the test venv along.

What

  • api/requirements.txt — the API deployable's OWN runtime manifest (fastapi, uvicorn, pyjwt[crypto], httpx; per the pyproject comment these must not live in the integration's groups).
  • Dockerfile (repo-root build context) — multi-stage python:3.12-slim, no toolchain left behind, non-root user, serves uvicorn --factory api.app:create_app; carries api/ and the bundled custom_components/nestquest/core/ (loaded by file location).
  • deploy/compose.yaml — SQLite file /var/lib/nestquest/nestquest.db on the NAMED VOLUME nestquest-db; port bound to localhost only (TLS/reverse proxy, Authentik, network separation are later tasks).
  • deploy/.env.example (committed, placeholder names with empty values) → real deploy/.env is git-ignored; .dockerignore keeps the build context minimal; .gitignore also ignores .env, *.db, WAL sidecars.
  • api/README.md — short deploy scaffold doc.

Done-condition proof (real Docker)

  1. docker build -t nestquest-api:latest . → image built.
  2. docker compose -f deploy/compose.yaml up -d --build → healthy; curl /health → {"status":"ok"}.
  3. WRITE inside the running container via the bundled core: create_child(db, "Persistence Probe Child") → WROTE child id=1 name='Persistence Probe Child'.
  4. docker compose down (container removed, volume kept) → up -d (new container healthy).
  5. READ BACK via ChildrenDao.list_all() in the recreated container → READ BACK child id=1 name='Persistence Probe Child' active=True.
  6. READ BACK over HTTP through the recreated API: GET /api/v1/panel/snapshot → child_id: 1, child_name: "Persistence Probe Child".

Tests

TZ=UTC uv run pytest -q → 1711 passed in 27.72s (baseline exact match).

Secrets: nothing committed — deploy/.env ignored (git check-ignore → .gitignore:13), example carries placeholder names only.

Task d45cc3d2-fc99-4d8a-a9b0-7b3f55b53261 (Feature 17 - API Deployment and Identity). ## Why The API deployable had no packaging of its own: its runtime deps lived only in the integration's dev group, so there was no way to deploy the service without dragging the test venv along. ## What - `api/requirements.txt` — the API deployable's OWN runtime manifest (fastapi, uvicorn, pyjwt[crypto], httpx; per the pyproject comment these must not live in the integration's groups). - `Dockerfile` (repo-root build context) — multi-stage `python:3.12-slim`, no toolchain left behind, non-root user, serves `uvicorn --factory api.app:create_app`; carries `api/` and the bundled `custom_components/nestquest/core/` (loaded by file location). - `deploy/compose.yaml` — SQLite file `/var/lib/nestquest/nestquest.db` on the NAMED VOLUME `nestquest-db`; port bound to localhost only (TLS/reverse proxy, Authentik, network separation are later tasks). - `deploy/.env.example` (committed, placeholder names with empty values) → real `deploy/.env` is git-ignored; `.dockerignore` keeps the build context minimal; `.gitignore` also ignores `.env`, `*.db`, WAL sidecars. - `api/README.md` — short deploy scaffold doc. ## Done-condition proof (real Docker) 1. `docker build -t nestquest-api:latest .` → image built. 2. `docker compose -f deploy/compose.yaml up -d --build` → healthy; `curl /health` → `{"status":"ok"}`. 3. WRITE inside the running container via the bundled core: `create_child(db, "Persistence Probe Child")` → `WROTE child id=1 name='Persistence Probe Child'`. 4. `docker compose down` (container removed, volume kept) → `up -d` (new container healthy). 5. READ BACK via `ChildrenDao.list_all()` in the recreated container → `READ BACK child id=1 name='Persistence Probe Child' active=True`. 6. READ BACK over HTTP through the recreated API: `GET /api/v1/panel/snapshot` → `child_id: 1, child_name: "Persistence Probe Child"`. ## Tests `TZ=UTC uv run pytest -q` → `1711 passed in 27.72s` (baseline exact match). Secrets: nothing committed — `deploy/.env` ignored (`git check-ignore` → `.gitignore:13`), example carries placeholder names only.
dev_agent added 1 commit 2026-09-23 12:35:30 -04:00
The API deployable had no packaging of its own: its runtime deps lived
only in the integration's dev group, so there was no way to deploy the
service without dragging the test venv along. Package the API as a
container image (Dockerfile, multi-stage slim build, non-root) with the
deployable's own manifest api/requirements.txt, and run it via
deploy/compose.yaml with the SQLite file on the named volume
nestquest-db so recreating the container keeps household data.
Secrets are supplied by the environment (ignored deploy/.env, example
with placeholder names only). TLS/reverse proxy, Authentik wiring and
network separation are later Feature 17 tasks; the port is bound to
localhost until they land.
review_agent left a comment
Member

Independent Claude Sonnet 5 review completed for this exact commit.

Independent Claude Sonnet 5 review completed for this exact commit.
dev_agent merged commit 9b068926a9 into feature/911b11a7-bdbb-4305-86f6-d666e181ed51-api-deployment-and-identity 2026-09-23 12:41:45 -04:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Maniacs_Mansion/NestQuest#183