feat: phase 0 foundation — FastAPI scaffold + /healthz

Scaffold app/ package, pinned requirements.txt, multi-stage Dockerfile,
docker-compose.yml, and .env.example. Add typed pydantic-settings loader
with full env contract and a production validator that refuses the
dev-sentinel SECRET_KEY. Wire structlog with an APP_ENV-driven renderer
(console in dev, JSON in prod). Ship a minimal unauthenticated /healthz
returning {status, version, commit_sha} with commit SHA fed through a
GIT_COMMIT_SHA build arg.

Also mark Phase 0 complete in docs/ROADMAP.md.
This commit is contained in:
2026-04-21 14:44:41 -05:00
parent 22f357f3e8
commit 78dd1ac243
19 changed files with 653 additions and 9 deletions

3
tests/__init__.py Normal file
View File

@@ -0,0 +1,3 @@
"""Pytest suite for the Chicken Babies R Us app."""
from __future__ import annotations

35
tests/test_healthz.py Normal file
View File

@@ -0,0 +1,35 @@
"""Tests for the ``/healthz`` endpoint.
Kept deliberately small in Phase 0: we verify contract and shape, not
content beyond what the response model guarantees.
"""
from __future__ import annotations
from fastapi.testclient import TestClient
from app import __version__
from app.main import app
def test_healthz_returns_ok_and_version() -> None:
"""``GET /healthz`` returns 200 with status=ok and the app version.
Also asserts ``commit_sha`` is present as a non-empty string — it
defaults to ``"unknown"`` in dev, which still satisfies the contract
surfaced to uptime probes.
"""
# TestClient uses the module-level app, which has already been wired
# by create_app() at import time — exactly the path uvicorn takes in
# production, so the test exercises real startup behavior.
client = TestClient(app)
response = client.get("/healthz")
assert response.status_code == 200, response.text
payload = response.json()
assert payload["status"] == "ok"
assert payload["version"] == __version__
assert isinstance(payload["commit_sha"], str)
assert payload["commit_sha"], "commit_sha must be a non-empty string"