twenty-sdk package provides defineEntity functions to declare your app’s data model. Вы должны использовать export default defineEntity({...}), чтобы SDK обнаруживал ваши сущности. Эти функции проверяют вашу конфигурацию на этапе сборки и обеспечивают автодополнение в IDE и безопасность типов.
Организация файлов — на ваше усмотрение.
Обнаружение сущностей основано на AST — SDK находит вызовы
export default defineEntity(...) независимо от расположения файла. Группировка файлов по типу (например, logic-functions/, roles/) — это лишь соглашение, а не требование.defineRole
Настраивает права роли и доступ к объектам
defineRole
Настраивает права роли и доступ к объектам
Роли инкапсулируют права на объекты и действия вашего рабочего пространства.
restricted-company-role.ts
defineApplication
Настройка метаданных приложения (обязательно, по одному на приложение)
defineApplication
Настройка метаданных приложения (обязательно, по одному на приложение)
В каждом приложении должен быть ровно один вызов Заметки:
Значение
defineApplication, который описывает:- Идентификация: идентификаторы, отображаемое имя и описание.
- Разрешения: какую роль используют его функции и фронтенд-компоненты.
- (Необязательно) Переменные: пары ключ–значение, доступные вашим функциям как переменные окружения.
- (Необязательно) Предустановочные / постустановочные функции: логические функции, которые запускаются до или после установки.
src/application-config.ts
- Поля
universalIdentifier— это детерминированные идентификаторы, которые принадлежат вам. Сгенерируйте их один раз и сохраняйте неизменными между синхронизациями. applicationVariablesстановятся переменными окружения для ваших функций и фронтенд-компонентов (например,DEFAULT_RECIPIENT_NAMEдоступна какprocess.env.DEFAULT_RECIPIENT_NAME).defaultRoleUniversalIdentifierдолжен ссылаться на роль, определённую с помощьюdefineRole()(см. выше).- Предустановочные и постустановочные функции обнаруживаются автоматически во время сборки манифеста — вам не нужно указывать их в
defineApplication().
Метаданные маркетплейса
Если вы планируете опубликовать приложение, эти необязательные поля определяют, как оно отображается в маркетплейсе:| Поле | Описание |
|---|---|
author | Имя автора или название компании |
category | Категория приложения для фильтрации в маркетплейсе |
logoUrl | Путь к логотипу вашего приложения (например, public/logo.png) |
screenshots | Массив путей к скриншотам (например, public/screenshot-1.png) |
aboutDescription | Расширенное описание в Markdown для вкладки “About”. Если опущено, маркетплейс использует README.md пакета из npm |
websiteUrl | Ссылка на ваш сайт |
termsUrl | Ссылка на условия предоставления услуг |
emailSupport | Адрес электронной почты поддержки |
issueReportUrl | Ссылка на систему отслеживания проблем |
Роли и разрешения
ПолеdefaultRoleUniversalIdentifier в application-config.ts обозначает роль по умолчанию, используемую логическими функциями и фронтенд-компонентами вашего приложения. Подробности см. в defineRole выше.- Токен времени выполнения, подставляемый как
TWENTY_APP_ACCESS_TOKEN, формируется из этой роли. - Типизированный клиент ограничен правами, предоставленными этой ролью.
- Следуйте принципу наименьших привилегий: создайте отдельную роль только с теми правами, которые нужны вашим функциям.
Роль функции по умолчанию
Когда вы генерируете новое приложение, CLI создаёт файл роли по умолчанию:src/roles/default-role.ts
universalIdentifier этой роли указывается в application-config.ts как defaultRoleUniversalIdentifier:- *.role.ts определяет, что может делать роль.
- application-config.ts указывает на эту роль, чтобы ваши функции наследовали её права.
- Начните со сгенерированной роли, затем постепенно ограничивайте её, следуя принципу наименьших привилегий.
- Замените
objectPermissionsиfieldPermissionsна объекты и поля, которые действительно нужны вашим функциям. permissionFlagsуправляют доступом к возможностям на уровне платформы. Сведите их к минимуму.- См. рабочий пример:
hello-world/src/roles/function-role.ts.
defineObject
Определяет пользовательские объекты с полями
defineObject
Определяет пользовательские объекты с полями
Пользовательские объекты описывают как схему, так и поведение записей в вашем рабочем пространстве. Используйте Основные моменты:
defineObject() для определения объектов со встроенной валидацией:postCard.object.ts
- Используйте
defineObject()для встроенной валидации и лучшей поддержки в IDE. universalIdentifierдолжен быть уникальным и стабильным между развёртываниями.- Каждому полю требуются
name,type,labelи собственный стабильныйuniversalIdentifier. - Массив
fieldsнеобязателен — вы можете определять объекты без пользовательских полей. - Вы можете сгенерировать новые объекты с помощью
yarn twenty add, который проведёт вас через выбор именования, полей и связей.
Базовые поля создаются автоматически. Когда вы определяете пользовательский объект, Twenty автоматически добавляет стандартные поля,
такие как
id, name, createdAt, updatedAt, createdBy, updatedBy и deletedAt.
Вам не нужно определять их в массиве fields — добавляйте только свои пользовательские поля.
Вы можете переопределить поля по умолчанию, определив поле с тем же именем в массиве fields,
но это не рекомендуется.defineField — Стандартные поля
Расширение существующих объектов дополнительными полями
defineField — Стандартные поля
Расширение существующих объектов дополнительными полями
Используйте Основные моменты:
defineField() для добавления полей к объектам, которые вам не принадлежат — например, к стандартным объектам Twenty (Person, Company и т. д.). или к объектам из других приложений. В отличие от встроенных полей в defineObject(), отдельные поля требуют objectUniversalIdentifier, чтобы указать, какой объект они расширяют:src/fields/company-loyalty-tier.field.ts
objectUniversalIdentifierопределяет целевой объект. Для стандартных объектов используйтеSTANDARD_OBJECT_UNIVERSAL_IDENTIFIERS, экспортируемые изtwenty-sdk.- При определении полей непосредственно в
defineObject()вам не нуженobjectUniversalIdentifier— он наследуется от родительского объекта. defineField()— единственный способ добавить поля к объектам, которые вы не создавали с помощьюdefineObject().
defineField — Поля связей
Связывайте объекты двунаправленными связями
defineField — Поля связей
Связывайте объекты двунаправленными связями
Отношения связывают объекты между собой. В Twenty отношения всегда двунаправленные — вы определяете обе стороны, и каждая сторона ссылается на другую.Существуют два типа отношений:
Шаг 2: Определите сторону MANY_TO_ONE на PostCardRecipient (сторона “many” — содержит внешний ключ):
| Тип отношения | Описание | Есть внешний ключ? |
|---|---|---|
MANY_TO_ONE | Многие записи этого объекта указывают на одну запись целевого объекта | Да (joinColumnName) |
ONE_TO_MANY | Одна запись этого объекта имеет много записей целевого объекта | Нет (обратная сторона) |
Как работают отношения
Каждое отношение требует двух полей, которые ссылаются друг на друга:- Сторона MANY_TO_ONE — находится в объекте, который содержит внешний ключ
- Сторона ONE_TO_MANY — находится в объекте, которому принадлежит коллекция
FieldType.RELATION и ссылаются друг на друга через relationTargetFieldMetadataUniversalIdentifier.Пример: Почтовая открытка имеет много получателей
Предположим,PostCard может быть отправлен множству записей PostCardRecipient. Каждый получатель относится ровно к одной открытке.Шаг 1: Определите сторону ONE_TO_MANY на PostCard (сторона “one”):src/fields/post-card-recipients-on-post-card.field.ts
src/fields/post-card-on-post-card-recipient.field.ts
Циклические импорты: Оба поля отношений ссылаются на
universalIdentifier друг друга. Чтобы избежать проблем с циклическими импортами, экспортируйте идентификаторы полей как именованные константы из каждого файла и импортируйте их в другом файле. Система сборки разрешает это на этапе компиляции.Связывание со стандартными объектами
Чтобы создать отношение со встроенным объектом Twenty (Person, Company и т. д.), используйтеSTANDARD_OBJECT_UNIVERSAL_IDENTIFIERS:src/fields/person-on-self-hosting-user.field.ts
Свойства поля отношения
| Свойство | Обязательно | Описание |
|---|---|---|
type | Да | Должно быть FieldType.RELATION |
relationTargetObjectMetadataUniversalIdentifier | Да | universalIdentifier целевого объекта |
relationTargetFieldMetadataUniversalIdentifier | Да | universalIdentifier соответствующего поля на целевом объекте |
universalSettings.relationType | Да | RelationType.MANY_TO_ONE или RelationType.ONE_TO_MANY |
universalSettings.onDelete | Только для MANY_TO_ONE | Что происходит при удалении связанной записи: CASCADE, SET_NULL, RESTRICT или NO_ACTION |
universalSettings.joinColumnName | Только для MANY_TO_ONE | Имя столбца базы данных для внешнего ключа (например, postCardId) |
Встроенные поля отношений в defineObject
Вы также можете определять поля отношений непосредственно внутриdefineObject(). В этом случае опустите objectUniversalIdentifier — он наследуется от родительского объекта:Создание заготовок сущностей с помощью yarn twenty add
Вместо ручного создания файлов сущностей вы можете использовать интерактивный генератор:
universalIdentifier и корректным вызовом defineEntity().
Вы также можете передать тип сущности напрямую, чтобы пропустить первый запрос:
Доступные типы сущностей
| Тип сущности | Команда | Сгенерированный файл |
|---|---|---|
| Объект | yarn twenty add object | src/objects/\<name>.ts |
| Поле | yarn twenty add field | src/fields/\<name>.ts |
| Логическая функция | yarn twenty add logicFunction | src/logic-functions/\<name>.ts |
| Компонент фронтенда | yarn twenty add frontComponent | src/front-components/\<name>.tsx |
| Роль | yarn twenty add role | src/roles/\<name>.ts |
| Навык | yarn twenty add skill | src/skills/\<name>.ts |
| Агент | yarn twenty add agent | src/agents/\<name>.ts |
| Представление | yarn twenty add view | src/views/\<name>.ts |
| Пункт меню навигации | yarn twenty add navigationMenuItem | src/navigation-menu-items/\<name>.ts |
| Макет страницы | yarn twenty add pageLayout | src/page-layouts/\<name>.ts |
Что генерирует скэффолдер
У каждого типа сущности есть свой шаблон. Например,yarn twenty add object запрашивает:
- Имя (единственное число) — например,
invoice - Имя (множественное число) — например,
invoices - Метка (единственное число) — заполняется автоматически из имени (например,
Invoice) - Метка (множественное число) — заполняется автоматически (например,
Invoices) - Создать представление и пункт навигации? — если вы ответите «да», скэффолдер также сгенерирует соответствующее представление и ссылку в боковой панели для нового объекта.
field более детализирован: он запрашивает имя поля, метку, тип (из списка всех доступных типов полей, таких как TEXT, NUMBER, SELECT, RELATION и т. д.), а также universalIdentifier целевого объекта.
Пользовательский путь вывода
Используйте флаг--path, чтобы поместить сгенерированный файл в пользовательское расположение: