# ── Stage 1: Build Go binary ────────────────────────────────────────────────── FROM golang:1.23-alpine AS go-builder WORKDIR /app # Download deps first (cached layer) COPY Apps/licensemanagerApp/backend/go.mod Apps/licensemanagerApp/backend/go.sum ./ RUN go mod download # Build COPY Apps/licensemanagerApp/backend/ . RUN CGO_ENABLED=0 GOOS=linux go build -o licensemanager ./cmd/server # ── Stage 2: Build React frontend ───────────────────────────────────────────── FROM node:20-alpine AS frontend-builder WORKDIR /frontend # Install deps first (cached layer). # Using npm install instead of npm ci because the lock file was generated on Windows # and omits Linux-specific optional packages (e.g. @emnapi/*) that npm ci requires. COPY Apps/licensemanagerApp/frontend/package*.json ./ RUN npm install # Build COPY Apps/licensemanagerApp/frontend/ . RUN npm run build # ── Stage 3: Minimal runtime image ──────────────────────────────────────────── FROM alpine:3.19 # ca-certificates: needed for TLS (PostgreSQL + SMTP over TLS) # tzdata: needed by the cron scheduler for timezone-aware scheduling RUN apk add --no-cache ca-certificates tzdata # Non-root user required by Hugging Face Spaces RUN addgroup -S app && adduser -S -G app app WORKDIR /app COPY --from=go-builder /app/licensemanager . COPY --from=frontend-builder /frontend/dist ./frontend/dist RUN chown -R app:app /app USER app # PORT=7860 for Hugging Face Spaces; docker-compose.yml overrides to 8080 for local dev EXPOSE 7860 ENV PORT=7860 CMD ["./licensemanager"]