# ── Stage 1: build the React SPA ───────────────────────────────────────────── FROM node:20-slim AS frontend WORKDIR /frontend COPY frontend/package.json frontend/package-lock.json* ./ RUN npm ci || npm install COPY frontend/ ./ RUN npm run build # ── Stage 2: Python runtime ────────────────────────────────────────────────── FROM python:3.11-slim ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \ PIP_NO_CACHE_DIR=1 WORKDIR /app RUN apt-get update && apt-get install -y --no-install-recommends \ fonts-dejavu-core \ fonts-liberation \ && rm -rf /var/lib/apt/lists/* COPY requirements.txt ./ RUN python -m pip install --no-cache-dir -r requirements.txt # Copy only what the server actually runs — keeps the final image lean and avoids # baking in frontend sources, tests, legacy scripts and unused root assets. COPY app.py ./ COPY rotate_preroll.py ./ COPY services/ ./services/ COPY static/ ./static/ # Bring in the built SPA from the frontend stage. COPY --from=frontend /frontend/dist ./frontend/dist RUN mkdir -p /app/cache /app/output /app/logs EXPOSE 8500 # Single worker (lean memory) and no access log (less CPU + log noise). CMD ["python", "-m", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8500", "--no-access-log"]