# syntax=docker/dockerfile:1.4 # Chess Tutor web UI — Vite static build + Python API on port 8765. # # Runtime files staged explicitly (not whole docs/ or data/ trees): # docs/playstyle_catalog*.yaml — coaching copy (3 YAML files only) # data/models/.../playstyle_teacher.joblib # data/models/.../opening_climber_stats.joblib # data/inference/chesscom_lichess_rapid_linear.joblib # data/web_artifacts/cohort/standard_600/* # data/lichess-puzzles/... — copied when present locally (optional) # # Not included: playstyle_feature_lookup.json, research docs, cohort DB, # playstyle_elo.joblib. Rust prebuilt is copied when present (amd64 speedup). # # Build: # docker build -t chess-tutor-web . # Run: # docker run --rm -p 8765:8765 chess-tutor-web FROM node:20-bookworm-slim AS frontend WORKDIR /app/src/chess_tutor/web/frontend COPY src/chess_tutor/web/frontend/package.json src/chess_tutor/web/frontend/package-lock.json ./ RUN npm ci COPY src/chess_tutor/web/frontend/ ./ RUN npm run build FROM python:3.12-slim-bookworm AS runtime WORKDIR /app RUN apt-get update \ && apt-get install -y --no-install-recommends curl \ && rm -rf /var/lib/apt/lists/* COPY requirements-web.txt pyproject.toml ./ RUN printf '%s\n' '# Chess Tutor web image' > Initial-plan.md COPY src ./src COPY classical-eval-rs/prebuilt/ classical-eval-rs/prebuilt/ COPY docker/entrypoint.sh docker/stage-web-data.sh /tmp/docker/ COPY docs/playstyle_catalog.yaml \ docs/playstyle_catalog_extended_dimensions.yaml \ docs/playstyle_catalog_coaching_dimensions.yaml \ /tmp/stage/catalog/ COPY data/models/cohort/standard_600/playstyle_teacher.joblib \ data/models/cohort/standard_600/opening_climber_stats.joblib \ /tmp/stage/models/ COPY data/inference/chesscom_lichess_rapid_linear.joblib /tmp/stage/inference/ COPY data/web_artifacts/cohort/standard_600/ /tmp/stage/web_artifacts/ # Optional puzzle shard from local checkout (skipped when file is absent) RUN --mount=type=bind,source=.,target=/ctx,readonly \ mkdir -p /tmp/stage/lichess-puzzles/data \ && if [ -f /ctx/data/lichess-puzzles/data/train-00000-of-00003.parquet ]; then \ cp /ctx/data/lichess-puzzles/data/train-00000-of-00003.parquet /tmp/stage/lichess-puzzles/data/; \ fi RUN chmod +x /tmp/docker/stage-web-data.sh /tmp/docker/entrypoint.sh \ && /tmp/docker/stage-web-data.sh /tmp/stage /app \ && mv /tmp/docker/entrypoint.sh /entrypoint.sh \ && rm -rf /tmp/stage /tmp/docker RUN pip install --no-cache-dir -U pip wheel \ && pip install --no-cache-dir -r requirements-web.txt \ && pip install --no-cache-dir -e . --no-deps \ && pip install --no-cache-dir \ "numpy==2.4.4" \ "scipy>=1.14.1,<1.18" \ "scikit-learn>=1.5.0,<1.9" COPY --from=frontend /app/src/chess_tutor/web/static ./src/chess_tutor/web/static ENV HOST=0.0.0.0 \ PORT=8765 \ DOWNLOAD_PUZZLES=0 \ PYTHONUNBUFFERED=1 EXPOSE 8765 HEALTHCHECK --interval=30s --timeout=5s --start-period=120s --retries=3 \ CMD curl -fsS "http://127.0.0.1:8765/api/version" >/dev/null || exit 1 ENTRYPOINT ["/entrypoint.sh"]