# The image of {{ project }}: it serves config.asgi:application with uvicorn,
# as a user without privileges who can write nothing in /app.
#
#   docker build -t {{ image }} .
#   docker run --rm --env-file /etc/{{ project }}/production.env {{ image }} python manage.py migrate
#   docker run --rm -p 8000:8000 --env-file /etc/{{ project }}/production.env {{ image }}
#
# Every setting comes from the environment ({{ prefix }}*), as
# src/config/settings/production.py lists them. Keep the env file out of the
# project, as above, or better in a secret store: nothing secret is built
# in. .dockerignore lets in only manage.py, pyproject.toml,
# requirements.lock, src/, and migrations/, and keeps env files, keys, and
# databases out even there. WEB_CONCURRENCY sets uvicorn's worker processes
# (one per core; one unless set).
#
# Lock what the image installs, each file by its hash, and commit the lock:
#
#   uv pip compile pyproject.toml --generate-hashes -o requirements.lock
#
# Without requirements.lock, each build installs the newest releases
# pyproject.toml allows. Pin python:3.13-slim by digest too
# (python:3.13-slim@sha256:...), and let Renovate or Dependabot keep it new.

FROM scratch AS wheels
# Empty. `docker build --build-context wheels=<directory> .` offers the wheels
# in <directory> (a fork, a release candidate) ahead of the package index.

FROM python:3.13-slim AS build
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 PIP_NO_CACHE_DIR=1
WORKDIR /app
# requirements.loc[k] copies the lock if there is one, and nothing if not.
COPY pyproject.toml requirements.loc[k] ./
# The project's dependencies in a virtual environment: those the lock names,
# each checked against its hash, or else those pyproject.toml names.
RUN --mount=type=bind,from=wheels,target=/wheels \
    python -m venv /opt/venv \
    && if [ -f requirements.lock ]; then \
        /opt/venv/bin/pip install --require-hashes --no-deps -r requirements.lock; \
    else \
        echo "No requirements.lock: installing the newest releases pyproject.toml allows." >&2 \
        && python -c "import tomllib; print('\n'.join(tomllib.load(open('pyproject.toml', 'rb'))['project']['dependencies']))" > requirements.txt \
        && /opt/venv/bin/pip install --find-links /wheels -r requirements.txt; \
    fi

FROM python:3.13-slim
ENV PATH=/opt/venv/bin:$PATH \
    PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    DOMAINKIT_PROJECT_ROOT=/app \
    {{ prefix }}SETTINGS_MODULE=config.settings.production
RUN useradd --system --uid 10001 --no-create-home --shell /usr/sbin/nologin app
WORKDIR /app
COPY --from=build /opt/venv /opt/venv
# What .dockerignore lets in, owned by root: the application reads its
# code and cannot change it.
COPY . .
USER 10001
EXPOSE 8000
# The limits docs/reference/servers.md gives ("Server limits"); proxy
# headers are the application's (TRUSTED_PROXIES), not uvicorn's.
CMD ["uvicorn", "config.asgi:application", "--app-dir", "src", \
     "--host", "0.0.0.0", "--port", "8000", "--loop", "uvloop", \
     "--limit-concurrency", "1200", "--backlog", "2048", \
     "--timeout-keep-alive", "5", "--timeout-graceful-shutdown", "10", \
     "--h11-max-incomplete-event-size", "16384", "--ws-max-size", "1048576", \
     "--no-proxy-headers", "--no-server-header"]
