# syntax=docker/dockerfile:1 # Multi-stage build for Hugging Face Spaces # Runs all three apps: Docusaurus docs, React frontend, FastAPI backend FROM node:20-slim AS docs-builder WORKDIR /build # Set baseUrl to /docs/ for HuggingFace deployment # Docs are served at nginx /docs/ location # routeBasePath: '/' in docusaurus.config.ts prevents /docs/docs/ nesting ENV DOCUSAURUS_BASE_URL=/docs/ COPY web_docs/package*.json ./ RUN npm config set fetch-retry-mintimeout 20000 && \ npm config set fetch-retry-maxtimeout 120000 && \ npm ci --prefer-offline --no-audit || npm install --prefer-offline --no-audit # Add cache-busting argument to force rebuild when needed ARG CACHE_BUST=2026-04-27-12-00-fix-double-docs-prefix COPY web_docs/ ./ # Verify environment variable is set and build RUN echo "Building Docusaurus with DOCUSAURUS_BASE_URL=$DOCUSAURUS_BASE_URL" && \ echo "Cache bust: 2026-04-27-12-00-fix-double-docs-prefix" && \ npm run build && \ echo "Verifying baseUrl in build output..." && \ grep -r "baseUrl" build/ | head -5 || true FROM python:3.11-slim # Install system dependencies, nginx, and Node.js for frontend build RUN apt-get update && apt-get install -y \ build-essential \ curl \ git \ tesseract-ocr \ nginx \ supervisor \ && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ && apt-get install -y nodejs \ && rm -rf /var/lib/apt/lists/* WORKDIR /app # Pre-install CPU-only torch/torchvision in their own cache-stable layer (no # requirements.txt dependency). sentence-transformers pulls torch transitively; # without this, pip drags in the ~2.5GB CUDA wheel — pure waste on a CPU-only HF # Space. Installing it here means an edit to requirements.txt (e.g. a transformers # pin bump) reuses this cached layer instead of redownloading the whole ML stack. RUN --mount=type=cache,target=/root/.cache/pip \ pip install torch==2.8.0 torchvision==0.23.0 \ --index-url https://download.pytorch.org/whl/cpu # Copy Python requirements and install. torch/torchvision are already satisfied # above, so this layer only (re)installs the lighter packages on a pin change. # The BuildKit cache mount persists pip's wheel cache (keeps the layer slim like # --no-cache-dir did, while still caching downloads for local rebuilds). COPY requirements.txt . RUN --mount=type=cache,target=/root/.cache/pip \ pip install -r requirements.txt # OPTIMIZATION: Copy frontend package files first for better caching COPY web_app/package*.json /app/web_app/ RUN cd /app/web_app && npm ci # Copy application code (now npm ci layer is cached) COPY . . # Install ALL workspace packages so they import as top-level modules at runtime # (--no-deps keeps the dependency closure unchanged — their third-party deps are # pinned in requirements.txt). The API eagerly imports agents, ingestion and llm # in api/main.py / routes, and lazily imports scrapers; installing the whole set # avoids a startup ModuleNotFoundError when any package imports a sibling package. RUN pip install --no-cache-dir --no-deps \ ./packages/core ./packages/core-lib ./packages/datamodels ./packages/agents \ ./packages/scrapers ./packages/ingestion ./packages/llm \ ./packages/accessibility ./packages/hosting # Copy built static files from docs stage COPY --from=docs-builder /build/build /app/static/docs # Build frontend (npm_modules already cached from above) # Set production environment variables for Vite ENV VITE_CANONICAL_DOMAIN=www.communityone.com ENV VITE_API_URL=/api # Cache bust: 2026-04-29-remove-axios ARG CACHE_BUST_FRONTEND=2026-04-29-remove-axios RUN cd /app/web_app && echo "Frontend build cache bust: $CACHE_BUST_FRONTEND" && npm run build # Frontend is already built to /app/api/static/ via vite.config.ts # Create frontend directory in /app/static for nginx RUN mkdir -p /app/static/frontend && \ ls -la /app/api/static/ && \ cp -r /app/api/static/* /app/static/frontend/ # Create necessary directories RUN mkdir -p /app/logs /app/data /var/log/supervisor # Copy Hugging Face specific configs COPY .huggingface/nginx.conf /etc/nginx/nginx.conf COPY .huggingface/supervisord.conf /etc/supervisor/conf.d/supervisord.conf COPY .huggingface/start.sh /app/start.sh RUN chmod +x /app/start.sh # Expose port 7860 (Hugging Face Spaces default) EXPOSE 7860 # Set environment variables ENV PYTHONUNBUFFERED=1 ENV LOG_LEVEL=INFO ENV HF_SPACES=1 # Use supervisor to run all services CMD ["/app/start.sh"]