---
title: 역할 및 권한
description: 앱의 로직 함수와 프런트 컴포넌트가 어떤 객체와 필드를 읽고 쓸 수 있는지 선언합니다.
icon: shield-halved
---

\*\*역할(role)\*\*은 권한 집합입니다. 즉, 앱이 어떤 객체를 읽거나 쓸 수 있는지, 어떤 필드를 볼 수 있는지, 그리고 어떤 플랫폼 수준 기능을 사용할 수 있는지를 정의합니다. 모든 앱의 로직 함수와 프런트 컴포넌트는 `defineApplicationRole()`로 표시된 역할의 권한을 상속받습니다(아래 [기본 함수 역할](#the-default-function-role)을 참조하세요).

```ts src/roles/restricted-company-role.ts
import {
  defineRole,
  STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
  SystemPermissionFlag,
} from 'twenty-sdk/define';

export default defineRole({
  universalIdentifier: '2c80f640-2083-4803-bb49-003e38279de6',
  label: 'My new role',
  description: 'A role that can be used in your workspace',
  canReadAllObjectRecords: false,
  canUpdateAllObjectRecords: false,
  canSoftDeleteAllObjectRecords: false,
  canDestroyAllObjectRecords: false,
  canUpdateAllSettings: false,
  canBeAssignedToAgents: false,
  canBeAssignedToUsers: false,
  canBeAssignedToApiKeys: false,
  objectPermissions: [
    {
      objectUniversalIdentifier:
        STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
      canReadObjectRecords: true,
      canUpdateObjectRecords: true,
      canSoftDeleteObjectRecords: false,
      canDestroyObjectRecords: false,
    },
  ],
  fieldPermissions: [
    {
      objectUniversalIdentifier:
        STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
      fieldUniversalIdentifier:
        STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.name
          .universalIdentifier,
      canReadFieldValue: false,
      canUpdateFieldValue: false,
    },
  ],
  permissionFlagUniversalIdentifiers: [SystemPermissionFlag.APPLICATIONS],
});
```

## 행 수준 보안

오브젝트 및 필드 권한은 역할이 *어떤 오브젝트와 필드* 를 다룰 수 있는지를 결정합니다. **행 수준
권한 프레디킷** 은 더 나아가 역할이 *어떤 레코드* 를 보고 작업할 수 있는지를 결정합니다. 예를 들어, 각 외부 사용자가 자신의 레코드만 볼 수 있는 셀프 서비스 역할 같은 경우입니다.

역할에 `rowLevelPermissionPredicates` 로 프레디킷을 선언합니다. 매니페스트의 나머지와 마찬가지로,
각 프레디킷은 자체 `universalIdentifier` 를 가지고, 오브젝트와 필드를 각각의
`universalIdentifier`, `operand`, 그리고 (선택적으로) 쿼리 시점에 값이 주입되는 workspaceMember 필드를 통해 참조합니다. 이렇게 하면 "레코드의 owner relation **is** 현재 workspace member이다"를 표현할 수 있습니다:

```ts src/roles/partner-role.ts
import {
  defineRole,
  RowLevelPermissionPredicateOperand,
  STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';

import { ACCOUNT_OWNER_FIELD_UNIVERSAL_IDENTIFIER } from '../fields/account-owner.field';

export default defineRole({
  universalIdentifier: 'c3c1dc2e-1a08-4de5-abb7-2139b3d99343',
  label: 'Partner',
  description: 'External partner — sees only its own records',
  canBeAssignedToUsers: true,
  objectPermissions: [
    {
      objectUniversalIdentifier:
        STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
      canReadObjectRecords: true,
      canUpdateObjectRecords: true,
    },
  ],
  rowLevelPermissionPredicates: [
    {
      universalIdentifier: 'd0f0c1a2-3b4c-4d5e-8f60-111111111111',
      objectUniversalIdentifier:
        STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
      fieldUniversalIdentifier: ACCOUNT_OWNER_FIELD_UNIVERSAL_IDENTIFIER,
      operand: RowLevelPermissionPredicateOperand.IS,
      workspaceMemberFieldUniversalIdentifier:
        STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workspaceMember.fields.id
          .universalIdentifier,
    },
  ],
});
```

프레디킷은 매니페스트에 함께 포함되어 배포되므로, 모든 설치와 업그레이드 시 역할과 함께 생성·업데이트·제거됩니다. 동기화를 유지하기 위한 별도의 설치 후 단계는 필요하지 않습니다.

### 프레디킷을 그룹과 결합하기

기본적으로 역할의 프레디킷은 `AND`로 결합됩니다. 일부를 `OR`로 결합하거나(또는 논리를 중첩하려면) `rowLevelPermissionPredicateGroups` 항목을 선언하고 각 프레디킷이 `predicateGroupUniversalIdentifier`를 통해 해당 그룹을 가리키도록 설정합니다. 이 역할은 파트너가 자신이 **소유한** 또는 **담당자**인 기회(Opportunity)를 볼 수 있도록 허용합니다:

```ts src/roles/partner-opportunities-role.ts
import {
  defineRole,
  RowLevelPermissionPredicateGroupLogicalOperator,
  RowLevelPermissionPredicateOperand,
  STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';

const OPPORTUNITY = STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.opportunity;
const CURRENT_MEMBER =
  STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workspaceMember.fields.id
    .universalIdentifier;

export default defineRole({
  universalIdentifier: 'b2a1c0d9-8e7f-4a6b-9c5d-222222222222',
  label: 'Partner (opportunities)',
  canBeAssignedToUsers: true,
  objectPermissions: [
    {
      objectUniversalIdentifier: OPPORTUNITY.universalIdentifier,
      canReadObjectRecords: true,
    },
  ],
  rowLevelPermissionPredicateGroups: [
    {
      universalIdentifier: 'c3b2a1d0-9f8e-4b7a-8d6c-333333333333',
      objectUniversalIdentifier: OPPORTUNITY.universalIdentifier,
      logicalOperator: RowLevelPermissionPredicateGroupLogicalOperator.OR,
    },
  ],
  rowLevelPermissionPredicates: [
    {
      universalIdentifier: 'd4c3b2a1-0e9f-4c8b-9e7d-444444444444',
      objectUniversalIdentifier: OPPORTUNITY.universalIdentifier,
      fieldUniversalIdentifier: OPPORTUNITY.fields.owner.universalIdentifier,
      operand: RowLevelPermissionPredicateOperand.IS,
      workspaceMemberFieldUniversalIdentifier: CURRENT_MEMBER,
      predicateGroupUniversalIdentifier: 'c3b2a1d0-9f8e-4b7a-8d6c-333333333333',
    },
    {
      universalIdentifier: 'e5d4c3b2-1f0e-4d9c-8f8e-555555555555',
      objectUniversalIdentifier: OPPORTUNITY.universalIdentifier,
      fieldUniversalIdentifier:
        OPPORTUNITY.fields.pointOfContact.universalIdentifier,
      operand: RowLevelPermissionPredicateOperand.IS,
      workspaceMemberFieldUniversalIdentifier: CURRENT_MEMBER,
      predicateGroupUniversalIdentifier: 'c3b2a1d0-9f8e-4b7a-8d6c-333333333333',
    },
  ],
});
```

노트:

* 모든 프레디킷과 그룹에 안정적인 `universalIdentifier`(임의의 uuid)를 부여하세요. 이는 업그레이드 전반에 걸쳐 엔티티의 키로 사용되며, 프레디킷은 이를 통해 그룹을 참조합니다.
* 프레디킷은 앱에서 소유한 오브젝트와 필드뿐만 아니라 Twenty의 표준 오브젝트가 소유한 오브젝트와 필드를 참조할 수 있습니다.
* 행 수준 보안은 이를 포함한 플랜의 워크스페이스에 대해 적용됩니다. 다른 플랜에서도 프레디킷은 계속 동기화되지만, 적용되지는 않습니다.

## 기본 함수 역할

새 앱을 스캐폴딩하면, CLI가 `defineApplicationRole()`로 선언된 기본 역할 파일을 생성합니다:

```ts src/roles/default-role.ts
import { defineApplicationRole } from 'twenty-sdk/define';

export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
  'b648f87b-1d26-4961-b974-0908fd991061';

export default defineApplicationRole({
  universalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
  label: 'Default function role',
  description: 'Default role for function Twenty client',
  canReadAllObjectRecords: true,
  canUpdateAllObjectRecords: false,
  canSoftDeleteAllObjectRecords: false,
  canDestroyAllObjectRecords: false,
  canUpdateAllSettings: false,
  canBeAssignedToAgents: false,
  canBeAssignedToUsers: false,
  canBeAssignedToApiKeys: false,
  objectPermissions: [],
  fieldPermissions: [],
  permissionFlagUniversalIdentifiers: [],
});
```

`defineApplicationRole()`는 설치 시 애플리케이션의 기본 역할로 사용할 역할을 표시하는, `defineRole()`에 대한 간단한 래퍼입니다. 검증 방식은 `defineRole`과 동일하지만, 빌드 파이프라인이 애플리케이션 매니페스트의 `defaultRoleUniversalIdentifier`에 해당 역할의 `universalIdentifier`를 자동으로 연결하므로, [`defineApplication`](/l/ko/developers/extend/apps/config/application)에서 직접 참조할 필요가 없습니다.

노트:

* 앱당 정확히 **하나의** `defineApplicationRole(...)`만 허용되며, 둘 이상 발견되면 매니페스트 빌드가 실패합니다.
* 앱에서 제공하는 **추가** 역할에는 `defineApplicationRole()`가 아니라 `defineRole()`을 사용하세요.
* 호환성을 위해 `defineApplication()`에서 `defaultRoleUniversalIdentifier`를 명시적으로 설정하는 방식도 여전히 지원되지만, 이제는 `defineApplicationRole()` 방식이 권장되며 이전 방식은 더 이상 권장되지 않습니다.

## 모범 사례

* 스캐폴딩된 역할에서 시작한 다음 점진적으로 권한을 제한하세요. 기본 설정은 광범위한 읽기 액세스를 부여하는데, 이는 프로덕션 환경에서 원하는 경우가 거의 없습니다.
* `objectPermissions`와 `fieldPermissions`를 함수에 실제로 필요한 정확한 객체와 필드로 교체하세요.
* `permissionFlagUniversalIdentifiers`는 플랫폼 수준 기능에 대한 액세스를 제어합니다. 최소한으로 유지하세요.
* 동작 예제를 참조하세요: [`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
