# ──────────────────────────────────────────────────────────────────────── # FinAI — single-container build for HuggingFace Spaces (free tier) # Runs Next.js (frontend) + FastAPI (backend) behind one exposed port. # ──────────────────────────────────────────────────────────────────────── # Build stage 1: compile Next.js into standalone bundle FROM node:20-bookworm-slim AS web-builder WORKDIR /app/web # pnpm is the project's package manager RUN corepack enable COPY apps/web/package.json apps/web/pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile --prod=false COPY apps/web/ ./ # Next.js 15 requires NEXT_TELEMETRY_DISABLED at build time too ENV NEXT_TELEMETRY_DISABLED=1 ENV NEXT_PUBLIC_API_URL=http://127.0.0.1:8000 RUN pnpm build # Build stage 2: runtime image with Python + Node FROM python:3.11-slim-bookworm AS runtime # Install Node.js 20 (for the Next.js standalone server) RUN apt-get update \ && apt-get install -y --no-install-recommends curl ca-certificates gnupg \ && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ && apt-get install -y --no-install-recommends nodejs \ && rm -rf /var/lib/apt/lists/* ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \ PIP_NO_CACHE_DIR=1 \ NEXT_TELEMETRY_DISABLED=1 \ # HF Spaces injects PORT — default to 7860 for local parity PORT=7860 # Create a non-root user so HF Spaces is happy writing to /home/user RUN useradd -m -u 1000 user USER user WORKDIR /home/user/app # ── Python deps ──────────────────────────────────────────────────────── COPY --chown=user:user apps/api/requirements.txt ./apps/api/requirements.txt ENV PATH="/home/user/.local/bin:${PATH}" RUN pip install --user --upgrade pip \ && pip install --user -r apps/api/requirements.txt # ── Backend source ───────────────────────────────────────────────────── COPY --chown=user:user apps/api/ ./apps/api/ # ── Frontend standalone bundle ───────────────────────────────────────── # Next.js standalone layout (relative to apps/web): # .next/standalone/server.js ← entrypoint # .next/standalone/.next/... ← server assets # .next/static ← static assets (copied next to .next) # public ← public assets (copied to standalone root) COPY --from=web-builder --chown=user:user /app/web/.next/standalone ./apps/web COPY --from=web-builder --chown=user:user /app/web/.next/static ./apps/web/.next/static COPY --from=web-builder --chown=user:user /app/web/public ./apps/web/public # ── Data (DuckDB + schema) ───────────────────────────────────────────── # Writable so KB uploads/renames work at runtime on HF Spaces. COPY --chown=user:user data/ ./data/ # ── Launch script ────────────────────────────────────────────────────── COPY --chown=user:user scripts/start.sh ./start.sh RUN chmod +x ./start.sh EXPOSE 7860 CMD ["./start.sh"]