/** * Personal-account helpers. * * Slice 4 establishes the convention that ZITADEL org names for personal * accounts end with the literal " (Personal)" suffix. This file * centralises the suffix and the predicate so both registration (which * sets the suffix) and onboarding (which reads it from the session) use * the same canonical form. * * Why a name suffix and not ZITADEL org metadata? * ----------------------------------------------- * 1. The suffix is visible in ZITADEL Console, admin tools, JWT claims, * etc. — useful debugging signal at zero cost. * 2. Customers cannot rename their own org (requires IAM_OWNER, which * only the SA holds), so the suffix is stable for the lifetime of * the org. * 3. No extra ZITADEL API calls at onboarding time to fetch metadata. * 4. No extra portal DB tables. * * The trade-off: an admin who manually renames a personal org via * ZITADEL Console could remove the suffix, after which onboarding * would treat that org as a company. That's a deliberate destructive * action and the worst outcome is a misnamed K8s CR; nothing breaks. */ export const PERSONAL_ORG_SUFFIX = " (Personal)"; /** * Returns true when the given ZITADEL org name marks a personal account. * * The check is exact-suffix match (after trimming). Whitespace inside * the suffix is significant — `" (personal)"` lowercase or `"(Personal)"` * without the leading space are not matches and not personal orgs. * * Pass `session.orgName` from the SessionUser at the call site. */ export function isPersonalOrgName(orgName: string | null | undefined): boolean { if (!orgName) return false; return orgName.trimEnd().endsWith(PERSONAL_ORG_SUFFIX); }