diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..12a7bb5 --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,18 @@ +# Build-context hygiene for the backend image (mirrors frontend/.dockerignore). +.venv +__pycache__ +*.pyc +*.pyo +.pytest_cache +.mypy_cache +.ruff_cache +.git +.env +.env.* +!.env.example +.researchx +runs +tests +Dockerfile +.dockerignore +README.md \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..c38493c --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,38 @@ +# ResearchX backend — production release image (ciagent release system) +# Multi-stage: deps -> runtime. FastAPI + uvicorn, single worker, non-root. +# Built ON the Docker host from the synced source (no local docker required), +# mirroring frontend/Dockerfile: the build context is backend/. + +# ---- deps ---- +FROM python:3.12-slim AS deps +# uv is the repo's package manager (backend/uv.lock). The repo pins no uv +# version, so this install is bounded to a major range; pin it exactly once +# the deploy host's uv version is known. +RUN pip install --no-cache-dir "uv>=0.8,<2" +WORKDIR /app +ENV UV_PYTHON_DOWNLOADS=never +COPY pyproject.toml uv.lock .python-version ./ +COPY src ./src +# --frozen: use uv.lock as written (no lock rewrite). --no-dev: no test/lint +# dependencies in the runtime image. --no-editable: copy the package into +# site-packages instead of linking the source tree. +RUN uv sync --frozen --no-dev --no-editable --no-cache --python 3.12 + +# ---- runtime ---- +FROM python:3.12-slim AS runtime +WORKDIR /app +ENV PATH="/app/.venv/bin:$PATH" \ + PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + RESEARCHX_DATA_DIR=/var/lib/researchx +COPY --from=deps /app/.venv /app/.venv +# Non-root app user (house recipe: frontend/Dockerfile runs as researchx). +RUN addgroup --system researchx \ + && adduser --system --ingroup researchx --no-create-home researchx \ + && mkdir -p /var/lib/researchx \ + && ln -s /var/lib/researchx /app/.researchx \ + && chown -R researchx:researchx /var/lib/researchx +USER researchx +EXPOSE 8000 +# Single worker (REQ-83): the run registry lives in process memory. +CMD ["uvicorn", "researchx.api.app:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"] \ No newline at end of file