# syntax=docker/dockerfile:1.6
#
# DECT Relay Agent — production container image
#
# Build context: the bundle produced by scripts/packageDectRelayAgent.js.
# The bundle contains a `workspace/` directory that mirrors just enough of
# the parent repo to satisfy the agent's `../integrations/...` and
# `../utils/...` imports without any source rewriting:
#
#   workspace/
#     dect-relay-agent/     ← WORKDIR at runtime
#       package.json
#       index.js
#     integrations/cisco-dect/{client,probes,statusXml}.js
#     utils/httpDigestAuth.js
#
# Building this Dockerfile in the raw repo (`docker build dect-relay-agent/`)
# WILL NOT WORK — the shared modules live one directory up and would be
# outside the build context. Always build from a bundle produced by the
# packager.

# ── Stage 1: install prod deps ──────────────────────────────────────
# node:20-alpine keeps the final image ~55MB. Alpine's musl libc has
# been fine for this agent's plain JS + axios + ws footprint (no
# native modules) but if you ever add one that needs glibc, switch to
# node:20-slim.
FROM node:20-alpine AS deps
WORKDIR /build

# Only copy the agent's manifest first so this layer caches across
# code-only changes.
COPY workspace/dect-relay-agent/package.json ./package.json

# `npm install --omit=dev` because there's no committed lockfile
# (the agent has three dependencies; every deploy resolving the same
# `^` ranges is acceptable for this operational tool). Add
# --ignore-scripts to refuse arbitrary lifecycle-script execution from
# the registry — none of our current deps use lifecycle scripts.
RUN npm install --omit=dev --ignore-scripts \
    && npm cache clean --force

# ── Stage 2: runtime ────────────────────────────────────────────────
FROM node:20-alpine AS runtime

# tini gives us proper PID-1 signal handling (SIGTERM propagates
# cleanly to node so our graceful shutdown path in index.js actually
# runs on `docker stop`).
RUN apk add --no-cache tini

# Non-root user. UID/GID pinned so bind-mounted volumes (if any) are
# predictable across hosts.
RUN addgroup -S -g 1500 dect \
 && adduser  -S -u 1500 -G dect -H -s /sbin/nologin dect

WORKDIR /app

# Copy the shared workspace tree — the agent's imports of
# `../integrations/...` and `../utils/...` resolve exactly as they do
# in the source repo. See the bundle layout comment at the top of
# this file.
COPY --chown=dect:dect workspace/ ./

# Bring in the deps that stage 1 resolved.
COPY --from=deps --chown=dect:dect /build/node_modules ./dect-relay-agent/node_modules

USER dect
WORKDIR /app/dect-relay-agent

# Runtime config comes from `docker compose` (--env-file .env) or
# `docker run --env-file ...`. Never bake secrets into the image.
# The agent process itself validates required vars and exits 1 if any
# are missing (see assertConfig() in index.js).

# tini reaps zombies + forwards SIGTERM. `-g` puts tini in the same
# process group as node so `docker stop` also delivers SIGTERM to
# child processes if any are spawned in the future.
ENTRYPOINT ["/sbin/tini", "-g", "--"]
CMD ["node", "index.js"]
