> ## Documentation Index
> Fetch the complete documentation index at: https://docs.findmydata.io/llms.txt
> Use this file to discover all available pages before exploring further.

# ADR 0015 commercial web and control plane

# ADR-0015: Commercial web ecosystem, human/machine plane separation, licensing

**Status:** Accepted · 2026-07-15 (applies handoff update-001)

## Context

Update-001 (`find_my_data_handoff/FIND_MY_DATA_CLAUDE_UPDATE_001/`) adds the
commercial web and customer lifecycle around the customer-hosted platform:
marketing, account portal, licensing, entitled downloads, support, an isolated
demo, a protected dev environment, and Cloudflare domain management. The core
invariant is unchanged and reinforced: **customer content never leaves the
customer boundary to license or support the product.**

## Decisions

### 1. Two planes, never merged: customer content plane vs. vendor commercial/control plane

The installed Find My Data platform (this repository) runs inside the customer's
Azure environment and holds all content, evidence, findings, identities, and
Analyst conversations. The vendor operates a separate commercial/control plane
for accounts, evaluations, licensing, downloads, support, and *minimized* fleet
health. Content, excerpts, filenames, paths, fingerprints, embeddings,
identities, permissions, findings, and prompts do not cross into the vendor
plane. Enforced in code by the strictly-allowlisted telemetry schema
(`controlplane/telemetry.ts`, `.strict()` + denylist test) and by keeping the
control-plane surface to licensing + coarse health only.

### 2. Human Account plane ≠ machine Control plane ≠ in-product roles

Three identity contexts stay distinct: `account.findmydata.io` (people —
commercial org, evaluations, downloads), `control.findmydata.io` (installed
software + scanners — activation, signed entitlement renewal, allowlisted fleet
health), and the capability roles *inside* each customer deployment (ADR-0004,
`capabilities.ts`). A human portal token is never the product's license
credential. This build implements the deployment side of the Control contract;
the vendor-hosted Account/Control services are out of this repository's scope
(they hold the signing private keys).

### 3. No `app.findmydata.io`

The product is customer-hosted with a customer-controlled URL and identity
context. `app.findmydata.io` would imply a shared SaaS data plane that does not
match the architecture; it is reserved, not built.

### 4. Signed, versioned entitlements verified locally (ADR extends the control plane)

Entitlements are signed by Control and verified locally by the deployment
(`controlplane/entitlement.ts`). Two verification algorithms selected by the
token header:

* **Ed25519** — the production shape: the deployment embeds/trusts only the
  vendor *public* key; the signing *private* key never leaves the hardened
  vendor service.
* **HMAC** — a runnable dev/test default.

Keys carry a `kid` so they rotate; the entitlement is versioned
(`entitlementVersion`) and expresses edition, feature flags, capacity meters,
term, connector families, offline/renewal policy, issuer, and a supersession
reference. Activation stores a verified token (an auditable **offline** path is
first-class; the live outbound path is gated on `controlUrl`). Renewal
re-verifies and reports the next-due time within a grace window.

### 5. Non-destructive expiry

Past the offline grace window an entitlement is `expired`, which the enforcement
layer (`assertLicensedOperation`, `LicenseError` 402) treats as "no new licensed
operations" (e.g. starting a new scan). It **never** deletes, encrypts, or locks
the customer's own configuration, findings, audit, or export. Unlicensed (no
entitlement configured) is permissive so the product runs unrestricted until a
customer activates a license.

### 6. Marketing/web surfaces are documented + minimally scaffolded, not prioritized over core

Per update-001's explicit guidance, a marketing-site build must not displace
core product work. This build adds a single self-contained static landing page
(`site/index.html`) that is brand-consistent and honest (customer-hosted, not a
consumer locator), plus the web-ecosystem architecture in the design set and a
Cloudflare domain runbook. The Account portal, Support platform, Demo instance,
and live Cloudflare changes are captured as design + roadmap, not built here.

### 7. Cloudflare: documented, reversible, inspect-first — no unattended live changes

The domain runbook (`docs/cloudflare-runbook.md`) records the intended DNS,
redirect, and Access posture with inspect-first discipline and rollback notes.
No live Cloudflare changes are made without explicit per-change confirmation;
registrar ownership, transfer lock, DNSSEC, recovery contacts, and email
delivery are preserved.

## Consequences

* The licensing/control-plane code now matches the commercial design (§6 of the
  new web-account-licensing design doc), while the content boundary stays an
  enforced invariant.
* The commercial web ecosystem is architecturally captured and lightly
  scaffolded; the heavy vendor-side services remain future work, honestly staged
  in `STATUS.md` and `docs/roadmap.md`.
* Product versioning is unchanged (`year.month.day.x`); this update is release
  **26.7.15.1** (a same-day increment over 26.7.15.0).
