7b5ee8a7bc
## What Enriches the **enterprise-only** license-validation channel (`/validate`, `/seats`) with best-effort instance metadata so the licensing backend can later reconcile seats and surface signs of license abuse (e.g. one subscription on many `serverId`s, a `serverId` on many URLs, dev-mode-in-prod). Reported alongside the existing `enterpriseKey` (and `seatCount` on `/seats`), under a new `instanceMetadata` object: | Field | Purpose | |---|---| | `serverId`, `serverUrl` | instance identity — sharing / clone signals | | `workspaceCount`, `activeUserWorkspaceCount`, `distinctUserCount` | seat reconciliation / overage | | `appVersion`, `nodeEnv`, `telemetryEnabled` | fleet/support; dev-mode-in-prod signal | | `adminContactEmail` | **single** administrative contact (oldest active user) for license administration — explicitly *not* an abuse signal | | `sentAt` | timestamp | No CRM data, record contents, or member PII beyond the one admin contact are sent. ## Why it's safe for existing instances - **Enterprise-only.** Gathering runs only after the `ENTERPRISE_KEY` checks, so free/community instances make no extra queries and send nothing — unchanged behavior. - **Never blocks a refresh.** Each lookup is isolated (`safeCount` / try-catch); any failure degrades to `null` and the license refresh / seat report proceeds. - **Purely additive.** `enterpriseKey` and `seatCount` are preserved; the `/validate` and `/seats` handlers ignore unknown fields, so this can ship ahead of any backend consumer. - **No schema or token-verification changes** → no migration, existing validity tokens keep validating. ## Verification - `nx test twenty-server` — full unit suite green (5829 passed), including the updated `enterprise-plan.service.spec` with a new metadata-payload test - `nx typecheck twenty-server` — pass - `oxlint` + `oxfmt --check` on changed files — clean ## Deliberately out of scope (follow-ups) - **Server-side correlation/detection** and **short-TTL + instance-bound validity tokens** live on the signing/billing side (`twenty-website`) and need a coordinated rollout (enforcing token binding now would break already-issued tokens). - **`adminContactEmail`** is PII on a contractual enterprise channel — the enterprise terms should disclose it before rollout. - The dev-key / build-provenance hardening discussed separately is **not** part of this PR. Opening as **draft** for review of the field set and the cross-repo rollout plan before wiring a consumer. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_0114DV9tctTjVo8eggBGgtKc --- _Generated by [Claude Code](https://claude.ai/code/session_0114DV9tctTjVo8eggBGgtKc)_ <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21793?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: Charles Bochet <charles@twenty.com>