From 9bdbfaa267db412678e58c2e93ba99434b15646a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenji=20Sato=20=E2=80=94=20PO=20researchx?= Date: Fri, 30 Oct 2026 23:01:51 +0000 Subject: [PATCH 1/2] Phase 4 slice 1: backend/Dockerfile (single worker, non-root) --- backend/Dockerfile | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 backend/Dockerfile 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 -- 2.43.0 From d51c66d45bfbd2acb4d5ea15f80b4f20a6f259b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenji=20Sato=20=E2=80=94=20PO=20researchx?= Date: Fri, 30 Oct 2026 23:01:55 +0000 Subject: [PATCH 2/2] Phase 4 slice 1: backend/.dockerignore (build-context hygiene) --- backend/.dockerignore | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 backend/.dockerignore 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 -- 2.43.0