# Multi-stage build for optimized production image FROM node:20-alpine AS build # Set working directory WORKDIR /app # Copy package files COPY package*.json ./ # Install all dependencies (including dev dependencies needed for build) RUN npm ci && npm cache clean --force # Copy source code (excluding .env to avoid conflicts) COPY package*.json ./ COPY tsconfig.json ./ COPY drizzle.config.ts ./ COPY vite.config.ts ./ COPY tailwind.config.ts ./ COPY postcss.config.js ./ COPY components.json ./ COPY client/ client/ COPY server/ server/ COPY shared/ shared/ # Vérifier la structure RUN ls -la server/ # Build the application # Build frontend first RUN npx vite build # Vérifier que les fichiers sont construits RUN echo "=== BUILD VERIFICATION ===" && \ ls -la dist/ && \ echo "Frontend files in dist/public:" && \ ls -la dist/public/ && \ echo "index.html exists:" && \ ls -la dist/public/index.html # Build backend avec tous les modules externes RUN npx esbuild server/index.production.ts \ --platform=node \ --bundle \ --format=esm \ --outfile=dist/index.js \ --external:vite \ --external:@vitejs/* \ --external:@replit/* \ --external:tsx \ --external:openid-client \ --external:@neondatabase/serverless \ --external:ws \ --external:drizzle-orm \ --external:pg \ --external:express \ --external:connect-pg-simple \ --external:passport \ --external:passport-local \ --external:express-session \ --external:zod \ --external:express-rate-limit \ --external:memoizee \ --external:nanoid \ --external:date-fns # Production stage FROM node:20-alpine AS production # Create non-root user for security RUN addgroup -g 1001 -S nodejs && \ adduser -S nextjs -u 1001 # Set working directory WORKDIR /app # Install production dependencies only COPY --from=build /app/package*.json ./ RUN npm ci --only=production && npm cache clean --force # Copy built application from build stage COPY --from=build --chown=nextjs:nodejs /app/dist ./dist COPY --from=build --chown=nextjs:nodejs /app/shared ./shared # Copy migration scripts and files COPY --chown=nextjs:nodejs scripts/ ./scripts/ COPY --chown=nextjs:nodejs migrations/ ./migrations/ COPY --chown=nextjs:nodejs scripts/docker-entrypoint.sh ./scripts/docker-entrypoint.sh # Create symlink for public files to be accessible from dist RUN ln -sf /app/dist/public /app/dist/public # Create uploads and backups directories with proper permissions RUN mkdir -p /app/uploads /app/backups && chown -R nextjs:nodejs /app/uploads /app/backups # Switch to non-root user USER nextjs # Expose port EXPOSE 3000 ENV PORT=3000 # Install wget for health check and postgresql-client for pg_dump USER root RUN apk add --no-cache wget postgresql-client USER nextjs # Health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1 # Make scripts executable RUN chmod +x /app/scripts/auto-migrate-production.sh && \ chmod +x /app/scripts/docker-entrypoint.sh && \ ls -la /app/scripts/ && \ test -f /app/scripts/docker-entrypoint.sh || echo "ERREUR: docker-entrypoint.sh manquant" # Apply DLC migration directly and start application CMD ["sh", "-c", "echo 'Applying DLC migration...'; if [ -n \"$DATABASE_URL\" ]; then psql \"$DATABASE_URL\" -c 'ALTER TABLE dlc_products ADD COLUMN IF NOT EXISTS stock_epuise boolean DEFAULT false NOT NULL, ADD COLUMN IF NOT EXISTS stock_epuise_by varchar(255), ADD COLUMN IF NOT EXISTS stock_epuise_at timestamp; CREATE INDEX IF NOT EXISTS idx_dlc_products_stock_epuise ON dlc_products(stock_epuise);' || echo 'Migration already applied or failed'; fi; node dist/index.js"]