# ---------- Build Stage ---------- FROM golang:1.24 AS builder WORKDIR /app COPY . . # Which commit this image is. Reported by GET /live/api/v1/health, so "I pushed # it" and "it is running" stop being the same sentence — a redeploy can reuse a # cached image, and there was no way to tell from outside. # # Passed by the platform as a build argument: # docker build --build-arg BUILD_VERSION=$(git rev-parse --short HEAD) . # In Dokploy this goes under the application's Build settings. Left unset it # reads "unknown", which is itself worth seeing — it means nothing stamped it. # # `.git` is not in the build context (see .dockerignore), so the build cannot # work this out for itself. ARG BUILD_VERSION=unknown RUN CGO_ENABLED=0 GOOS=linux go build \ -ldflags "-X nearle/controllers.Version=${BUILD_VERSION}" -o server # ---------- Runtime Stage ---------- FROM alpine:latest RUN apk add --no-cache tzdata WORKDIR /app COPY --from=builder /app/server /app COPY nearle-gear-firebase-adminsdk-l9oha-23ca3b3609.json . # Nearle Buddy's credential, as ONE container variable. # # Not an env file. `COPY .env.production .` was tried on 2026-09-25 and took the # backend down with 502 on every endpoint: that file declares twenty-three # variables, and godotenv fills any the platform leaves unset, so a stale # committed DB or Redis value replaced a live one and the process died at boot. # Twenty-three variables shipped to deliver one. # # A single ENV cannot do that — it sets this name and no other. A value set on # the platform still wins, because `docker run -e` overrides a Dockerfile ENV, # so this is a default rather than an override. # # Provider, endpoint and model are constants in config.go, so this is the only # thing the assistant needs to come up. ENV ASSISTANT_API_KEY=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 # Where the nutrition panel and health score come from. # # A PUBLIC URL, not a secret — it is the catalogue-intelligence service the # console already reads its health score card from, and the same value is in # .env.example. So it is a build-time default rather than a platform setting, # for the same reason ASSISTANT_API_KEY is: one variable, set in one place, # that cannot be missed on a deploy. # # It has been missed twice. Unset, `getproductbyvariant` simply omits # `nutrition` and `healthscore`, which is indistinguishable from a product the # service has not scored — so the feature ships switched off and looks broken # rather than absent. The startup log now names which state it is in. # # A value set on the platform still wins: `docker run -e` overrides a Dockerfile # ENV, so this is a default and not a lock-in. ENV NUTRITION_BASE=https://mcp.nearle.ai.in/api # No `.env.*` is copied in (see .dockerignore), so this only decides which rules # config.Load applies: production insists on a signing secret and never falls # back to localhost values. Every other real value comes from the platform's # environment settings, exactly as before. ENV APP_ENV=production # Must match APP_PORT in the platform's environment (1009 in production). EXPOSE 1009 CMD ["/app/server"]