# Bard — schema-driven taxonomy UI.
#
# Pure Node: bard reads everything over HTTP from the taxonomy API, so this
# image needs no Python, no taxonomy checkout, and no `kata` binary. Point it at
# an API with TAXONOMY_API_URL and it works against whichever backend that API
# is configured for (filesystem, Databricks, Neo4j, Postgres).

FROM node:22-alpine AS build
WORKDIR /app
# All workspace manifests must be present before `npm ci`, or npm cannot build
# the workspace tree. Contribution directories are copied whole rather than
# glob-selecting their package.json files: Docker's COPY flattens globs, which
# would put every package.json at the same path.
COPY package.json package-lock.json ./
COPY web/package.json ./web/
COPY wings ./wings/
COPY plugins-ui ./plugins-ui/
RUN npm ci
COPY web/ ./web/
RUN npm run build

FROM node:22-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production

# The server is bundled into a single self-contained CJS file, so the runtime
# stage needs no package.json and no node_modules at all.
COPY --from=build /app/web/dist ./dist

# Run unprivileged. The node image ships a `node` user.
USER node

# 0.0.0.0 is required in any container; binding loopback makes the app
# unreachable through a reverse proxy.
ENV HOST=0.0.0.0 \
    PORT=5273 \
    WEB_DIST_DIR=/app/dist/web \
    TAXONOMY_API_URL=http://127.0.0.1:8000

EXPOSE 5273

# /health deliberately does not check the upstream API: a liveness probe that
# fails when a dependency is down restarts the container for a problem
# restarting cannot fix. Use /api/ready for readiness.
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD node -e "fetch('http://127.0.0.1:'+(process.env.PORT||5273)+'/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"

CMD ["node", "dist/server/index.cjs"]
