Skip to main content
The twenty-sdk package provides defineEntity functions to declare your app’s data model. Sie müssen export default defineEntity({...}) verwenden, damit das SDK Ihre Entitäten erkennt. Diese Funktionen validieren Ihre Konfiguration zur Build-Zeit und bieten IDE-Autovervollständigung sowie Typsicherheit.
Die Dateiorganisation liegt bei Ihnen. Die Entitätserkennung ist AST-basiert — das SDK findet Aufrufe von export default defineEntity(...), unabhängig davon, wo sich die Datei befindet. Das Gruppieren von Dateien nach Typ (z. B. logic-functions/, roles/) ist lediglich eine Konvention, keine Voraussetzung.
Rollen kapseln Berechtigungen für die Objekte und Aktionen Ihres Workspaces.
restricted-company-role.ts
Jede App muss genau einen Aufruf von defineApplication haben, der Folgendes beschreibt:
  • Identität: Bezeichner, Anzeigename und Beschreibung.
  • Berechtigungen: welche Rolle ihre Funktionen und Frontend-Komponenten verwenden.
  • (Optional) Variablen: Schlüssel–Wert-Paare, die Ihren Funktionen als Umgebungsvariablen zur Verfügung gestellt werden.
  • (Optional) Pre-/Post-Installationsfunktionen: Logikfunktionen, die vor oder nach der Installation ausgeführt werden.
src/application-config.ts
Notizen:
  • universalIdentifier-Felder sind deterministische IDs, die Ihnen gehören. Erzeugen Sie sie einmal und halten Sie sie über Synchronisierungen hinweg stabil.
  • applicationVariables werden zu Umgebungsvariablen für Ihre Funktionen und Frontend-Komponenten (z. B. ist DEFAULT_RECIPIENT_NAME als process.env.DEFAULT_RECIPIENT_NAME verfügbar).
  • defaultRoleUniversalIdentifier muss auf eine mit defineRole() definierte Rolle verweisen (siehe oben).
  • Pre- und Post-Installationsfunktionen werden während des Manifest-Builds automatisch erkannt — Sie müssen sie in defineApplication() nicht referenzieren.

Marktplatz-Metadaten

Wenn Sie planen, Ihre App zu veröffentlichen, steuern diese optionalen Felder, wie Ihre App im Marktplatz erscheint:

Rollen und Berechtigungen

Das Feld defaultRoleUniversalIdentifier in application-config.ts legt die Standardrolle fest, die von den Logikfunktionen und Frontend-Komponenten Ihrer App verwendet wird. Details finden Sie oben unter defineRole.
  • Das zur Laufzeit als TWENTY_APP_ACCESS_TOKEN injizierte Token wird aus dieser Rolle abgeleitet.
  • Der typisierte Client ist auf die dieser Rolle gewährten Berechtigungen beschränkt.
  • Befolgen Sie das Least-Privilege-Prinzip: Erstellen Sie eine dedizierte Rolle nur mit den Berechtigungen, die Ihre Funktionen benötigen.
Standard-Funktionsrolle
Wenn Sie eine neue App erzeugen, erstellt die CLI eine Standard-Rolldatei:
src/roles/default-role.ts
Der universalIdentifier dieser Rolle wird in application-config.ts als defaultRoleUniversalIdentifier referenziert:
  • *.role.ts definiert, was die Rolle darf.
  • application-config.ts verweist auf diese Rolle, sodass Ihre Funktionen deren Berechtigungen erben.
Notizen:
  • Beginnen Sie mit der vorab erstellten Rolle und schränken Sie sie schrittweise gemäß dem Least-Privilege-Prinzip ein.
  • Ersetzen Sie objectPermissions und fieldPermissions durch die Objekte und Felder, die Ihre Funktionen tatsächlich benötigen.
  • permissionFlags steuern den Zugriff auf Funktionen auf Plattformebene. Halten Sie sie minimal.
  • Ein funktionierendes Beispiel finden Sie unter: hello-world/src/roles/function-role.ts.
Benutzerdefinierte Objekte beschreiben sowohl Schema als auch Verhalten für Datensätze in Ihrem Workspace. Verwenden Sie defineObject(), um Objekte mit eingebauter Validierung zu definieren:
postCard.object.ts
Hauptpunkte:
  • Verwenden Sie defineObject() für eingebaute Validierung und bessere IDE-Unterstützung.
  • Der universalIdentifier muss eindeutig und über Deployments hinweg stabil sein.
  • Jedes Feld benötigt name, type, label und einen eigenen stabilen universalIdentifier.
  • Das Array fields ist optional — Sie können Objekte ohne benutzerdefinierte Felder definieren.
  • Sie können mit yarn twenty add neue Objekte erzeugen; der Assistent führt Sie durch Benennung, Felder und Beziehungen.
Basisfelder werden automatisch erstellt. Wenn Sie ein benutzerdefiniertes Objekt definieren, fügt Twenty automatisch Standardfelder hinzu wie id, name, createdAt, updatedAt, createdBy, updatedBy und deletedAt. Sie müssen diese nicht in Ihrem fields-Array definieren — fügen Sie nur Ihre benutzerdefinierten Felder hinzu. Sie können Standardfelder überschreiben, indem Sie in Ihrem fields-Array ein Feld mit demselben Namen definieren, dies wird jedoch nicht empfohlen.
Verwenden Sie defineField(), um Objekten, die Ihnen nicht gehören — etwa Standardobjekten von Twenty (Person, Company usw.) — Felder hinzuzufügen oder Objekten aus anderen Apps. Im Gegensatz zu Inline-Feldern in defineObject() benötigen eigenständige Felder einen objectUniversalIdentifier, um anzugeben, welches Objekt sie erweitern:
src/fields/company-loyalty-tier.field.ts
Hauptpunkte:
  • Der objectUniversalIdentifier identifiziert das Zielobjekt. Für Standardobjekte verwenden Sie STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS, die aus twenty-sdk exportiert werden.
  • Wenn Sie Felder inline in defineObject() definieren, benötigen Sie objectUniversalIdentifier nicht — er wird vom übergeordneten Objekt geerbt.
  • defineField() ist die einzige Möglichkeit, Felder zu Objekten hinzuzufügen, die Sie nicht mit defineObject() erstellt haben.
Relationen verbinden Objekte miteinander. In Twenty sind Relationen stets bidirektional — Sie definieren beide Seiten, und jede Seite referenziert die andere.Es gibt zwei Relationstypen:

Wie Relationen funktionieren

Jede Relation erfordert zwei Felder, die sich gegenseitig referenzieren:
  1. Die MANY_TO_ONE-Seite — befindet sich auf dem Objekt, das den Fremdschlüssel hält
  2. Die ONE_TO_MANY-Seite — befindet sich auf dem Objekt, dem die Sammlung gehört
Beide Felder verwenden FieldType.RELATION und verweisen über relationTargetFieldMetadataUniversalIdentifier gegenseitig aufeinander.

Beispiel: Postkarte hat viele Empfänger

Angenommen, eine PostCard kann an viele PostCardRecipient-Datensätze gesendet werden. Jeder Empfänger gehört genau zu einer Postkarte.Schritt 1: Definieren Sie die ONE_TO_MANY-Seite auf PostCard (die “eine” Seite):
src/fields/post-card-recipients-on-post-card.field.ts
Schritt 2: Definieren Sie die MANY_TO_ONE-Seite auf PostCardRecipient (die “viele” Seite — hält den Fremdschlüssel):
src/fields/post-card-on-post-card-recipient.field.ts
Zyklische Importe: Beide Relationsfelder referenzieren gegenseitig den universalIdentifier des jeweils anderen. Um Probleme mit zyklischen Importen zu vermeiden, exportieren Sie Ihre Feld-IDs als benannte Konstanten aus jeder Datei und importieren Sie sie in der jeweils anderen Datei. Das Build-System löst dies zur Kompilierzeit auf.

Relationen zu Standardobjekten

Um eine Relation mit einem integrierten Twenty-Objekt (Person, Company usw.) zu erstellen, verwenden Sie STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS:
src/fields/person-on-self-hosting-user.field.ts

Eigenschaften von Relationsfeldern

Inline-Relationsfelder in defineObject

Sie können Relationsfelder auch direkt innerhalb von defineObject() definieren. In diesem Fall lassen Sie objectUniversalIdentifier weg — er wird vom übergeordneten Objekt geerbt:

Entitäten mit yarn twenty add erstellen

Anstatt Entitätsdateien manuell zu erstellen, können Sie den interaktiven Scaffolder verwenden:
Dies fordert Sie auf, einen Entitätstyp auszuwählen, und führt Sie durch die erforderlichen Felder. Er erzeugt eine einsatzbereite Datei mit einem stabilen universalIdentifier und dem korrekten defineEntity()-Aufruf. Sie können den Entitätstyp auch direkt übergeben, um die erste Eingabeaufforderung zu überspringen:

Verfügbare Entitätstypen

Was der Scaffolder generiert

Jeder Entitätstyp hat seine eigene Vorlage. Zum Beispiel fragt yarn twenty add object nach:
  1. Name (Singular) — z. B. invoice
  2. Name (Plural) — z. B. invoices
  3. Label (Singular) — automatisch aus dem Namen befüllt (z. B. Invoice)
  4. Label (Plural) — automatisch befüllt (z. B. Invoices)
  5. Ansicht und Navigationseintrag erstellen? — wenn Sie mit Ja antworten, erzeugt der Scaffolder außerdem eine passende Ansicht und einen Sidebar-Link für das neue Objekt.
Andere Entitätstypen haben einfachere Eingabeaufforderungen — die meisten fragen nur nach einem Namen. Der Entitätstyp field ist detaillierter: Er fragt nach Feldname, Label, Typ (aus einer Liste aller verfügbaren Feldtypen wie TEXT, NUMBER, SELECT, RELATION usw.) sowie dem universalIdentifier des Zielobjekts.

Benutzerdefinierter Ausgabepfad

Verwenden Sie den Schalter --path, um die generierte Datei an einem benutzerdefinierten Ort abzulegen: