Dependency Policy
Purpose
Section titled “Purpose”Dependencies must support self-hosted operation, commercial use, and future customer-owned on-premise Kubernetes deployments.
This policy applies to runtime dependencies, development dependencies, build tooling, generated artifacts, and optional integrations.
Dependency Classes
Section titled “Dependency Classes”Runtime dependencies are packaged with applications or required for production operation. They need explicit review for:
- license compatibility with commercial use and redistribution,
- self-hosted and on-premise operation,
- required external services,
- operational ownership,
- security update path,
- replacement strategy when the dependency is adapter-facing.
Development dependencies are used for local checks, CI, tests, documentation, or build tooling. They still need license review, but they must not become required runtime services.
Optional proprietary integrations must be isolated behind adapters and must not be required for core platform operation.
License Expectations
Section titled “License Expectations”Allowed by default after review:
- MIT,
- Apache-2.0,
- BSD-2-Clause,
- BSD-3-Clause,
- ISC.
Requires explicit review before adoption:
- LGPL,
- MPL,
- EPL,
- AGPL,
- GPL,
- custom or source-available licenses,
- licenses with field-of-use, SaaS, hosting, telemetry, or redistribution restrictions.
Unknown license metadata blocks adoption until clarified.
Change Requirements
Section titled “Change Requirements”When adding dependencies, the same change must document:
- package name and purpose,
- runtime or development classification,
- license,
- whether the dependency requires a proprietary service,
- whether it affects deployment, Helm values, secrets, or environment variables,
- whether it changes a public or cross-module contract.
Runtime dependencies that affect contracts, configuration, deployment, security, tenancy, persistence, or operations also require matching documentation and tests.
Dependency update workflow
Section titled “Dependency update workflow”GitHub Dependabot alerts report known vulnerabilities. Dependabot security updates and version-update pull requests are disabled. Keep the alerts enabled when changing the repository security settings.
Renovate scans package manifests, GitHub Actions, Dockerfiles, and Docker Compose
files. It records available updates in the Dependency updates GitHub Issue.
An update becomes actionable after a minimum release age of seven days.
The dashboard is the update backlog. To implement an update manually, create a branch from the current default branch and open a pull request with the manifest, lockfile, code, test, and documentation changes that the update needs. Do not select the dashboard checkbox. Renovate removes the item after the update reaches the default branch.
Select a dashboard checkbox only when Renovate should prepare a routine update
pull request. Every routine update requires this explicit approval. Known
vulnerabilities bypass dashboard approval so Renovate can create a remediation
pull request; Dependabot alerts remain an independent notification source. CI
also runs pnpm audit --prod, so a known production vulnerability blocks the
change until the dependency graph is patched or an exception is reviewed and
documented.
The hosted Mend Renovate GitHub App runs this repository automation. Renovate’s update engine uses the AGPL-3.0-only license. The hosted app is an optional proprietary development service and has no platform runtime or deployment impact. It requires read and write access to repository contents, workflows, issues, pull requests, checks, and commit statuses. It also needs read access to repository administration metadata and Dependabot alerts. The service clones the private repository while a job runs and retains dependency, version, and pull-request metadata. It does not require a repository secret.
Phase 2 Tooling Dependencies
Section titled “Phase 2 Tooling Dependencies”Phase 2 adds these root development dependencies:
| Package | Purpose | License | Runtime impact |
|---|---|---|---|
eslint | JavaScript and TypeScript linting | MIT | None |
@eslint/js | ESLint recommended JavaScript rules | MIT | None |
typescript-eslint | ESLint support for TypeScript | MIT | None |
eslint-config-prettier | Disable conflicting formatting rules | MIT | None |
prettier | Repository formatting baseline | MIT | None |
prettier-plugin-astro | Format Astro files when present | MIT | None |
vitest | Unit test runner | MIT | None |
globals | Shared ESLint global definitions | MIT | None |
@types/node | Node.js type declarations | MIT | None |
These dependencies are dev-only, do not add production services, do not require secrets, and do not change application behavior.
Documentation dependencies
Section titled “Documentation dependencies”The documentation image self-hosts its build output and API tools. It does not use a hosted documentation registry or request proxy.
| Package | Purpose | License | Runtime impact |
|---|---|---|---|
astro, @astrojs/starlight | Static documentation application and content model | MIT | Build output served by the existing docs container |
starlight-openapi | Generates operation pages from the repository OpenAPI file | MIT | Build-time generation only |
@scalar/api-reference@1.64.0 | Interactive OpenAPI reference and browser request client | MIT | Self-hosted browser assets in the docs image |
starlight-theme-celestia | Documentation presentation theme | MIT | CSS and static UI assets |
Scalar telemetry is disabled, authentication persistence is disabled, and no
proxy.scalar.com or other hosted Scalar service is configured. Browser
requests go directly to the API server selected from the repository-owned
OpenAPI document. The vue-demi install script is approved because Scalar’s
self-hosted Vue bundle requires its local compatibility setup; it performs no
runtime network or hosted-service integration.
Local Infrastructure Images
Section titled “Local Infrastructure Images”Local development operates the database by default. The explicit ingestion profile also runs the pinned NATS image.
| Image | Purpose | License review | Runtime impact |
|---|---|---|---|
timescale/timescaledb:2.28.1-pg17-oss@sha256:… | Local PostgreSQL/TimescaleDB database | TimescaleDB Apache 2 Edition: Apache-2.0 | Local infrastructure only |
nats:2.14.0-alpine3.22@sha256:… | Durable raw-ingestion stream | Apache-2.0 | Optional local profile and Kubernetes runtime |
Image references retain a readable version tag and pin the exact manifest
digest. The TimescaleDB image uses the -oss tag so the local default stays on
the Apache-2.0 edition. If later work requires TimescaleDB Community features,
that must be reviewed and documented as a separate licensing decision.
The Apache-2.0 edition is sufficient for the Phase 3 local database container and for validating connectivity. It does not close the later database decision for automated TimescaleDB retention policies, compression, continuous aggregates, or other features that may require the Timescale License.
NATS JetStream is the active durable stream for Netmore raw ingestion. It is self-hosted, cluster-internal, bounded by stream limits, and replaceable behind the internal raw-event contract. A permanent mock MQTT broker is not part of the target architecture.
Phase 9/10 ingestion dependencies
Section titled “Phase 9/10 ingestion dependencies”| Package / image | Purpose | License | Runtime impact |
|---|---|---|---|
mqtt@5.15.2 | MQTT 3.1.1/TLS client and PUBACK backpressure boundary | MIT | mqtt-ingestion-worker only |
@nats-io/jetstream@3.4.0 | JetStream publish, bootstrap, and pull-consume APIs | Apache-2.0 | Both ingestion workers and bootstrap |
@nats-io/transport-node@3.4.0 | Node.js NATS transport | Apache-2.0 | Both ingestion workers and bootstrap |
@nats-io/nats-core@3.4.0 | Shared NATS connection types and core protocol | Apache-2.0 | Both ingestion workers |
nats:2.14.0-alpine3.22@sha256:… | Self-hosted single-replica JetStream server | Apache-2.0 | Cluster-internal StatefulSet with PVC |
natsio/prometheus-nats-exporter:0.20.1@sha256:… | Converts local NATS and JetStream state to Prometheus metrics | Apache-2.0 | NATS metrics sidecar only |
None requires a proprietary or hosted runtime. Netmore is an optional external provider integration isolated inside the adapter; raw storage and the internal event contract do not depend on its SDK.
Phase 4 Runtime Dependencies
Section titled “Phase 4 Runtime Dependencies”Phase 4 adds runtime dependencies for the shared service baseline. They do not require proprietary services and are compatible with self-hosted and future customer-owned Kubernetes deployments.
| Package | Purpose | License | Runtime impact |
|---|---|---|---|
zod | Runtime configuration schema validation | MIT | Application library, no external service |
pino | Structured JSON logging | MIT | Application library, no external service |
fastify | Health, readiness, and metrics HTTP endpoints | MIT | Application library, no external service |
prom-client | Prometheus-compatible metrics exposition | Apache-2.0 | Application library, no external service |
These dependencies affect runtime behavior, configuration validation, logs, metrics, and operation endpoints. They do not add new Helm values yet, do not introduce secrets, do not add persistence, and do not change tenant-owned data paths.
Phase 4.5 Deployment Images and Tooling
Section titled “Phase 4.5 Deployment Images and Tooling”Phase 4.5 adds container packaging, a Helm chart, and GitOps deployment infrastructure for the dedicated Kubernetes test and controlled production environments.
Application container images use node:24-bookworm-slim as the runtime and
build base. The image packages the service and its production dependencies only.
It must not contain local environment files, SSH keys, Kubernetes credentials,
or production secrets.
The Helm chart under infra/helm/sens-platform can deploy embedded
infrastructure for the early single-node environments:
| Image | Purpose | License review | Runtime impact |
|---|---|---|---|
timescale/timescaledb:2.28.1-pg17-oss@sha256:… | PostgreSQL/TimescaleDB StatefulSet | TimescaleDB Apache 2 Edition: Apache-2.0 | Early single-node environments |
| Argo CD | GitOps sync and environment status overview | Apache-2.0 | Cluster operations component |
| cert-manager | ACME certificate management | Apache-2.0 | Cluster operations component |
| Traefik | Existing k3s ingress controller | MIT | Existing cluster ingress component |
The chart references Kubernetes Secrets by name and must not render secret
values from committed defaults. The dedicated environments use
sens-test-timescaledb-auth or sens-production-timescaledb-auth for the
embedded TimescaleDB password and ghcr-pull for GHCR image pulls.
CI uses Helm only for rendering and linting. Helm is a deployment validation tool and does not add an application runtime dependency.
Secret-Management Runtime Components
Section titled “Secret-Management Runtime Components”The self-hosted secret-management workflow adds these cluster runtime components. All versions are pinned in the infra repository and must be upgraded through a reviewed render, backup, test, and rollback procedure.
| Component / image | Purpose | License review | Scope |
|---|---|---|---|
OpenBao chart 0.28.6, server 2.6.1 | KV-v2, audit, Raft storage, auth, and policy | MPL-2.0 | Dedicated openbao namespace |
External Secrets Operator chart 2.8.0 | OpenBao-to-Kubernetes synchronization | Apache-2.0 | Four namespace-scoped controller instances |
Stakater Reloader chart 2.2.14 | Restart on synchronized Secret changes | Apache-2.0 | One scoped controller per environment |
OpenBao is self-hosted and required for the active secret-management path. Its MPL-2.0 license has been explicitly reviewed for this network service use. Test, Production, and Operations use separate mounts and policies.
The operators are namespace-scoped and do not receive cluster-wide access to Kubernetes Secrets. External Secrets custom resource definitions are installed once through a separate cluster-scoped Argo CD Application. NetworkPolicies restrict ingress to OpenBao and its allowed clients. No component requires a proprietary hosted service.
Phase 6 Database Dependencies
Section titled “Phase 6 Database Dependencies”Phase 6 adds the PostgreSQL repository and migration implementation. These packages run entirely inside the self-hosted application and migration containers and do not require a proprietary service.
| Package | Purpose | License | Runtime impact |
|---|---|---|---|
pg | PostgreSQL connection pool and queries | MIT | Runtime database adapter |
node-pg-migrate | Versioned SQL migration execution | MIT | Database migration image only |
@types/pg | TypeScript declarations for the pg package | MIT | Development and build-time type information |
pg is isolated behind @sens-platform/database repositories and connection
helpers. node-pg-migrate is packaged into the dedicated database migration
image and is not required by long-running service containers. Their deployment
configuration and secret handling are documented in the database migration and
runtime configuration runbooks.
Phase 7A Authentication Dependencies
Section titled “Phase 7A Authentication Dependencies”Phase 7A adds self-contained libraries to platform-api; none requires a hosted
or proprietary runtime service.
| Package | Purpose | License | Runtime impact |
|---|---|---|---|
argon2 | Native Argon2id password hashing and verification | MIT | CPU/memory-bounded API operation; native binary packaged in the image |
jose | HS256 JWT issue and verification | MIT | In-process cryptography only |
@fastify/cookie | Host-only HttpOnly refresh-cookie parsing and serialization | MIT | Fastify plugin, no service |
@fastify/cors | Exact-origin browser policy with credentials | MIT | Fastify plugin, no service |
@zxcvbn-ts/core | Offline password-strength estimation | MIT | In-process password validation |
@zxcvbn-ts/language-common | Local common-password dictionaries and graphs | MIT | Packaged static data, no network request |
@sens-platform/database | Auth repositories and PostgreSQL session state | Private workspace package | Existing self-hosted PostgreSQL dependency |
The container build copies and compiles the database workspace package and
includes the approved argon2 native build lifecycle. No password, token, or
identifier is sent to a third-party service.
The Phase 7A security review also requires patched Fastify transitive runtime
versions. The lockfile resolves find-my-way to 9.7.0 or newer and overrides
affected fast-uri 3.x/4.x ranges to patched versions within the same major
line. These resolutions address the upstream
find-my-way HTTP denial-of-service
and
fast-uri URL host-confusion
advisories without adding another runtime component or bypassing the
repository’s dependency-age checks.
Phase 8 telemetry-flow dependencies
Section titled “Phase 8 telemetry-flow dependencies”The visual flow slice adds only self-hostable in-process libraries. No package requires an external proprietary runtime.
| Package | Purpose | License | Runtime impact |
|---|---|---|---|
@xyflow/react | Visual DAG canvas and port interactions | MIT | Browser bundle only |
quickjs-emscripten | Isolated custom-script JavaScript runtime | MIT | WASM inside the dedicated sandbox worker |
handlebars | Strict tenant e-mail template rendering | MIT | Action worker with an explicit helper allowlist |
sanitize-html | Sanitizes rendered e-mail HTML | MIT | Action worker only |
nodemailer | SMTP adapter | MIT-0 | Action worker only; no hosted service required |
axllent/mailpit:v1.27.8@sha256:… | Optional local SMTP sink and inspection UI | MIT | Compose actions profile only; never Helm |
React Flow does not send telemetry. The QuickJS adapter is isolated behind the sandbox request contract and hardened by process and Pod boundaries. Its use is not a claim of a complete security audit; the documented review remains a mandatory production gate. Custom-script editing was outside the initial slice; the completion adds Monaco as direct ESM modules with local workers and no CDN; script source is never executed in the browser. Mailpit is a fixed local-development image and is not a core runtime dependency or production deployment component.
Web-console dependencies
Section titled “Web-console dependencies”apps/web-console uses only self-hosted browser and build dependencies. None
sends telemetry or requires a hosted service.
| Package / tool | Purpose | License | Runtime impact |
|---|---|---|---|
react, react-dom | Permanent platform web console | MIT | Browser bundle only |
react-router ^8.3.0 | Declarative, hash-free browser routing | MIT | Browser bundle only; no hosted service |
vite | Static production build and local dev server | MIT | Build/development only |
@vitejs/plugin-react-swc | React transform through SWC | MIT | Build/development only |
@swc/core | Native SWC compiler used by the Vite plugin | Apache-2.0 | Approved install script; absent from runtime image |
| Testing Library packages | Accessible component interaction tests | MIT | Test only |
happy-dom | Browser DOM implementation for unit tests | MIT | Test only |
class-variance-authority | Typed component variants | Apache-2.0 | Browser bundle only |
clsx, tailwind-merge | Deterministic class composition | MIT | Browser bundle only |
lucide-react | Tree-shakeable interface icons | ISC | Browser bundle only |
| Direct Radix primitive packages | Accessible shadcn interaction and composition primitives | MIT | Browser bundle only; no aggregate runtime barrel |
tailwindcss, @tailwindcss/vite | shadcn-compatible token utilities and build integration | MIT | Build/development only |
tw-animate-css | Reduced-motion-compatible utility definitions | MIT | Build/development only |
@xyflow/react | Typed visual telemetry-flow canvas | MIT | Browser bundle only |
monaco-editor 0.56.0 | Custom TypeScript source editor and local language worker | MIT | Lazy Scripts-view browser chunk; no CDN |
@sentry/node, @sentry/react | Optional sanitized error and performance reporting | MIT | No-op when disabled; optional EU SaaS |
@sentry/vite-plugin | CI source-map upload and deletion | MIT | Build only; token never enters runtime |
posthog-js | Consent-based fixed product events | MIT | Browser only, Production flag, dynamically loaded |
axe-core | Automated accessibility assertions | MPL-2.0 | Test only; absent from runtime image |
The final container contains only Node.js, the built static assets, and the dependency-free runtime server. Runtime configuration is injected when the container starts and is not baked into the browser bundle.
React Router 8 requires Node.js >=22.22.0 for development and builds. CI and
container builds use the pinned Node.js 24 Active LTS line. Dependabot may update
that line, but a new Node.js major is adopted only through an explicit migration
after it reaches Active LTS. Routing remains client-side; no additional runtime
service, environment variable, Ingress rule, or Helm value is required.