/ Dockerfile
Dockerfile
 1  FROM node:lts AS frontend-builder
 2  
 3  WORKDIR /frontend
 4  COPY frontend/package*.json ./
 5  RUN npm install
 6  COPY frontend/ ./
 7  RUN npm run build
 8  
 9  
10  FROM python:3.12 AS backend-builder
11  
12  RUN apt-get update && apt-get install --no-install-recommends -y postgresql-client python3-dev ffmpeg \
13      && apt-get clean -y && rm -rf /var/lib/apt/lists/*
14  
15  COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
16  
17  WORKDIR /app
18  
19  COPY pyproject.toml uv.lock ./
20  # `--no-install-project` skips building the local workspace package
21  # (restai-core). Without it uv would try to build a wheel here and
22  # hatchling would need README.md + the package source — but we only
23  # copied pyproject.toml + uv.lock at this point on purpose, so we keep
24  # the dependency-install layer cacheable across source changes. The
25  # runtime runs `python main.py` directly from /app, so the package
26  # never needs to be importable as an installed dist anyway.
27  RUN uv sync --frozen --no-group gpu --no-group dev --no-install-project
28  
29  COPY . /app
30  
31  
32  FROM python:3.12-slim AS runtime
33  
34  RUN apt-get update && apt-get install --no-install-recommends -y postgresql-client ffmpeg \
35      && apt-get clean -y && rm -rf /var/lib/apt/lists/*
36  
37  RUN useradd --user-group --system --create-home --no-log-init user \
38      && mkdir -p /home/user/.cache /home/user/.local/share \
39      && chown -R user:user /home/user
40  
41  USER user
42  WORKDIR /app
43  
44  COPY --from=frontend-builder /frontend/build /app/frontend/build
45  COPY --from=backend-builder --chown=user:user /app/.venv /app/.venv
46  COPY --chown=user:user . /app
47  
48  EXPOSE 9000
49  
50  HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
51      CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:9000/health/live')" || exit 1
52  
53  CMD ["sh", "-c", ".venv/bin/python database.py && .venv/bin/python main.py"]