# syntax=docker/dockerfile:1
#
# Three stages, because the TypeScript API client is generated from the backend's
# OpenAPI schema at build time — never hand-written, never committed (a committed
# client drifts silently from the Pydantic models it mirrors).
#
#   pybase   -> Python deps, shared by the schema dump and the runtime image
#   openapi  -> imports the FastAPI app and dumps openapi.json (no server needed)
#   frontend -> generates the TS client from that file, then builds the SPA
#   runtime  -> the app plus the built assets. Node is discarded.

# ---- Stage 1: Python dependencies --------------------------------------
FROM python:3.12-slim AS pybase
WORKDIR /app
ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

# ---- Stage 2: dump the OpenAPI schema ----------------------------------
FROM pybase AS openapi
COPY app/ app/
RUN python -m app.openapi_dump > /openapi.json

# ---- Stage 3: build the SPA (Node exists ONLY here) --------------------
FROM node:22-slim AS frontend
WORKDIR /build
COPY frontend/package.json frontend/package-lock.json* ./
RUN if [ -f package-lock.json ]; then npm ci; else npm install; fi
COPY frontend/ ./
COPY --from=openapi /openapi.json ./openapi.json
RUN npm run build

# ---- Stage 4: the running app — one Python process ---------------------
FROM pybase AS runtime
WORKDIR /app
COPY alembic.ini ./
COPY alembic/ alembic/
COPY app/ app/
COPY --from=frontend /build/dist app/static/

EXPOSE 3000
# Migrate, then serve. Alembic is the only thing that touches the schema.
CMD ["sh", "-c", "alembic upgrade head && exec uvicorn app.main:app --host 0.0.0.0 --port 3000"]
