# Modeleum: the API, the job workers, and the browse interface in one image.
#
# Three stages. The first builds the site with Node and the second fetches
# Litestream; both are discarded. The third is the runtime and carries no Node,
# no compiler, and no source checkout beyond the installed package. The data
# root is a volume, secrets come from the environment, and readiness is what
# the platform should route on.

# ---- stage 1: the browse interface ----------------------------------------
FROM node:22-alpine AS web
WORKDIR /web
COPY web/package.json web/package-lock.json ./
RUN npm ci --no-audit --no-fund
COPY web/ ./
RUN npm run build

# ---- stage 2: litestream, pinned by checksum -------------------------------
# Continuous replication of the SQLite database to the object store. Fetched
# here so the runtime stage carries neither curl's download nor the archive.
FROM python:3.13-slim AS litestream
ARG TARGETARCH
ARG LITESTREAM_VERSION=0.5.17
RUN apt-get update \
 && apt-get install -y --no-install-recommends curl ca-certificates \
 && case "$TARGETARCH" in \
      amd64) ASSET=x86_64; SUM=cfb371176d164437ae869f8351cfde49bd1804ae71c61923f75c9cba9c9c006d ;; \
      arm64) ASSET=arm64;  SUM=f8ca4a050095c1efbda2c4365172e61bf9d955ea0d9ac42f448b52e51819baa5 ;; \
      *) echo "no litestream build for $TARGETARCH" >&2; exit 1 ;; \
    esac \
 && curl -fsSL -o /tmp/litestream.tgz \
      "https://github.com/benbjohnson/litestream/releases/download/v${LITESTREAM_VERSION}/litestream-${LITESTREAM_VERSION}-linux-${ASSET}.tar.gz" \
 && echo "${SUM}  /tmp/litestream.tgz" | sha256sum -c - \
 && tar -xzf /tmp/litestream.tgz -C /usr/local/bin litestream

# ---- stage 3: the runtime --------------------------------------------------
FROM python:3.13-slim AS runtime

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PIP_NO_CACHE_DIR=1 \
    MODELEUM_DATA_ROOT=/data \
    MODELEUM_WEB_ROOT=/app/web/dist \
    MODELEUM_LOG_FORMAT=json

# curl is the health check; nothing else is added to the base image.
RUN apt-get update \
 && apt-get install -y --no-install-recommends curl \
 && rm -rf /var/lib/apt/lists/* \
 && useradd --system --uid 10001 --create-home --home-dir /home/modeleum modeleum

WORKDIR /app
COPY pyproject.toml README.md LICENSE NOTICE ./
COPY src/ ./src/
COPY docs/ ./docs/
RUN pip install --no-cache-dir '.[server]'
COPY --from=web /web/dist ./web/dist
COPY --from=litestream /usr/local/bin/litestream /usr/local/bin/litestream
COPY docker/entrypoint.sh ./entrypoint.sh

# /replica is the mount point for a directory replica (compose, the drill);
# owned by the service user so a volume initialised from the image is writable.
RUN mkdir -p /data /replica && chown -R modeleum:modeleum /data /replica /app
USER modeleum
VOLUME ["/data"]
EXPOSE 8000

HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
  CMD curl -fsS http://127.0.0.1:8000/readyz || exit 1

# The entrypoint is `modeleum serve`, wrapped in replication when a replica
# URL is configured. See docker/entrypoint.sh.
CMD ["/app/entrypoint.sh"]
