diff --git a/.env.example b/.env.example new file mode 100644 index 000000000..b57f76d13 --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +# Build-time args for the frontend image (baked into the Next.js bundle) +NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co +NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY=your-supabase-anon-key +# URL the browser uses to reach the backend — must be publicly reachable +NEXT_PUBLIC_API_BASE_URL=http://localhost:3001 diff --git a/README.md b/README.md index 9e70f9af6..ef75969f2 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,30 @@ Supabase values come from the project dashboard. Use the project URL for `SUPABA Provider keys are only needed for the models and email features you plan to use. Model provider keys can be configured in `backend/.env` for the whole instance, or per user in **Account > Models & API Keys**. If a provider key is present in `backend/.env`, that provider is available by default and the matching browser API key field is read-only. +## Docker + +The easiest way to run the full stack is with Docker Compose. + +**1. Copy and fill in env files:** + +```bash +cp .env.example .env +cp backend/.env.example backend/.env +cp frontend/.env.local.example frontend/.env.local +``` + +Edit each file with your Supabase, R2, and provider keys (see [Environment](#environment) below for details). The root `.env` supplies build-time values for the frontend image. + +**2. Build and start:** + +```bash +docker compose up --build +``` + +Frontend is served at `http://localhost:3000`, backend at `http://localhost:3001`. + +**Note:** `NEXT_PUBLIC_*` variables are baked into the frontend image at build time. If you change them, re-run `docker compose up --build` to rebuild the image. + ## Install Install each app package: diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 000000000..986411c7b --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,27 @@ +FROM node:20-slim AS deps +WORKDIR /app +COPY package*.json ./ +RUN npm ci + +FROM node:20-slim AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +RUN npm run build + +FROM node:20-slim AS runner +WORKDIR /app + +RUN apt-get update && \ + apt-get install -y --no-install-recommends libreoffice && \ + rm -rf /var/lib/apt/lists/* + +ENV NODE_ENV=production + +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/node_modules ./node_modules +COPY package.json ./ + +EXPOSE 3001 + +CMD ["node", "dist/index.js"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..c541a86cd --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,24 @@ +services: + backend: + build: + context: ./backend + env_file: + - ./backend/.env + ports: + - "3001:3001" + restart: unless-stopped + + frontend: + build: + context: ./frontend + args: + NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL} + NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY: ${NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY} + NEXT_PUBLIC_API_BASE_URL: ${NEXT_PUBLIC_API_BASE_URL:-http://localhost:3001} + env_file: + - ./frontend/.env.local + ports: + - "3000:3000" + depends_on: + - backend + restart: unless-stopped diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 000000000..53b4251a8 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,31 @@ +FROM node:20-alpine AS deps +WORKDIR /app +COPY package*.json ./ +RUN npm ci + +FROM node:20-alpine AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +ARG NEXT_PUBLIC_SUPABASE_URL +ARG NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY +ARG NEXT_PUBLIC_API_BASE_URL + +ENV NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL +ENV NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY=$NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY +ENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL + +RUN npm run build + +FROM node:20-alpine AS runner +WORKDIR /app +ENV NODE_ENV=production + +COPY --from=builder /app/public ./public +COPY --from=builder /app/.next/standalone ./ +COPY --from=builder /app/.next/static ./.next/static + +EXPOSE 3000 + +CMD ["node", "server.js"] diff --git a/frontend/next.config.ts b/frontend/next.config.ts index 84dce26f7..1f9b7a295 100644 --- a/frontend/next.config.ts +++ b/frontend/next.config.ts @@ -1,7 +1,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + output: "standalone", reactCompiler: true, async rewrites() { return [