Skip to content

ADR-001: Repo topology and shared-session mechanism

Source of truth: docs/adr/001-topology-and-session.md (synced at build time — edit the original, not this copy). Status: Accepted (2026-07-03 — routing + compose cutover authored; live e2e verified 2026-07-03 against v0.2.6 / v0.18.0: scripts/verify-sso.sh 7/7 cutover checks PASS — see docs/sso-verification.md)

Superseded in part by ADR-003 (2026-07-03): the shared-cookie mechanism (Decision 2) stands, but the issuer moved — Veltro, a standalone identity app, is now the suite authority (not VectorFlow). VectorFlow and CHAD both delegate to Veltro. Decision 1 (separate repos + thin platform repo) is unchanged.

Amended by ADR-004 (2026-07-04): the per-product delegated-auth flag is now the single VELTRO_INTEGRATED and the fanned session secret is VELTRO_SESSION_SECRET.

VectorFlow (Next.js/NextAuth v5, AGPL, ghcr images) and CHAD (FastAPI + React SPA, ghcr images) must ship as one product experience while remaining deployable standalone (CHAD-only for users with an existing logging stack). Both repos have live CI, worktrees, and published images.

Decision 1: Separate repos + one thin suite repo

Section titled “Decision 1: Separate repos + one thin suite repo”

No monorepo, no submodules. Application repos stay where they are; this repo contains only compose profiles (full|vectorflow|chad), nginx config, the unified env contract, pinned image tags (versions.env), a multi-root .code-workspace, and ADRs. Rationale: a solo dev gains nothing from merging git histories; both products already publish ghcr images the suite can pin; the AGPL (VectorFlow) vs undecided CHAD license question makes code-level merging premature. VF Lake (ClickHouse) and the OpenSearch bundle are omitted from suite v1; they return behind opt-in profiles when a deployment needs them.

Decision 2: Shared session = direct Auth.js JWE decode in CHAD

Section titled “Decision 2: Shared session = direct Auth.js JWE decode in CHAD”

In the full profile, VectorFlow is the suite’s identity authority and CHAD (CHAD_DELEGATED_AUTH=true) authenticates browser requests by decrypting VF’s Auth.js session cookie directly: HKDF-SHA256 of the shared secret (VF_SESSION_SECRET, = VF’s NEXTAUTH_SECRET), JWE dir/A256CBC- HS512, via python-jose (already a CHAD dependency; encrypt-in-Node → decrypt-in-Python verified end-to-end). One login, one logout, zero per-request hops. Standalone CHAD (CHAD_DELEGATED_AUTH=false, the container default) keeps its own login/OIDC unchanged.

Section titled “Rejected: suite-token cookie (15-min VF-minted token)”

Fatal refresh gap: only VF middleware could refresh it, so a user living in /chad/* would be hard-logged-out every 15 minutes.

Rejected: external IdP (Keycloak/Authentik)

Section titled “Rejected: external IdP (Keycloak/Authentik)”

A fourth stateful service for a solo dev, and VF’s DB-configured OIDC/SAML settings UI already does the upstream-IdP job.

If an Auth.js upgrade changes the cookie format, or VF Cloud’s per-org DEK-derived keys unpark (which silently breaks shared-secret decode — CHAD carries a loud startup guard for exactly this), the fallback is a VF /api/internal/session introspection endpoint that CHAD calls per request. A committed VF-minted cookie fixture + contract test guards against format drift. As of ADR-005 that fixture and test live in the veltro-suite-auth package and VF CI (a fresh Node-minted cookie decoded in Python, per PR), not CHAD’s CI.

  • NEXTAUTH_SECRET is the suite’s crown-jewel secret: it now mints valid sessions for BOTH apps. Rotating it logs everyone out of both.
  • Single-origin nginx is required for cookie sharing (host-only cookie). The final layout is three zones: / → 302 /vectorflow/launcher, /vectorflow/* → VectorFlow (basePath baked), /chad/* → CHAD.
  • versions.env is the only file that changes on routine upgrades.