[Breaking change] Prepare non-system permission flags (#20847)

# Summary

Replaces the enum-keyed `permissionFlags: PermissionFlag[]` on roles
with `permissionFlagUniversalIdentifiers: string[]`

This unlocks mixing system flags (`SystemPermissionFlag.*`) with
app-defined flags in a role config.

This is a breaking change. Existing app source must switch to the new
field.

# Breaking changes

- `RoleManifest.permissionFlags` removed. Use
`RoleManifest.permissionFlagUniversalIdentifiers: string[]`.
- `RoleConfig.permissionFlags` removed (was `PermissionFlagType[]`). Use
`RoleConfig.permissionFlagUniversalIdentifiers: string[]`.
- `PermissionFlagManifest` type removed from
`twenty-shared/application`.
- `PermissionFlag` re-export removed from `twenty-sdk/define`.
`SystemPermissionFlag` is re-exported in its place.
- Retargeting a permission flag between roles is now classified as
delete + create instead of update

 ### Not in this PR
- definePermissionFlag SDK function and top-level
Manifest.permissionFlags catalog (apps defining their own custom flags).
Until those land, permissionFlagUniversalIdentifiers only accepts
SystemPermissionFlag.* UUIDs; arbitrary UUIDs fail validation.
This commit is contained in:
Weiko
2026-05-22 23:22:28 +02:00
committed by GitHub
parent eda41b4eba
commit 3bda05ea57
18 changed files with 81 additions and 80 deletions
@@ -330,7 +330,7 @@ export const EXPECTED_MANIFEST: Manifest = {
canBeAssignedToApiKeys: false,
fieldPermissions: [],
objectPermissions: [],
permissionFlags: [],
permissionFlagUniversalIdentifiers: [],
},
],
};
@@ -1,6 +1,6 @@
import { FieldType } from '@/sdk/define';
import type { Manifest } from 'twenty-shared/application';
import { PermissionFlagType } from 'twenty-shared/constants';
import { SystemPermissionFlag } from 'twenty-shared/constants';
import {
FieldMetadataType,
NavigationMenuItemType,
@@ -1385,7 +1385,7 @@ export const EXPECTED_MANIFEST: Manifest = {
universalIdentifier: 'c0c1c2c3-c4c5-4000-8000-000000000001',
fieldPermissions: [],
objectPermissions: [],
permissionFlags: [],
permissionFlagUniversalIdentifiers: [],
},
{
canBeAssignedToAgents: false,
@@ -1417,12 +1417,7 @@ export const EXPECTED_MANIFEST: Manifest = {
objectUniversalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
},
],
permissionFlags: [
{
universalIdentifier: '01d7865a-7700-5d49-b2aa-62623c2cbac7',
flag: PermissionFlagType.APPLICATIONS,
},
],
permissionFlagUniversalIdentifiers: [SystemPermissionFlag.APPLICATIONS],
universalIdentifier: 'b648f87b-1d26-4961-b974-0908fd991061',
},
],
@@ -13,10 +13,10 @@ exports[`stub-twenty-sdk-define plugin > matches the recorded export partition 1
"ObjectRecordGroupByDateGranularity",
"OnDeleteAction",
"PageLayoutTabLayoutMode",
"PermissionFlag",
"RelationType",
"STANDARD_OBJECT",
"STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS",
"SystemPermissionFlag",
"ViewCalendarLayout",
"ViewFilterGroupLogicalOperator",
"ViewFilterOperand",
@@ -28,14 +28,7 @@ export const fromRoleConfigToRoleManifest = (
),
}),
),
permissionFlags: (roleConfig.permissionFlags ?? []).map(
(permissionFlag) => ({
universalIdentifier: uuidv5(
`${roleConfig.universalIdentifier}:${permissionFlag}`,
ROLE_UNIVERSAL_IDENTIFIER_NAMESPACE,
),
flag: permissionFlag,
}),
),
permissionFlagUniversalIdentifiers:
roleConfig.permissionFlagUniversalIdentifiers ?? [],
};
};