# Stage 1: Install dependencies (native addons need build tools) FROM node:20-alpine AS deps RUN apk add --no-cache python3 make g++ WORKDIR /app COPY package.json package-lock.json ./ COPY apps/web/package.json apps/web/package.json COPY packages/shared/package.json packages/shared/package.json RUN npm ci # Stage 2: Build everything (web needs server types via packages/shared) FROM deps AS build COPY tsconfig.json ./ COPY apps/server/ apps/server/ COPY apps/web/ apps/web/ COPY packages/shared/ packages/shared/ # Server build (tsc → apps/server/dist/) RUN npm run build # Web build (vite bundle → apps/web/dist/) RUN npx --workspace=apps/web vite build # Stage 3: Production image FROM node:20-alpine AS prod RUN apk add --no-cache git curl jq COPY --from=caddy:2-alpine /usr/bin/caddy /usr/bin/caddy WORKDIR /app # Node modules (includes native better-sqlite3) COPY --from=deps /app/node_modules/ node_modules/ COPY package.json ./ # Server build output + drizzle migrations COPY --from=build /app/apps/server/dist/ apps/server/dist/ COPY apps/server/drizzle/ apps/server/drizzle/ # Web build output COPY --from=build /app/apps/web/dist/ apps/web/dist/ # Scripts and config COPY scripts/ scripts/ COPY scripts/Caddyfile /etc/caddy/Caddyfile RUN chmod +x scripts/*.sh # Workspace volume RUN mkdir -p /workspace EXPOSE 3000 ENTRYPOINT ["sh", "/app/scripts/entrypoint.sh"]