Was sind Apps?
Mit Apps können Sie Twenty-Anpassungen als Code erstellen und verwalten. Anstatt alles über die UI zu konfigurieren, definieren Sie Ihr Datenmodell und Logikfunktionen im Code — das beschleunigt Entwicklung, Wartung und den Rollout auf mehrere Workspaces. Was Sie heute tun können:- Benutzerdefinierte Objekte und Felder als Code definieren (verwaltetes Datenmodell)
- Logikfunktionen mit benutzerdefinierten Triggern erstellen
- Dieselbe App in mehreren Workspaces bereitstellen
Voraussetzungen
- Node.js 24+ und Yarn 4
- Ein Twenty-Workspace und ein API-Schlüssel (unter https://app.twenty.com/settings/api-webhooks erstellen)
Erste Schritte
Erstellen Sie mit dem offiziellen Scaffolder eine neue App, authentifizieren Sie sich und beginnen Sie mit der Entwicklung:Projektstruktur (vom Scaffolder erzeugt)
Wenn Sienpx create-twenty-app@latest my-twenty-app ausführen, erledigt der Scaffolder Folgendes:
- Kopiert eine minimale Basisanwendung nach
my-twenty-app/ - Fügt eine lokale
twenty-sdk-Abhängigkeit und die Yarn-4-Konfiguration hinzu - Erstellt Konfigurationsdateien und Skripte, die an die
twenty-CLI angebunden sind - Generiert eine Standard-Anwendungskonfiguration und eine Standard-Funktionsrolle
- package.json: Deklariert den App-Namen, die Version, Engines (Node 24+, Yarn 4) und fügt
twenty-sdksowie Skripte wieapp:dev,app:generate,entity:add,function:logs,function:execute,app:uninstallsowie Authentifizierungsbefehle hinzu, die an die lokaletwenty-CLI delegieren. - .gitignore: Ignoriert übliche Artefakte wie
node_modules,.yarn,generated/(typisierter Client),dist/,build/, Coverage-Ordner, Logdateien und.env*-Dateien. - yarn.lock, .yarnrc.yml, .yarn/: Fixieren und konfigurieren die vom Projekt verwendete Yarn-4-Toolchain.
- .nvmrc: Legt die vom Projekt erwartete Node.js-Version fest.
- eslint.config.mjs und tsconfig.json: Stellen Linting und TypeScript-Konfiguration für die TypeScript-Quellen Ihrer App bereit.
- README.md: Ein kurzes README im App-Root mit grundlegenden Anweisungen.
- public/: Ein Ordner zum Speichern öffentlicher Assets (Bilder, Schriftarten, statische Dateien), die zusammen mit Ihrer Anwendung bereitgestellt werden. Hier abgelegte Dateien werden während der Synchronisierung hochgeladen und sind zur Laufzeit zugänglich.
- src/: Der Hauptort, an dem Sie Ihre Anwendung als Code definieren
Entitätserkennung
Das SDK erkennt Entitäten, indem es Ihre TypeScript-Dateien nach Aufrufen vonexport default define<Entity>({...}) parst. Für jeden Entitätstyp gibt es eine entsprechende Hilfsfunktion, die aus twenty-sdk exportiert wird:
| Hilfsfunktion | Entitätstyp |
|---|---|
defineObject() | Benutzerdefinierte Objektdefinitionen |
defineLogicFunction() | Definitionen von Logikfunktionen |
defineFrontComponent() | Definitionen von Frontend-Komponenten |
defineRole() | Rollendefinitionen |
defineField() | Felderweiterungen für bestehende Objekte |
Dateibenennung ist flexibel. Die Entitätserkennung ist AST-basiert — das SDK durchsucht Ihre Quelldateien nach dem Muster
export default define<Entity>({...}). Sie können Ihre Dateien und Ordner nach Belieben organisieren. Die Gruppierung nach Entitätstyp (z. B. logic-functions/, roles/) ist lediglich eine Konvention zur Codeorganisation, keine Voraussetzung.yarn app:generateerstellt einengenerated/-Ordner (typisierter Twenty-Client + Workspace-Typen).yarn entity:addfügt untersrc/Entitätsdefinitionsdateien für Ihre benutzerdefinierten Objekte, Funktionen, Front-Komponenten oder Rollen hinzu.
Authentifizierung
Wenn Sieyarn auth:login zum ersten Mal ausführen, werden Sie nach Folgendem gefragt:
- API-URL (standardmäßig http://localhost:3000 oder Ihr aktuelles Workspace-Profil)
- API-Schlüssel
~/.twenty/config.json gespeichert. Sie können mehrere Profile verwalten und zwischen ihnen wechseln.
Arbeitsbereiche verwalten
auth:switch den Arbeitsbereich gewechselt haben, verwenden alle nachfolgenden Befehle standardmäßig diesen Arbeitsbereich. Sie können es weiterhin vorübergehend mit --workspace <name> überschreiben.
SDK-Ressourcen verwenden (Typen & Konfiguration)
Das twenty-sdk stellt typisierte Bausteine und Hilfsfunktionen bereit, die Sie in Ihrer App verwenden. Im Folgenden finden Sie die wichtigsten Bausteine, mit denen Sie am häufigsten arbeiten.Hilfsfunktionen
Das SDK stellt Hilfsfunktionen bereit, um die Entitäten Ihrer App zu definieren. Wie in Entitätserkennung beschrieben, müssen Sieexport default define<Entity>({...}) verwenden, damit Ihre Entitäten erkannt werden:
| Funktion | Zweck |
|---|---|
defineApplication() | Anwendungsmetadaten konfigurieren (erforderlich, eine pro App) |
defineObject() | Benutzerdefinierte Objekte mit Feldern definieren |
defineLogicFunction() | Logikfunktionen mit Handlern definieren |
defineFrontComponent() | Frontend-Komponenten für benutzerdefinierte UI definieren |
defineRole() | Rollenberechtigungen und Objektzugriff konfigurieren |
defineField() | Bestehende Objekte mit zusätzlichen Feldern erweitern |
Objekte definieren
Benutzerdefinierte Objekte beschreiben sowohl Schema als auch Verhalten für Datensätze in Ihrem Workspace. Verwenden SiedefineObject(), um Objekte mit eingebauter Validierung zu definieren:
- Verwenden Sie
defineObject()für eingebaute Validierung und bessere IDE-Unterstützung. - Der
universalIdentifiermuss eindeutig und über Deployments hinweg stabil sein. - Jedes Feld benötigt
name,type,labelund einen eigenen stabilenuniversalIdentifier. - Das Array
fieldsist optional — Sie können Objekte ohne benutzerdefinierte Felder definieren. - Sie können mit
yarn entity:addneue 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 wie
name, createdAt, updatedAt, createdBy, position und deletedAt hinzu. Sie müssen diese nicht in Ihrem fields-Array definieren — fügen Sie nur Ihre benutzerdefinierten Felder hinzu.Anwendungskonfiguration (application-config.ts)
Jede App hat eine einzelne Dateiapplication-config.ts, die Folgendes beschreibt:
- Was die App ist: Bezeichner, Anzeigename und Beschreibung.
- Wie ihre Funktionen ausgeführt werden: welche Rolle sie für Berechtigungen verwenden.
- (Optional) Variablen: Schlüssel–Wert-Paare, die Ihren Funktionen als Umgebungsvariablen zur Verfügung gestellt werden.
defineApplication(), um Ihre Anwendungskonfiguration zu definieren:
universalIdentifier-Felder sind deterministische IDs, die Sie besitzen; generieren Sie sie einmal und halten Sie sie über Synchronisierungen hinweg stabil.applicationVariableswerden zu Umgebungsvariablen für Ihre Funktionen (zum Beispiel istDEFAULT_RECIPIENT_NAMEalsprocess.env.DEFAULT_RECIPIENT_NAMEverfügbar).defaultRoleUniversalIdentifiermuss mit der Rollendatei übereinstimmen (siehe unten).
Rollen und Berechtigungen
Anwendungen können Rollen definieren, die Berechtigungen für die Objekte und Aktionen Ihres Workspaces kapseln. Das FelddefaultRoleUniversalIdentifier in application-config.ts legt die Standardrolle fest, die von den Logikfunktionen Ihrer App verwendet wird.
- Der zur Laufzeit als
TWENTY_API_KEYinjizierte API-Schlüssel wird von dieser Standard-Funktionsrolle 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, und verweisen Sie dann auf deren universellen Bezeichner.
Standard-Funktionsrolle (*.role.ts)
Wenn Sie eine neue App erzeugen, erstellt die CLI auch eine Standard-Rolldatei. Verwenden SiedefineRole(), um Rollen mit eingebauter Validierung zu definieren:
universalIdentifier dieser Rolle wird anschließend in application-config.ts als defaultRoleUniversalIdentifier referenziert. Anders ausgedrückt:
- *.role.ts definiert, was die Standard-Funktionsrolle darf.
- application-config.ts verweist auf diese Rolle, sodass Ihre Funktionen deren Berechtigungen erben.
- Beginnen Sie mit der vorab erstellten Rolle und schränken Sie sie schrittweise gemäß dem Least-Privilege-Prinzip ein.
- Ersetzen Sie
objectPermissionsundfieldPermissionsdurch die Objekte/Felder, die Ihre Funktionen benötigen. permissionFlagssteuern den Zugriff auf Funktionen auf Plattformebene. Halten Sie sie minimal; fügen Sie nur hinzu, was Sie benötigen.- Ein funktionierendes Beispiel finden Sie in der Hello-World-App:
packages/twenty-apps/hello-world/src/roles/function-role.ts.
Konfiguration von Logikfunktionen und Einstiegspunkt
Jede Funktionsdatei verwendetdefineLogicFunction(), um eine Konfiguration mit einem Handler und optionalen Triggern zu exportieren.
- route: Stellt Ihre Funktion unter einem HTTP-Pfad und einer Methode unter dem Endpunkt
/s/bereit:
z. B.path: '/post-card/create',-> Aufruf unter<APP_URL>/s/post-card/create
- cron: Führt Ihre Funktion nach Zeitplan mithilfe eines CRON-Ausdrucks aus.
- databaseEvent: Wird bei Lebenszyklusereignissen von Workspace-Objekten ausgeführt. Wenn die Ereignisoperation
updatedist, können bestimmte zu überwachende Felder im ArrayupdatedFieldsangegeben werden. Wenn das Array undefiniert oder leer ist, löst jede Aktualisierung die Funktion aus.
z. B. person.updated
Notizen:
- Das Array
triggersist optional. Funktionen ohne Trigger können als von anderen Funktionen aufgerufene Utility-Funktionen verwendet werden. - Sie können mehrere Trigger-Typen in einer Funktion kombinieren.
Routen-Trigger-Payload
Wenn ein Routen-Trigger Ihre Logikfunktion aufruft, erhält sie einRoutePayload-Objekt, das dem AWS HTTP API v2-Format entspricht. Importieren Sie den Typ aus twenty-sdk:
RoutePayload hat die folgende Struktur:
| Eigenschaft | Typ | Beschreibung |
|---|---|---|
headers | Record<string, string | undefined> | HTTP-Header (nur die in forwardedRequestHeaders aufgelisteten) |
queryStringParameters | Record<string, string | undefined> | Query-String-Parameter (mehrere Werte mit Kommas verbunden) |
pathParameters | Record<string, string | undefined> | Aus dem Routenmuster extrahierte Pfadparameter (z. B. /users/:id → { id: '123' }) |
inhalt | object | null | Geparster Request-Body (JSON) |
isBase64Encoded | boolesch | Gibt an, ob der Body Base64-codiert ist |
requestContext.http.method | string | HTTP-Methode (GET, POST, PUT, PATCH, DELETE) |
requestContext.http.path | string | Rohpfad der Anfrage |
Weiterleiten von HTTP-Headern
Standardmäßig werden HTTP-Header von eingehenden Anfragen aus Sicherheitsgründen nicht an Ihre Logikfunktion weitergegeben. Um auf bestimmte Header zuzugreifen, listen Sie diese explizit im ArrayforwardedRequestHeaders auf:
Header-Namen werden in Kleinbuchstaben normalisiert. Greifen Sie mit Schlüsseln in Kleinbuchstaben darauf zu (zum Beispiel
event.headers['content-type']).- Generiert: Führen Sie
yarn entity:addaus und wählen Sie die Option zum Hinzufügen einer neuen Logikfunktion. Dadurch wird eine Starterdatei mit Handler und Konfiguration erzeugt. - Manuell: Erstellen Sie eine neue
*.logic-function.ts-Datei und verwenden SiedefineLogicFunction()nach demselben Muster.
Frontend-Komponenten
Frontend-Komponenten ermöglichen es Ihnen, benutzerdefinierte React-Komponenten zu erstellen, die innerhalb der Twenty-UI gerendert werden. Verwenden SiedefineFrontComponent(), um Komponenten mit eingebauter Validierung zu definieren:
- Frontend-Komponenten sind React-Komponenten, die in isolierten Kontexten innerhalb von Twenty gerendert werden.
- Verwenden Sie die Dateiendung
*.front-component.tsxfür die automatische Erkennung. - Das Feld
componentverweist auf Ihre React-Komponente. - Komponenten werden während
yarn app:devautomatisch gebaut und synchronisiert.
- Generiert: Führen Sie
yarn entity:addaus und wählen Sie die Option zum Hinzufügen einer neuen Frontend-Komponente. - Manuell: Erstellen Sie eine neue
*.front-component.tsx-Datei und verwenden SiedefineFrontComponent().
Generierter typisierter Client
Führen Sie yarn app:generate aus, um einen lokalen typisierten Client in generated/ basierend auf Ihrem Workspace-Schema zu erstellen. Verwenden Sie ihn in Ihren Funktionen:yarn app:generate erneut generiert. Führen Sie ihn nach Änderungen an Ihren Objekten oder beim Onboarding in einen neuen Workspace erneut aus.
Laufzeit-Anmeldedaten in Logikfunktionen
Wenn Ihre Funktion auf Twenty läuft, injiziert die Plattform vor der Ausführung Ihres Codes Anmeldedaten als Umgebungsvariablen:TWENTY_API_URL: Basis-URL der Twenty-API, auf die Ihre App abzielt.TWENTY_API_KEY: Kurzlebiger Schlüssel, der auf die Standard-Funktionsrolle Ihrer Anwendung begrenzt ist.
- Sie müssen dem generierten Client weder URL noch API-Schlüssel übergeben. Er liest
TWENTY_API_URLundTWENTY_API_KEYzur Laufzeit aus process.env. - Die Berechtigungen des API-Schlüssels werden durch die Rolle bestimmt, auf die in Ihrer
application-config.tsüberdefaultRoleUniversalIdentifierverwiesen wird. Dies ist die Standardrolle, die von den Logikfunktionen Ihrer Anwendung verwendet wird. - Anwendungen können Rollen definieren, um das Least-Privilege-Prinzip einzuhalten. Gewähren Sie nur die Berechtigungen, die Ihre Funktionen benötigen, und verweisen Sie dann mit
defaultRoleUniversalIdentifierauf den universellen Bezeichner dieser Rolle.
Hello-World-Beispiel
Ein minimales End-to-End-Beispiel, das Objekte, Logikfunktionen, Frontend-Komponenten und mehrere Trigger demonstriert, finden Sie hier:Manuelle Einrichtung (ohne Scaffolder)
Wir empfehlen zwarcreate-twenty-app für das beste Einstiegserlebnis, Sie können ein Projekt aber auch manuell einrichten. Installieren Sie die CLI nicht global. Fügen Sie stattdessen twenty-sdk als lokale Abhängigkeit hinzu und binden Sie Skripte in Ihrer package.json ein:
yarn app:dev, yarn app:generate usw.
Fehlerbehebung
- Authentifizierungsfehler: Führen Sie
yarn auth:loginaus und stellen Sie sicher, dass Ihr API-Schlüssel die erforderlichen Berechtigungen hat. - Verbindung zum Server nicht möglich: Überprüfen Sie die API-URL und dass der Twenty-Server erreichbar ist.
- Typen oder Client fehlen/veraltet: Führen Sie
yarn app:generateaus. - Dev-Modus synchronisiert nicht: Stellen Sie sicher, dass
yarn app:devläuft und dass Änderungen von Ihrer Umgebung nicht ignoriert werden.