41 lines
1.7 KiB
TypeScript
41 lines
1.7 KiB
TypeScript
/**
|
|
* 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);
|
|
}
|