| # syntax=docker/dockerfile:1.7 | |
| # | |
| # automAIta β single-container image for HuggingFace Spaces. | |
| # | |
| # HF Space contract (https://huggingface.co/docs/hub/spaces-sdks-docker): | |
| # - Container runs as UID 1000. β user `app`, USER app below. | |
| # - Single port exposed (default 7860). β EXPOSE + uvicorn --port 7860. | |
| # - $HOME must be writable by the runtime user. β ENV HOME=/home/app. | |
| # - Persistent storage (when enabled in Space settings) is mounted at /data | |
| # at RUNTIME ONLY β not available during build. Pre-create + chown the dir | |
| # so the runtime mount lands on an owned, writable path. | |
| # - Don't use `VOLUME` for /data (HF doesn't honor it). | |
| # - Build-time secrets must be declared with --mount=type=secret,id=NAME and | |
| # read from /run/secrets/NAME β DO NOT bake secrets into env vars. | |
| # ---------- Stage 1: build the React PWA ---------- | |
| FROM node:20-alpine AS frontend-build | |
| WORKDIR /fe | |
| COPY frontend/package.json frontend/package-lock.json* ./ | |
| RUN npm install --no-audit --no-fund | |
| COPY frontend/ ./ | |
| RUN npm run build | |
| # ---------- Stage 2: runtime (FastAPI serves API + built static) ---------- | |
| FROM python:3.12-slim AS runtime | |
| ENV PYTHONDONTWRITEBYTECODE=1 \ | |
| PYTHONUNBUFFERED=1 \ | |
| UV_LINK_MODE=copy \ | |
| UV_COMPILE_BYTECODE=1 \ | |
| UV_PROJECT_ENVIRONMENT=/app/.venv \ | |
| HOME=/home/app \ | |
| PATH="/app/.venv/bin:/home/app/.local/bin:${PATH}" \ | |
| AUTOMAITA_STATIC_DIR=/app/static \ | |
| AUTOMAITA_DATA_DIR=/data | |
| # Non-root user matching the HF Space UID. | |
| RUN groupadd --system --gid 1000 app \ | |
| && useradd --system --uid 1000 --gid 1000 --create-home --home-dir /home/app --shell /bin/bash app | |
| WORKDIR /app | |
| # Install uv (pip is fine for a single binary install). | |
| RUN pip install --no-cache-dir uv==0.5.11 | |
| # Install backend deps. Cached layer if pyproject + lock are unchanged. | |
| COPY --chown=app:app backend/pyproject.toml backend/uv.lock* ./ | |
| RUN uv sync --frozen --no-dev || uv sync --no-dev | |
| # Backend source. | |
| COPY --chown=app:app backend/app ./app | |
| # Built frontend β /app/static. | |
| COPY --from=frontend-build --chown=app:app /fe/dist ./static | |
| # Pre-create /data so the runtime persistent-storage mount lands on a path | |
| # already owned by uid 1000. If no storage is attached, this directory still | |
| # exists and is writable β the app falls back to ephemeral writes. | |
| RUN mkdir -p /data && chown -R 1000:1000 /data | |
| RUN chown -R app:app /app /home/app | |
| USER app | |
| EXPOSE 7860 | |
| CMD ["uv", "run", "--no-sync", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860"] | |