Ctrl K
ComunidadGuías…

Dockerfile

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# syntax=docker/dockerfile:1
#
# YourPHR: the Angular app and the TypeScript server, one image (yourphr#587, yourphr#652).
#
# THE FRONTEND IS BUILT HERE, from frontend/ in this repository. It used to be copied out of the
# released Go image, because the two stacks lived in two repositories and the spike had no frontend
# of its own. They are one repository now (yourphr#650), so the UI and the server that serves it are
# built from the same commit — which is the thing that arrangement could not give.
#
# MULTI-ARCH without native runners: the TypeScript compiles on the BUILD platform (its output is
# arch-independent), and the only native dependency, better-sqlite3-multiple-ciphers, ships linux
# x64 AND arm64 prebuilds, so the per-arch stages download rather than compile. No QEMU compile.

# --- the Angular app --------------------------------------------------------------------------
FROM --platform=$BUILDPLATFORM node:24-bookworm-slim AS frontend
WORKDIR /build/frontend
COPY frontend/package.json frontend/yarn.lock ./
RUN yarn install --frozen-lockfile --network-timeout 600000
COPY frontend ./
# Writes to /build/dist/web — one dist/, all TypeScript, and the Angular build CLEARS its output
# directory, which is why the two halves have their own subdirectories.
#
# `-c prod` IS LOAD-BEARING (yourphr#673). angular.json declares no defaultConfiguration, so a bare
# `ng build` applies no fileReplacements and ships src/environments/environment.ts — the DEVELOPMENT
# file, with production:false (enableProdMode never runs) and environment_name "sandbox". 3.0.0 and
# 3.1.0 both shipped it, which is how a production PHR came to display "sandbox-3.1.0" and to tell
# patients on the sources page that it "cannot access real patient information".
#
# The Go image built with `--configuration ${YOURPHR_ENV}`; that flag was lost when the frontend
# build moved into this repository (yourphr#652). It is `prod` unconditionally now rather than a
# build argument: one image serves every instance, and what an instance IS is runtime configuration
# (yourphr.web.environment-name), never something compiled in.
RUN yarn build -- -c prod
# The tooth. `outputHashing: "all"` lives in the CONFIGURATIONS, not the base options, so hashed
# filenames are the structural signature that a configuration was applied at all. Asserting on that
# rather than on a string inside the bundle is deliberate: a marker string is a guard that rots
# silently the day someone edits the environment file, and this failure mode is already one that
# looked exactly like success.
RUN test ! -e /build/dist/web/main.js \
    && ls /build/dist/web/main.*.js > /dev/null \
    || (echo "REFUSED: the Angular output is unhashed — 'ng build' ran with no configuration, so it has shipped environment.ts (development). See yourphr#673." >&2; exit 1)

# --- compile TypeScript once, on the build platform -------------------------------------------
FROM --platform=$BUILDPLATFORM node:24-bookworm-slim AS build
WORKDIR /build
COPY package.json package-lock.json tsconfig.json tsconfig.build.json ./
# --ignore-scripts: the repo's `prepare` hook wires git hooks, which has no business in an image.
RUN npm ci --ignore-scripts
COPY src ./src
RUN npm run build

# The demo's baked-in baseline (yourphr#645): the databases a public demo resets itself to, built
# HERE so what ships is reproducible and nobody hand-curates a database strangers will read.
# Everything in it is synthetic, generated by the same fake provider the harnesses use, and it
# carries no working credential — both demo passwords are provisioned at startup. SQLite files are
# architecture-independent, so building on the build platform is correct.
COPY scripts ./scripts
COPY config ./config
RUN npx tsx scripts/build-demo-baseline.ts --out /build/baseline

# --- production dependencies for the TARGET platform ------------------------------------------
FROM node:24-bookworm-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev --ignore-scripts && npm cache clean --force

# --- the runtime --------------------------------------------------------------------------------
FROM node:24-bookworm-slim
ENV NODE_ENV=production
WORKDIR /opt/yourphr
COPY --from=deps /app/node_modules ./node_modules
COPY --from=build /build/dist/server ./dist/server
COPY package.json ./
# The shipped defaults are part of the product (yourphr#621): the process refuses to boot without
# them, and WORKDIR is where FileConfigProvider looks. Instance overrides live under ./data.
COPY config ./config
# Inert on every instance that is not a demo: the reset needs demo.enabled AND reset-on-restart AND
# this directory, and then still has to prove the database belongs to a demo (yourphr#645).
COPY --from=build /build/baseline ./baseline
COPY --from=frontend /build/dist/web ./web
RUN mkdir -p /opt/yourphr/data && chown -R node:node /opt/yourphr
USER node

# Bootstrap only (yourphr#472): where the data lives, where the UI is, which port. Settings live in
# the config store under the data directory. Secrets (YOURPHR_DATABASE_ENCRYPTION_KEY,
# YOURPHR_BACKUP_ENCRYPTION_KEY) come from the orchestrator, never from an image.
# Names derive from the configuration keys, which carry the yourphr. prefix (yourphr#627). The
# pre-#627 SPIKE_* names are still accepted with a warning, so a deployment whose manifests have
# not been updated keeps booting; that fallback goes at the cut-over (yourphr#588). Secrets and any
# other bootstrap value belong in <YOURPHR_FAST_STORAGE>/.env on the mounted volume (yourphr#630),
# never in this image.
ENV YOURPHR_FAST_STORAGE=/opt/yourphr/data \
    YOURPHR_SLOW_STORAGE=/opt/yourphr/data \
    YOURPHR_WEB_STATIC_DIR=/opt/yourphr/web \
    YOURPHR_WEB_LISTEN_PORT=8080
EXPOSE 8080
VOLUME ["/opt/yourphr/data"]
# ENTRYPOINT plus a default CMD, not CMD alone (yourphr#654). Words after the image name REPLACE
# CMD and leave ENTRYPOINT in place, so `docker run … <image> migrate --go …` — what the upgrade
# guide has always told self-hosters to run — becomes `node dist/server/main.js migrate --go …`.
# With CMD alone those words replaced the whole command and docker looked for a binary called
# `migrate`, which is why the documented upgrade could not be performed from the image.
#
# `start` is the default, so an argument-less `docker run` and every existing Deployment (neither
# yourphr nor demo-yourphr sets command: or args:) behave exactly as before. A shell for debugging
# now needs --entrypoint, which is the ordinary cost of a container that has more than one job.
ENTRYPOINT ["node", "dist/server/main.js"]
CMD ["start"]