Skip to content

Deploy pipeline — coaching user permissions

The admin Deploy page runs shell steps as the same Unix user as the Next.js / pm2 process (typically coaching). Below is what that user must be allowed to do.

Node.js version (npm warn EBADENGINE)

package.json declares "engines": { "node": ">=22.0.0", "npm": ">=10.0.0" }. Some Prisma tooling also expects Node ≥ 22.

If production runs Node 20 (or older), npm install during Deploy prints EBADENGINE Unsupported engine — npm still installs by default, but you are outside the supported range and should upgrade.

Fix on the server

  1. Install Node.js 22 LTS (same major for shell and pm2 — pm2 uses the node binary it was started with).

Option A — nvm (as coaching or deploy user):

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.nvm/nvm.sh
nvm install 22
nvm alias default 22
node -v   # v22.x

Option B — NodeSource / distro packages — use your distribution’s Node 22 packages so /usr/bin/node is v22.

  1. Reinstall globals if needed (npm i -g pm2), then pm2 restart / pm2 reload the app from the same environment where node -v is 22.

  2. Optional: enforce engines in CI with engine-strict=true in .npmrc — not recommended on the server until Node is upgraded.

Do not “fix” only package.json engines

Lowering engines to Node 20 silences the warning for coach-studio, but transitive packages (e.g. @prisma/streams-local) can still report EBADENGINE until Node is actually ≥ 22.

If PM2 runs under systemd, put the Node bin directory first in the unit PATH — see PM2 systemd and Node.js.

Repository and generated files

  • Read/write on the whole clone (e.g. /var/www/coaching), including:
  • documentation/site/ — recreated by mkdocs build on each deploy.
  • Prefer ownership of the clone by coaching so builds never require sudo for writing HTML.

What each step needs

Area Requirement
Git / npm / Node / Prisma / Next Commands on PATH; no extra Unix privilege.
MkDocs (documentation/build-from-deploy.sh) python3, python3 -m pip, write permission under documentation/site/. Optional write access for pip installs (see next section).
Systemd cron (deploy/cron/install-from-deploy.sh) sudo only if you configured passwordless install.sh — see deploy/cron/README.md. Otherwise the step prints SKIP and exits successfully.

Python / pip and --break-system-packages

The deploy script runs:

python3 -m pip install -r documentation/requirements.txt --break-system-packages -q
mkdocs build -q

On recent Debian / Ubuntu, system Python is marked externally managed (PEP 668), so pip install without a venv fails unless you use --break-system-packages or a virtual environment.

Using the flag lets the coaching user install MkDocs, mkdocs-material, and mkdocs-static-i18n into that Python environment without sudo. Trade-off: those packages live in the shared Python install used by python3 (often acceptable on a dedicated app server).

Isolation alternative

For stricter isolation, create documentation/.venv once (as coaching), pip install -r requirements.txt inside it, and change documentation/build-from-deploy.sh to source .venv/bin/activate before mkdocs build, without --break-system-packages.

Summary

Privilege Needed for
Normal user (coaching) owning the repo Git pull, npm, Next build, MkDocs output, pm2 reload
pip install … --break-system-packages MkDocs dependencies on PEP 668 hosts without a venv
Passwordless sudo for deploy/cron/install.sh only Optional — refresh systemd timer units during deploy

Root (sudo) is not required for the documentation build if coaching can write documentation/site/.