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.sh7/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_INTEGRATEDand the fanned session secret isVELTRO_SESSION_SECRET.
Context
Section titled “Context”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.
Rejected: suite-token cookie (15-min VF-minted token)
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.
Escape hatch: introspection endpoint
Section titled “Escape hatch: introspection endpoint”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.
Consequences
Section titled “Consequences”NEXTAUTH_SECRETis 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.envis the only file that changes on routine upgrades.