# The build order in this file is the lesson. Read it top to bottom once.
#
# Every instruction produces a layer, and a layer is reused on rebuild only if it
# and everything above it are unchanged. So the rule is: things that change
# rarely go first, things that change constantly go last. Your source code
# changes on every save; your dependency list changes once a week. Put COPY . .
# above pip install and every one-character edit reinstalls the whole world.
#
# pay.docker1 walks through this line by line.

# --- base -------------------------------------------------------------------
# A specific minor version, not `python:3` and not `latest`. "It worked on my
# machine last month" is usually a tag that moved underneath you.
FROM python:3.12-slim AS base

# PYTHONDONTWRITEBYTECODE: .pyc files in an image are dead weight; the container
#   is recreated, never warmed.
# PYTHONUNBUFFERED: without it, stdout is block-buffered when not a terminal, so
#   your logs arrive late or not at all when the process is killed. This single
#   line is the difference between debugging a crash and guessing at it.
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PIP_NO_CACHE_DIR=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=1

# libpq is what psycopg talks to Postgres through. build-essential is needed to
# compile some wheels and is dropped again in the runtime stage below, because
# shipping a compiler to production widens the attack surface for no benefit.
RUN apt-get update \
 && apt-get install -y --no-install-recommends build-essential libpq-dev curl \
 && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# --- dependencies -----------------------------------------------------------
# Copied alone, before the source. This layer is the expensive one and it now
# survives every code change.
COPY requirements.txt ./
RUN pip install -r requirements.txt

# --- source -----------------------------------------------------------------
# Last, because it changes most often.
COPY payments_agent ./payments_agent
COPY migrations ./migrations
COPY alembic.ini ./
COPY policies ./policies
COPY evals ./evals

# Not root. A container escape that lands as root on the host is a much worse day
# than one that lands as uid 1000.
RUN useradd --create-home --uid 1000 app && chown -R app:app /app
USER app

EXPOSE 8000

# A healthcheck the platform can act on. "The process is running" is not the same
# claim as "the app can serve a request".
HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \
  CMD curl -fsS http://localhost:8000/healthz || exit 1

# exec form, not shell form. Shell form wraps the process in /bin/sh, which does
# not forward SIGTERM, so your app never gets to shut down cleanly and the
# platform kills it after the grace period instead.
CMD ["uvicorn", "payments_agent.api.main:app", "--host", "0.0.0.0", "--port", "8000"]
