# 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 FROM node:20-alpine WORKDIR /app # Install dumb-init for proper signal handling RUN apk add --no-cache dumb-init # Copy server package files COPY package*.json ./ # Install build tools for native modules (better-sqlite3), then install deps RUN apk add --no-cache python3 build-base linux-headers && \ npm ci --omit=dev && \ apk del python3 build-base linux-headers # Copy server code COPY server ./server # Copy built React client from builder stage COPY --from=client-builder /app/client/build ./client/build # Create data directory and set permissions RUN mkdir -p /app/data && chown -R 1001:1001 /app # Create non-root user RUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001 USER nodejs # Expose port EXPOSE 3001 # Use dumb-init to handle signals properly ENTRYPOINT ["dumb-init", "--"] # Start the server CMD ["node", "server/index.js"]