# ─────────────────────────────────────────────────────────────────
# ISMS Builder – Dockerfile
# Multi-stage: build (npm ci) → runtime (node:lts-alpine)
#
# Daten (JSON + Uploads) werden NICHT ins Image gebacken.
# Sie müssen als Bind-Mount bereitgestellt werden:
#   docker compose up   →  ./data:/app/data  (siehe docker-compose.yml)
# ─────────────────────────────────────────────────────────────────

# ── Stage 1: install dependencies ────────────────────────────────
FROM node:lts-alpine AS deps
WORKDIR /app

# Copy only manifests first (better layer caching)
COPY package.json package-lock.json ./
RUN npm ci --omit=dev

# ── Stage 2: runtime image ────────────────────────────────────────
FROM node:lts-alpine AS runtime
WORKDIR /app

# Non-root user for security + su-exec for privilege drop in entrypoint
# Fixed uid/gid rather than whatever adduser -S happens to pick, so the ids
# the container runs as are known and stable across rebuilds. Not load-bearing
# for Cloud Run: that platform mounts the Cloud Storage volume itself as
# uid/gid 2001 with mode 0666/0777, i.e. writable whatever the container user is.
RUN addgroup -S -g 1001 isms && adduser -S -u 1001 -G isms isms \
    && apk add --no-cache su-exec

# Copy installed modules from build stage
COPY --from=deps /app/node_modules ./node_modules

# Copy application source (kein data/ – wird als Bind-Mount gemountet)
COPY server ./server
COPY ui     ./ui
# docs/ + die vier Root-Markdown-Dateien: werden von den Guidance-Seeds
# (ARCH_SEED in guidanceStore.js) zur Laufzeit eingelesen. .dockerignore
# filtert die grossen/internen Teile (docs/private, docs/community, ...)
# bereits raus — Gesamtgewicht der kopierten docs/ < 1 MB.
COPY docs ./docs
COPY Dockerfile ./
COPY README.md CONTRIBUTING.md CHANGELOG.md THIRD-PARTY-LICENSES.md ./
COPY package.json package-lock.json ./
COPY LICENSE CHANGELOG-LUMINA.md SOURCE-OFFER.md ./
COPY docker-entrypoint.sh ./

# AGPL-3.0 section 13: people interact with this modified version over the
# network, so its Corresponding Source has to be offered to them. The image
# carries its own source as a tarball and serves it at /source, which keeps the
# offer in step with whatever is actually deployed - a separate published copy
# can drift, and a drifted copy is a licence problem, not housekeeping.
# Excluded: node_modules (fetched from package-lock.json), data (ours, not part
# of the program), and our hosting notes.
RUN tar -czf /app/corresponding-source.tar.gz \
      --exclude='./corresponding-source.tar.gz' \
      ./server ./ui ./docs ./package.json ./package-lock.json ./LICENSE \
      ./README.md ./CONTRIBUTING.md ./CHANGELOG.md ./CHANGELOG-LUMINA.md \
      ./SOURCE-OFFER.md ./THIRD-PARTY-LICENSES.md ./Dockerfile ./docker-entrypoint.sh \
    && chmod 444 /app/corresponding-source.tar.gz

RUN chmod +x docker-entrypoint.sh \
    && chown -R isms:isms /app

# Container startet als root: Entrypoint legt Verzeichnisse an, chownt das
# (ggf. bind-gemountete) data/-Verzeichnis und wechselt dann per su-exec zu
# isms. USER isms hier zu setzen würde das verhindern (kein chown-Recht auf
# host-gemountete Verzeichnisse mit abweichendem Owner) — s. GitHub Issue #46.

# Environment defaults (override via .env.docker oder docker run -e)
ENV NODE_ENV=production \
    PORT=3000 \
    JWT_EXPIRES_IN=8h \
    DEV_HEADER_AUTH=false \
    STORAGE_BACKEND=json

EXPOSE 3000

# Healthcheck (HTTP; bei SSL auf https anpassen oder wget-Flag setzen)
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
  CMD wget -qO- http://localhost:3000/ui/login.html || exit 1

# Entrypoint erstellt fehlende Unterverzeichnisse und startet den Server
ENTRYPOINT ["./docker-entrypoint.sh"]
