# Build stage for React client FROM node:20-alpine AS client-builder WORKDIR /app/client # Copy client package files COPY client/package*.json ./ # Install dependencies (--legacy-peer-deps needed for react-scripts 5 + React 19) RUN npm ci --legacy-peer-deps # Copy client source COPY client/src ./src COPY client/public ./public # Build React app RUN npm run build # Final stage - Node.js server (slim Debian for glibc native module compatibility) FROM node:20-slim WORKDIR /app # Install dumb-init and build tools needed by better-sqlite3 RUN apt-get update && apt-get install -y --no-install-recommends \ dumb-init python3 make g++ \ && rm -rf /var/lib/apt/lists/* # Copy server package files COPY package*.json ./ # Install production dependencies only RUN npm ci --omit=dev # Copy server code COPY server ./server # Copy built React client from builder stage COPY --from=client-builder /app/client/build ./client/build # Create non-root user and data directory RUN groupadd -g 1001 nodejs && \ useradd -u 1001 -g nodejs nodejs && \ mkdir -p /app/data && \ chown -R nodejs:nodejs /app USER nodejs # Expose port EXPOSE 3001 # Use dumb-init to handle signals properly ENTRYPOINT ["dumb-init", "--"] # Start the server CMD ["node", "server/index.js"]