17. Dependencies and upgrades¶
17.1. Runtime stack¶
Versions as of 1.4.4, as declared in the manifests. The manifests are the source of truth; this table is a map.
Component |
Version |
Declared in |
|---|---|---|
Node.js |
22.12 or later |
|
Express |
|
|
express-openapi-validator |
|
|
mysql2 |
|
|
Sequelize |
|
|
Umzug |
|
|
jsonwebtoken |
|
|
swagger-ui-express |
|
|
Angular |
|
|
PrimeNG and |
|
|
Tailwind CSS |
|
|
TypeScript |
|
|
Vitest and Vite |
|
|
angular-auth-oidc-client |
|
|
Sphinx |
|
|
furo |
|
|
The API also depends on the Vercel AI SDK and its provider packages for the mitigation feature, and the client on Chart.js, ngx-charts, ECharts, ExcelJS, and date-fns. Read the manifests for the rest.
17.2. Upgrade procedure¶
Dependencies are upgraded by hand, one package directory at a time, with npm-check-updates (a devDependency in both api/ and client/):
Run
npx ncuto see what is behind, thennpx ncu -uto update the manifest, reviewing major bumps individually.Reinstall to regenerate the lockfile:
npm installinapi/, andnpm install --forceinclient/. The client needs--forcebecause the peer range of@swimlane/ngx-chartshas lagged Angular majors; a lockfile produced under--forceinstalls only undernpm ci --force, and that is what theDockerfile, the PR Tests workflow, and the release workflow’s lockfile gate all run. Do not switch to--legacy-peer-deps;.npmrcsetslegacy-peer-deps = falseand the three installers above would fail.Commit the manifest and the lockfile together. A manifest change without its lockfile fails
npm ciin CI and in the release gate.Run the full test suite and a production build in the package you changed, and
npm run lint:specfor the API.After a PrimeNG upgrade, review
client/src/app/common/directives/multi-select.directive.ts, which reaches into theSelectcomponent’s internals, andclient/src/app/app-theme.ts, whose preset builds on the Aura compatibility layer.After an Angular major, expect the
--forcerequirement to persist until ngx-charts publishes a matching peer range.Use the commit subject
chore(api): Update dependencies,chore(client): Update dependencies, orchore(docs): Update dependencies.
The documentation requirements are split into a source file and a lock file. docs/requirements.in lists the five packages Sphinx is configured to use as minimum versions, plus colorama, which Sphinx requires only on Windows; listing it unconditionally keeps the lock installable on Windows however the lock is regenerated. docs/requirements.txt is generated from it and pins every package, direct and transitive, to an exact version with the SHA-256 hashes of every artifact published for that version, wheels and source distributions alike. Do not edit requirements.txt by hand. Regenerate it from the repository root with uv:
uv pip compile docs/requirements.in --generate-hashes --only-binary :all: --python-version 3.12 --universal -o docs/requirements.txt
Without further flags the command keeps the versions already in the lock, so it is the way to add a package or raise a floor. To see what is behind, add --upgrade and read git diff docs/requirements.txt; that diff is the report, and git checkout docs/requirements.txt discards it. --upgrade-package sphinx moves one package. docs/make.bat outdated (docs/build.sh outdated from bash) shows what is behind without touching the lock: it creates docs/.venv on first use, syncs it to the lock, and lists every package with a newer release on PyPI. A row that survives a regeneration is capped by another package’s requirement, as docutils is by Sphinx. --only-binary :all: restricts resolution to versions that publish a wheel. The command above is the canonical one; Dependabot rewrites the lock’s header comment with its own invocation.
The lock is installed with pip install --require-hashes --only-binary :all: by the PR Tests workflow and docs/Dockerfile, so neither can install a package that is missing from the lock, an artifact whose hash differs from the recorded one, or a source distribution. Read the Docs passes no flags. It enters hash-checking mode on its own because the file carries hashes, but it could build a source distribution whose hash is in the lock if no wheel matched its platform. docs/Dockerfile starts from sphinxdoc/sphinx:8.2.3 and pip upgrades Sphinx to the locked version at image build time. Rebuild the documentation image after regenerating the lock.
17.3. Automation¶
Dependabot is configured for GitHub Actions and for the documentation’s Python packages (.github/dependabot.yml), each weekly and grouped into one pull request: Actions with a ci commit prefix, docs/ with chore(docs). Actions are referenced by commit SHA with a version comment, and Dependabot keeps the SHAs current. The docs/ entry uses the uv ecosystem, which regenerates requirements.txt with uv pip compile and keeps the hashes, the --universal marker set, and the Python floor recorded in the lock’s header; because requirements.in holds floors, a bump normally changes the lock alone. Dependabot does not pass --only-binary, so the PR Tests docs job, which does, is the check that a new version still publishes a wheel. Security updates for npm packages arrive as Dependabot pull requests without configuration. There is no Renovate.
17.4. Rules that keep installs reproducible¶
Both
.npmrcfiles setengine-strict = true,legacy-peer-deps = false,audit = true, andfund = false.Both manifests carry
"overrides": { "uuid": "^14.0.2" }, which pins the transitiveuuidversion.docs/requirements.txtpins every Python package, direct and transitive, with the hashes of every published artifact, and the PR Tests workflow anddocs/Dockerfileinstall it with--require-hashes --only-binary :all:.The client manifest lists
typescriptandtypescript-eslintunderdependenciesrather thandevDependencies; a production install of the client package is never performed, so this has no runtime effect.Node is pinned by the
enginesrange, bynode-version: "22"in the workflows, and by thenode:lts-alpinebase image. There is no.nvmrc.Lockfile integrity is checked by the release workflow’s dry-run installs before anything is pushed. See Release process.
17.5. Licenses¶
The production client build writes client/dist/3rdpartylicenses.txt with the licenses of every bundled package (extractLicenses in angular.json). The PrimeNG license key is not a dependency: it reaches the client from CPAT_PRIMENG_LICENSE or from a build secret baked into the published image, and it is never committed. See Building a Custom Image.