# Stage 1: Build Vite SPA FROM node:22-alpine AS webapp-builder WORKDIR /webapp COPY webapp/package.json webapp/package-lock.json ./ RUN npm ci COPY webapp/ ./ RUN npm run build # Stage 2: Compile static TypeScript FROM node:22-alpine AS static-ts-builder WORKDIR /build/backend COPY backend/static-ts/ ./static-ts/ RUN mkdir -p ./internal/api/static \ && cd ./static-ts \ && npm ci \ && npm run build # Stage 3: Build Go server FROM golang:1.25-alpine AS go-builder WORKDIR /app COPY backend/go.mod backend/go.sum ./ RUN go mod download COPY backend/ ./ # Inject compiled static JS COPY --from=static-ts-builder /build/backend/internal/api/static/ ./internal/api/static/ RUN go test ./... # Inject built SPA into embed path COPY --from=webapp-builder /webapp/dist ./internal/api/webapp/ RUN CGO_ENABLED=0 GOOS=linux go build -o /server ./cmd/server RUN CGO_ENABLED=0 GOOS=linux go build -o /createuser ./cmd/createuser # Stage 3: Minimal runtime image FROM gcr.io/distroless/static-debian12 COPY --from=go-builder /server /server COPY --from=go-builder /createuser /createuser ENTRYPOINT ["/server"]