# Multi-stage build for Soroban Abacus Flashcards FROM node:18-alpine AS base # Install Python and build tools for better-sqlite3 RUN apk add --no-cache python3 py3-setuptools make g++ # Install pnpm and turbo RUN npm install -g pnpm@9.15.4 turbo@1.10.0 WORKDIR /app # Copy package files for dependency resolution COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json ./ COPY apps/web/package.json ./apps/web/ COPY packages/core/client/node/package.json ./packages/core/client/node/ COPY packages/abacus-react/package.json ./packages/abacus-react/ COPY packages/templates/package.json ./packages/templates/ # Install ALL dependencies for build stage RUN pnpm install --frozen-lockfile # Builder stage FROM base AS builder # Accept git information as build arguments ARG GIT_COMMIT ARG GIT_COMMIT_SHORT ARG GIT_BRANCH ARG GIT_TAG ARG GIT_DIRTY # Set as environment variables for build scripts ENV GIT_COMMIT=${GIT_COMMIT} ENV GIT_COMMIT_SHORT=${GIT_COMMIT_SHORT} ENV GIT_BRANCH=${GIT_BRANCH} ENV GIT_TAG=${GIT_TAG} ENV GIT_DIRTY=${GIT_DIRTY} COPY . . # Generate Panda CSS styled-system before building RUN cd apps/web && npx @pandacss/dev # Build using turbo for apps/web and its dependencies RUN turbo build --filter=@soroban/web # Production dependencies stage - install only runtime dependencies FROM node:18-alpine AS deps WORKDIR /app # Install build tools temporarily for better-sqlite3 installation RUN apk add --no-cache python3 py3-setuptools make g++ # Install pnpm RUN npm install -g pnpm@9.15.4 # Copy package files COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ COPY apps/web/package.json ./apps/web/ COPY packages/core/client/node/package.json ./packages/core/client/node/ COPY packages/abacus-react/package.json ./packages/abacus-react/ COPY packages/templates/package.json ./packages/templates/ # Install ONLY production dependencies RUN pnpm install --frozen-lockfile --prod # Production image FROM node:18-alpine AS runner WORKDIR /app # Install ONLY runtime dependencies (no build tools needed) RUN apk add --no-cache python3 py3-pip typst qpdf # Create non-root user RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs # Copy built Next.js application COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next ./apps/web/.next COPY --from=builder --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public # Copy Panda CSS generated styles COPY --from=builder --chown=nextjs:nodejs /app/apps/web/styled-system ./apps/web/styled-system # Copy server files (compiled from TypeScript) COPY --from=builder --chown=nextjs:nodejs /app/apps/web/server.js ./apps/web/ COPY --from=builder --chown=nextjs:nodejs /app/apps/web/dist ./apps/web/dist # Copy database migrations COPY --from=builder --chown=nextjs:nodejs /app/apps/web/drizzle ./apps/web/drizzle # Copy PRODUCTION node_modules only (no dev dependencies) COPY --from=deps --chown=nextjs:nodejs /app/node_modules ./node_modules COPY --from=deps --chown=nextjs:nodejs /app/apps/web/node_modules ./apps/web/node_modules # Copy core package (needed for Python flashcard generation scripts) COPY --from=builder --chown=nextjs:nodejs /app/packages/core ./packages/core # Copy templates package (needed for Typst templates) COPY --from=builder --chown=nextjs:nodejs /app/packages/templates ./packages/templates # Install Python dependencies for flashcard generation RUN pip3 install --no-cache-dir --break-system-packages -r packages/core/requirements.txt # Copy package.json files for module resolution COPY --from=builder --chown=nextjs:nodejs /app/package.json ./ COPY --from=builder --chown=nextjs:nodejs /app/apps/web/package.json ./apps/web/ # Set up environment WORKDIR /app/apps/web # Create data directory for SQLite database RUN mkdir -p data && chown nextjs:nodejs data USER nextjs EXPOSE 3000 ENV PORT 3000 ENV HOSTNAME "0.0.0.0" ENV NODE_ENV production # Start the application CMD ["node", "server.js"]