i18n - docs translations (#17499)
Created by Github action Co-authored-by: github-actions <github-actions@twenty.com>
This commit is contained in:
committed by
GitHub
parent
2ffe2d8aa6
commit
59d123d2b1
@@ -50,15 +50,12 @@ yarn app:dev
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new entity to your application (guided)
|
||||
yarn app:create-entity
|
||||
yarn entity:add
|
||||
|
||||
# Generate a typed Twenty client and workspace entity types
|
||||
yarn app:generate
|
||||
|
||||
# Run a one‑time sync (instead of watch mode)
|
||||
yarn app:sync
|
||||
|
||||
# Watch your application's functions logs
|
||||
# Watch your application's function logs
|
||||
yarn function:logs
|
||||
|
||||
# Execute a function by name
|
||||
@@ -68,7 +65,7 @@ yarn function:execute -n my-function -p '{"name": "test"}'
|
||||
yarn app:uninstall
|
||||
|
||||
# Display commands' help
|
||||
yarn app:help
|
||||
yarn help
|
||||
```
|
||||
|
||||
راجع أيضًا: صفحات مرجع CLI لـ [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) و[twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk).
|
||||
@@ -97,22 +94,23 @@ my-twenty-app/
|
||||
tsconfig.json
|
||||
README.md
|
||||
src/
|
||||
app/
|
||||
application.config.ts # مطلوب - التكوين الرئيسي للتطبيق
|
||||
default-function.role.ts # الدور الافتراضي للوظائف بدون خادم
|
||||
// الكيانات الخاصة بك (*.object.ts, *.function.ts, *.role.ts)
|
||||
utils/ # اختياري - تنفيذات المُعالِجات والأدوات المساعدة
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
hello-world.function.ts # Example serverless function
|
||||
hello-world.front-component.tsx # Example front component
|
||||
// your entities (*.object.ts, *.function.ts, *.front-component.tsx, *.role.ts)
|
||||
```
|
||||
|
||||
### الاتفاقية فوق التهيئة
|
||||
|
||||
تستخدم التطبيقات نهج **الاتفاقية فوق التهيئة** حيث تُكتشف الكيانات عبر لاحقة اسم الملف. يتيح ذلك تنظيمًا مرنًا داخل مجلد `src/app/`:
|
||||
|
||||
| لاحقة الملف | نوع الكيان |
|
||||
| --------------- | ---------------------- |
|
||||
| `*.object.ts` | تعريفات كائنات مخصصة |
|
||||
| `*.function.ts` | تعريفات وظائف بلا خادم |
|
||||
| `*.role.ts` | تعريفات الأدوار |
|
||||
| لاحقة الملف | نوع الكيان |
|
||||
| ----------------------- | --------------------------- |
|
||||
| `*.object.ts` | تعريفات كائنات مخصصة |
|
||||
| `*.function.ts` | تعريفات وظائف بلا خادم |
|
||||
| `*.front-component.tsx` | Front component definitions |
|
||||
| `*.role.ts` | تعريفات الأدوار |
|
||||
|
||||
### طرق تنظيم المجلدات المدعومة
|
||||
|
||||
@@ -121,12 +119,14 @@ my-twenty-app/
|
||||
**تقليدي (حسب النوع):**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── objects/
|
||||
│ └── postCard.object.ts
|
||||
├── functions/
|
||||
│ └── createPostCard.function.ts
|
||||
├── components/
|
||||
│ └── card.front-component.tsx
|
||||
└── roles/
|
||||
└── admin.role.ts
|
||||
```
|
||||
@@ -134,44 +134,45 @@ src/app/
|
||||
**حسب الميزة:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
└── post-card/
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── postCardAdmin.role.ts
|
||||
```
|
||||
|
||||
**مسطح:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── admin.role.ts
|
||||
```
|
||||
|
||||
بشكل عام:
|
||||
|
||||
* **package.json**: يصرّح باسم التطبيق والإصدار والمحرّكات (Node 24+، Yarn 4)، ويضيف `twenty-sdk` فضلًا عن نصوص مثل `dev` و`sync` و`generate` و`create-entity` و`logs` و`uninstall` و`auth` التي تفوِّض إلى `twenty` CLI المحلي.
|
||||
* **package.json**: Declares the app name, version, engines (Node 24+, Yarn 4), and adds `twenty-sdk` plus scripts like `app:dev`, `app:generate`, `entity:add`, `function:logs`, `function:execute`, `app:uninstall`, and `auth:login` that delegate to the local `twenty` CLI.
|
||||
* **.gitignore**: يتجاهل العناصر الشائعة مثل `node_modules` و`.yarn` و`generated/` (عميل مضبوط الأنواع) و`dist/` و`build/` ومجلدات التغطية وملفات السجلات وملفات `.env*`.
|
||||
* **yarn.lock**، **.yarnrc.yml**، **.yarn/**: تقوم بقفل وتكوين حزمة أدوات Yarn 4 المستخدمة في المشروع.
|
||||
* **.nvmrc**: يثبّت إصدار Node.js المتوقع للمشروع.
|
||||
* **eslint.config.mjs** و**tsconfig.json**: يقدّمان إعدادات الفحص والتهيئة لـ TypeScript لمصادر TypeScript في تطبيقك.
|
||||
* **README.md**: ملف README قصير في جذر التطبيق يتضمن تعليمات أساسية.
|
||||
* **src/app/**: المكان الرئيسي حيث تعرّف تطبيقك ككود:
|
||||
* **src/**: The main place where you define your application-as-code:
|
||||
* `application.config.ts`: التكوين العام لتطبيقك (بيانات وصفية وربط وقت التشغيل). انظر "تكوين التطبيق" أدناه.
|
||||
* `*.role.ts`: تعريفات الأدوار المستخدمة بواسطة وظائفك بلا خادم. انظر "الدور الافتراضي للوظيفة" أدناه.
|
||||
* `*.object.ts`: تعريفات كائنات مخصصة.
|
||||
* `*.function.ts`: تعريفات وظائف بلا خادم.
|
||||
* **src/utils/**: مجلد اختياري لتنفيذات المعالجات والأدوات المساعدة.
|
||||
* `*.front-component.tsx`: Front component definitions.
|
||||
|
||||
ستضيف الأوامر اللاحقة مزيدًا من الملفات والمجلدات:
|
||||
|
||||
* `yarn app:generate` سيُنشئ مجلدًا `generated/` (عميل Twenty مضبوط الأنواع + أنواع مساحة العمل).
|
||||
* `yarn app:create-entity` سيضيف ملفات تعريف الكيانات تحت `src/app/` لكائناتك المخصصة أو الوظائف أو الأدوار.
|
||||
l
|
||||
* `yarn entity:add` will add entity definition files under `src/` for your custom objects, functions, front components, or roles.
|
||||
|
||||
## المصادقة
|
||||
|
||||
@@ -302,63 +303,12 @@ export default defineObject({
|
||||
* `universalIdentifier` يجب أن يكون فريدًا وثابتًا عبر عمليات النشر.
|
||||
* يتطلب كل حقل `name` و`type` و`label` ومعرّف `universalIdentifier` ثابتًا خاصًا به.
|
||||
* المصفوفة `fields` اختيارية — يمكنك تعريف كائنات بدون حقول مخصصة.
|
||||
* يمكنك إنشاء كائنات جديدة باستخدام `yarn app:create-entity`، والذي يرشدك خلال التسمية والحقول والعلاقات.
|
||||
* You can scaffold new objects using `yarn entity:add`, which guides you through naming, fields, and relationships.
|
||||
|
||||
<Note>
|
||||
**يتم إنشاء الحقول الأساسية تلقائيًا.** عند تعريف كائن مخصص، يضيف Twenty تلقائيًا حقولًا قياسية مثل `name` و`createdAt` و`updatedAt` و`createdBy` و`position` و`deletedAt`. لا تحتاج إلى تعريف هذه في مصفوفة `fields` — أضف فقط حقولك المخصصة.
|
||||
</Note>
|
||||
|
||||
<Accordion title="بديل: صياغة قائمة على المزيّنات">
|
||||
يمكنك أيضًا تعريف كائنات باستخدام مزيّنات TypeScript. يستخدم هذا النهج صياغة معتمدة على الأصناف مع مزيّنات `@Object` و`@Field` و`@Relation`:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
type AddressField,
|
||||
Field,
|
||||
FieldType,
|
||||
type FullNameField,
|
||||
Object,
|
||||
OnDeleteAction,
|
||||
Relation,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { type Note } from '../../generated';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post card',
|
||||
labelPlural: 'Post cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
export class PostCard {
|
||||
@Field({
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Relation({
|
||||
universalIdentifier: 'c9e2b4f4-b9ad-4427-9b42-9971b785edfe',
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
label: 'Notes',
|
||||
icon: 'IconComment',
|
||||
inverseSideTargetUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
onDelete: OnDeleteAction.CASCADE,
|
||||
})
|
||||
notes: Note[];
|
||||
}
|
||||
```
|
||||
|
||||
ملاحظة: يتطلب نهج المزيّنات `experimentalDecorators` في تهيئة TypeScript لديك.
|
||||
</Accordion>
|
||||
|
||||
### تكوين التطبيق (application.config.ts)
|
||||
|
||||
كل تطبيق لديه ملف واحد `application.config.ts` يصف:
|
||||
@@ -469,14 +419,9 @@ export default defineRole({
|
||||
// src/app/createPostCard.function.ts
|
||||
import { defineFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
import Twenty, { type Person } from '~/generated';
|
||||
|
||||
const handler = async (
|
||||
params:
|
||||
| RoutePayload
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload,
|
||||
) => {
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new Twenty(); // generated typed client
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
@@ -507,18 +452,18 @@ export default defineFunction({
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
{
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
type: 'cron',
|
||||
pattern: '0 0 1 1 *',
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
{
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
type: 'databaseEvent',
|
||||
eventName: 'person.updated',
|
||||
updatedFields: ['name'],
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -633,7 +578,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
يمكنك إنشاء وظائف جديدة بطريقتين:
|
||||
|
||||
* **مُنشأ بالقالب**: شغّل `yarn app:create-entity` واختر خيار إضافة وظيفة جديدة. يُولّد هذا ملفًا مبدئيًا مع معالج وتكوين.
|
||||
* **Scaffolded**: Run `yarn entity:add` and choose the option to add a new function. يُولّد هذا ملفًا مبدئيًا مع معالج وتكوين.
|
||||
* **يدوي**: أنشئ ملفًا جديدًا `*.function.ts` واستخدم `defineFunction()` مع اتباع النمط نفسه.
|
||||
|
||||
### عميل مُولَّد مضبوط الأنواع
|
||||
@@ -641,13 +586,13 @@ const handler = async (event: RoutePayload) => {
|
||||
شغّل yarn app:generate لإنشاء عميل محلي مضبوط الأنواع في generated/ استنادًا إلى مخطط مساحة العمل لديك. استخدمه في وظائفك:
|
||||
|
||||
```typescript
|
||||
import Twenty from './generated';
|
||||
import Twenty from '~/generated';
|
||||
|
||||
const client = new Twenty();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
```
|
||||
|
||||
يُعاد توليد العميل بواسطة `yarn app:generate`. أعِد تشغيله بعد تغيير كائناتك وتشغيل `yarn app:sync` أو عند الانضمام إلى مساحة عمل جديدة.
|
||||
يُعاد توليد العميل بواسطة `yarn app:generate`. Re-run after changing your objects or when onboarding to a new workspace.
|
||||
|
||||
#### بيانات الاعتماد في وقت التشغيل في الوظائف بلا خادم
|
||||
|
||||
@@ -679,25 +624,29 @@ yarn add -D twenty-sdk
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"auth": "twenty auth login",
|
||||
"generate": "twenty app generate",
|
||||
"dev": "twenty app dev",
|
||||
"sync": "twenty app sync",
|
||||
"uninstall": "twenty app uninstall",
|
||||
"logs": "twenty app logs",
|
||||
"create-entity": "twenty app add",
|
||||
"help": "twenty --help"
|
||||
"auth:login": "twenty auth:login",
|
||||
"auth:logout": "twenty auth:logout",
|
||||
"auth:status": "twenty auth:status",
|
||||
"auth:switch": "twenty auth:switch",
|
||||
"auth:list": "twenty auth:list",
|
||||
"app:dev": "twenty app:dev",
|
||||
"app:generate": "twenty app:generate",
|
||||
"app:uninstall": "twenty app:uninstall",
|
||||
"entity:add": "twenty entity:add",
|
||||
"function:logs": "twenty function:logs",
|
||||
"function:execute": "twenty function:execute",
|
||||
"help": "twenty help"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
يمكنك الآن تشغيل الأوامر نفسها عبر Yarn، مثل `yarn app:dev` و`yarn app:sync`، إلخ.
|
||||
Now you can run the same commands via Yarn, e.g. `yarn app:dev`, `yarn app:generate`, etc.
|
||||
|
||||
## استكشاف الأخطاء وإصلاحها
|
||||
|
||||
* أخطاء المصادقة: شغّل `yarn auth:login` وتأكد من أن مفتاح واجهة برمجة التطبيقات لديك يمتلك الأذونات المطلوبة.
|
||||
* يتعذّر الاتصال بالخادم: تحقق من عنوان URL لواجهة البرمجة وأن خادم Twenty قابل للوصول.
|
||||
* الأنواع أو العميل مفقود/قديم: شغّل `yarn app:generate` ثم `yarn app:dev`.
|
||||
* Types or client missing/outdated: run `yarn app:generate`.
|
||||
* وضع التطوير لا يزامن: تأكد من أن `yarn app:dev` قيد التشغيل وأن التغييرات ليست متجاهلة من بيئتك.
|
||||
|
||||
قناة المساعدة على Discord: https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
|
||||
@@ -50,15 +50,12 @@ Odtud můžete:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new entity to your application (guided)
|
||||
yarn app:create-entity
|
||||
yarn entity:add
|
||||
|
||||
# Generate a typed Twenty client and workspace entity types
|
||||
yarn app:generate
|
||||
|
||||
# Run a one‑time sync (instead of watch mode)
|
||||
yarn app:sync
|
||||
|
||||
# Watch your application's functions logs
|
||||
# Watch your application's function logs
|
||||
yarn function:logs
|
||||
|
||||
# Execute a function by name
|
||||
@@ -68,7 +65,7 @@ yarn function:execute -n my-function -p '{"name": "test"}'
|
||||
yarn app:uninstall
|
||||
|
||||
# Display commands' help
|
||||
yarn app:help
|
||||
yarn help
|
||||
```
|
||||
|
||||
Viz také: referenční stránky CLI pro [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) a [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk).
|
||||
@@ -97,22 +94,23 @@ my-twenty-app/
|
||||
tsconfig.json
|
||||
README.md
|
||||
src/
|
||||
app/
|
||||
application.config.ts # Povinné - hlavní konfigurace aplikace
|
||||
default-function.role.ts # Výchozí role pro serverless funkce
|
||||
// vaše entity (*.object.ts, *.function.ts, *.role.ts)
|
||||
utils/ # Volitelné - implementace handlerů a nástroje
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
hello-world.function.ts # Example serverless function
|
||||
hello-world.front-component.tsx # Example front component
|
||||
// your entities (*.object.ts, *.function.ts, *.front-component.tsx, *.role.ts)
|
||||
```
|
||||
|
||||
### Konvence před konfigurací
|
||||
|
||||
Aplikace používají přístup **konvence před konfigurací**, kde jsou entity detekovány podle přípony souboru. To umožňuje flexibilní organizaci ve složce `src/app/`:
|
||||
|
||||
| Přípona souboru | Typ entity |
|
||||
| --------------- | -------------------------- |
|
||||
| `*.object.ts` | Definice vlastních objektů |
|
||||
| `*.function.ts` | Definice serverless funkcí |
|
||||
| `*.role.ts` | Definice rolí |
|
||||
| Přípona souboru | Typ entity |
|
||||
| ----------------------- | --------------------------- |
|
||||
| `*.object.ts` | Definice vlastních objektů |
|
||||
| `*.function.ts` | Definice serverless funkcí |
|
||||
| `*.front-component.tsx` | Front component definitions |
|
||||
| `*.role.ts` | Definice rolí |
|
||||
|
||||
### Podporované uspořádání složek
|
||||
|
||||
@@ -121,12 +119,14 @@ Entity můžete uspořádat podle některého z těchto vzorů:
|
||||
**Tradiční (podle typu):**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── objects/
|
||||
│ └── postCard.object.ts
|
||||
├── functions/
|
||||
│ └── createPostCard.function.ts
|
||||
├── components/
|
||||
│ └── card.front-component.tsx
|
||||
└── roles/
|
||||
└── admin.role.ts
|
||||
```
|
||||
@@ -134,44 +134,45 @@ src/app/
|
||||
**Podle funkcí:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
└── post-card/
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── postCardAdmin.role.ts
|
||||
```
|
||||
|
||||
**Plochá:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── admin.role.ts
|
||||
```
|
||||
|
||||
V kostce:
|
||||
|
||||
* **package.json**: Deklaruje název aplikace, verzi, engines (Node 24+, Yarn 4) a přidává `twenty-sdk` plus skripty jako `dev`, `sync`, `generate`, `create-entity`, `logs`, `uninstall` a `auth`, které delegují na lokální `twenty` CLI.
|
||||
* **package.json**: Declares the app name, version, engines (Node 24+, Yarn 4), and adds `twenty-sdk` plus scripts like `app:dev`, `app:generate`, `entity:add`, `function:logs`, `function:execute`, `app:uninstall`, and `auth:login` that delegate to the local `twenty` CLI.
|
||||
* **.gitignore**: Ignoruje běžné artefakty jako `node_modules`, `.yarn`, `generated/` (typovaný klient), `dist/`, `build/`, složky s coverage, logy a soubory `.env*`.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Zamykají a konfigurují nástrojový řetězec Yarn 4 používaný projektem.
|
||||
* **.nvmrc**: Fixuje verzi Node.js požadovanou projektem.
|
||||
* **eslint.config.mjs** a **tsconfig.json**: Poskytují lintování a konfiguraci TypeScriptu pro zdrojové soubory vaší aplikace v TypeScriptu.
|
||||
* **README.md**: Krátké README v kořeni aplikace se základními pokyny.
|
||||
* **src/app/**: Hlavní místo, kde definujete svou aplikaci jako kód:
|
||||
* **src/**: The main place where you define your application-as-code:
|
||||
* `application.config.ts`: Globální konfigurace vaší aplikace (metadata a napojení za běhu). Viz „Konfigurace aplikace“ níže.
|
||||
* `*.role.ts`: Definice rolí používané vašimi serverless funkcemi. Viz „Výchozí role funkce“ níže.
|
||||
* `*.object.ts`: Definice vlastních objektů.
|
||||
* `*.function.ts`: Definice serverless funkcí.
|
||||
* **src/utils/**: Volitelná složka pro implementace obslužných funkcí a pomocné nástroje.
|
||||
* `*.front-component.tsx`: Front component definitions.
|
||||
|
||||
Pozdější příkazy přidají další soubory a složky:
|
||||
|
||||
* `yarn app:generate` vytvoří složku `generated/` (typovaný klient Twenty + typy pracovního prostoru).
|
||||
* `yarn app:create-entity` přidá soubory s definicemi entit do `src/app/` pro vaše vlastní objekty, funkce nebo role.
|
||||
l
|
||||
* `yarn entity:add` will add entity definition files under `src/` for your custom objects, functions, front components, or roles.
|
||||
|
||||
## Ověření
|
||||
|
||||
@@ -302,63 +303,12 @@ Hlavní body:
|
||||
* Hodnota `universalIdentifier` musí být jedinečná a stabilní napříč nasazeními.
|
||||
* Každé pole vyžaduje `name`, `type`, `label` a svůj vlastní stabilní `universalIdentifier`.
|
||||
* Pole `fields` je volitelné — objekty můžete definovat i bez vlastních polí.
|
||||
* Nové objekty můžete vygenerovat pomocí `yarn app:create-entity`, který vás provede pojmenováním, poli a vztahy.
|
||||
* You can scaffold new objects using `yarn entity:add`, which guides you through naming, fields, and relationships.
|
||||
|
||||
<Note>
|
||||
**Základní pole jsou vytvořena automaticky.** Když definujete vlastní objekt, Twenty automaticky přidá standardní pole jako `name`, `createdAt`, `updatedAt`, `createdBy`, `position` a `deletedAt`. Nemusíte je definovat v poli `fields` — přidejte pouze svá vlastní pole.
|
||||
</Note>
|
||||
|
||||
<Accordion title="Alternativa: Syntaxe založená na dekorátorech">
|
||||
Objekty můžete definovat také pomocí dekorátorů TypeScriptu. Tento přístup používá třídovou syntaxi s dekorátory `@Object`, `@Field` a `@Relation`:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
type AddressField,
|
||||
Field,
|
||||
FieldType,
|
||||
type FullNameField,
|
||||
Object,
|
||||
OnDeleteAction,
|
||||
Relation,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { type Note } from '../../generated';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post card',
|
||||
labelPlural: 'Post cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
export class PostCard {
|
||||
@Field({
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Relation({
|
||||
universalIdentifier: 'c9e2b4f4-b9ad-4427-9b42-9971b785edfe',
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
label: 'Notes',
|
||||
icon: 'IconComment',
|
||||
inverseSideTargetUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
onDelete: OnDeleteAction.CASCADE,
|
||||
})
|
||||
notes: Note[];
|
||||
}
|
||||
```
|
||||
|
||||
Poznámka: Přístup s dekorátory vyžaduje `experimentalDecorators` v konfiguraci TypeScriptu.
|
||||
</Accordion>
|
||||
|
||||
### Konfigurace aplikace (application.config.ts)
|
||||
|
||||
Každá aplikace má jeden soubor `application.config.ts`, který popisuje:
|
||||
@@ -469,14 +419,9 @@ Každý soubor funkce používá `defineFunction()` k exportu konfigurace s obsl
|
||||
// src/app/createPostCard.function.ts
|
||||
import { defineFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
import Twenty, { type Person } from '~/generated';
|
||||
|
||||
const handler = async (
|
||||
params:
|
||||
| RoutePayload
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload,
|
||||
) => {
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new Twenty(); // generated typed client
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
@@ -507,18 +452,18 @@ export default defineFunction({
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
{
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
type: 'cron',
|
||||
pattern: '0 0 1 1 *',
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
{
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
type: 'databaseEvent',
|
||||
eventName: 'person.updated',
|
||||
updatedFields: ['name'],
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -633,7 +578,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Nové funkce můžete vytvářet dvěma způsoby:
|
||||
|
||||
* **Vygenerované**: Spusťte `yarn app:create-entity` a zvolte možnost přidat novou funkci. Tím se vygeneruje startovací soubor s obslužnou funkcí a konfigurací.
|
||||
* **Scaffolded**: Run `yarn entity:add` and choose the option to add a new function. Tím se vygeneruje startovací soubor s obslužnou funkcí a konfigurací.
|
||||
* **Ruční**: Vytvořte nový soubor `*.function.ts` a použijte `defineFunction()` podle stejného vzoru.
|
||||
|
||||
### Generovaný typovaný klient
|
||||
@@ -641,13 +586,13 @@ Nové funkce můžete vytvářet dvěma způsoby:
|
||||
Spusťte yarn app:generate a vytvořte lokálního typovaného klienta v generated/ na základě schématu vašeho pracovního prostoru. Použijte jej ve svých funkcích:
|
||||
|
||||
```typescript
|
||||
import Twenty from './generated';
|
||||
import Twenty from '~/generated';
|
||||
|
||||
const client = new Twenty();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
```
|
||||
|
||||
Klient je znovu generován příkazem `yarn app:generate`. Spusťte jej znovu po změně objektů a po `yarn app:sync`, případně při připojení k novému pracovnímu prostoru.
|
||||
Klient je znovu generován příkazem `yarn app:generate`. Re-run after changing your objects or when onboarding to a new workspace.
|
||||
|
||||
#### Běhové přihlašovací údaje v serverless funkcích
|
||||
|
||||
@@ -679,25 +624,29 @@ Poté přidejte skripty jako tyto:
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"auth": "twenty auth login",
|
||||
"generate": "twenty app generate",
|
||||
"dev": "twenty app dev",
|
||||
"sync": "twenty app sync",
|
||||
"uninstall": "twenty app uninstall",
|
||||
"logs": "twenty app logs",
|
||||
"create-entity": "twenty app add",
|
||||
"help": "twenty --help"
|
||||
"auth:login": "twenty auth:login",
|
||||
"auth:logout": "twenty auth:logout",
|
||||
"auth:status": "twenty auth:status",
|
||||
"auth:switch": "twenty auth:switch",
|
||||
"auth:list": "twenty auth:list",
|
||||
"app:dev": "twenty app:dev",
|
||||
"app:generate": "twenty app:generate",
|
||||
"app:uninstall": "twenty app:uninstall",
|
||||
"entity:add": "twenty entity:add",
|
||||
"function:logs": "twenty function:logs",
|
||||
"function:execute": "twenty function:execute",
|
||||
"help": "twenty help"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Nyní můžete spouštět stejné příkazy přes Yarn, např. `yarn app:dev`, `yarn app:sync` atd.
|
||||
Now you can run the same commands via Yarn, e.g. `yarn app:dev`, `yarn app:generate`, etc.
|
||||
|
||||
## Řešení potíží
|
||||
|
||||
* Chyby ověření: spusťte `yarn auth:login` a ujistěte se, že váš klíč API má požadovaná oprávnění.
|
||||
* Nelze se připojit k serveru: ověřte URL API a že je server Twenty dosažitelný.
|
||||
* Typy nebo klient chybí/jsou zastaralé: spusťte `yarn app:generate` a poté `yarn app:dev`.
|
||||
* Types or client missing/outdated: run `yarn app:generate`.
|
||||
* Režim vývoje nesynchronizuje: ujistěte se, že běží `yarn app:dev` a že vaše prostředí změny neignoruje.
|
||||
|
||||
Kanál podpory na Discordu: https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
|
||||
@@ -50,15 +50,12 @@ Von hier aus können Sie:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new entity to your application (guided)
|
||||
yarn app:create-entity
|
||||
yarn entity:add
|
||||
|
||||
# Generate a typed Twenty client and workspace entity types
|
||||
yarn app:generate
|
||||
|
||||
# Run a one‑time sync (instead of watch mode)
|
||||
yarn app:sync
|
||||
|
||||
# Watch your application's functions logs
|
||||
# Watch your application's function logs
|
||||
yarn function:logs
|
||||
|
||||
# Execute a function by name
|
||||
@@ -68,7 +65,7 @@ yarn function:execute -n my-function -p '{"name": "test"}'
|
||||
yarn app:uninstall
|
||||
|
||||
# Display commands' help
|
||||
yarn app:help
|
||||
yarn help
|
||||
```
|
||||
|
||||
Siehe auch: die CLI-Referenzseiten für [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) und [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk).
|
||||
@@ -97,22 +94,23 @@ my-twenty-app/
|
||||
tsconfig.json
|
||||
README.md
|
||||
src/
|
||||
app/
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
// your entities (*.object.ts, *.function.ts, *.role.ts)
|
||||
utils/ # Optional - handler implementations & utilities
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
hello-world.function.ts # Example serverless function
|
||||
hello-world.front-component.tsx # Example front component
|
||||
// your entities (*.object.ts, *.function.ts, *.front-component.tsx, *.role.ts)
|
||||
```
|
||||
|
||||
### Konvention vor Konfiguration
|
||||
|
||||
Anwendungen verwenden einen Ansatz **Konvention vor Konfiguration**, bei dem Entitäten anhand ihrer Dateiendung erkannt werden. Dies ermöglicht eine flexible Organisation im Ordner `src/app/`:
|
||||
|
||||
| Dateiendung | Entitätstyp |
|
||||
| --------------- | ------------------------------------- |
|
||||
| `*.object.ts` | Benutzerdefinierte Objektdefinitionen |
|
||||
| `*.function.ts` | Definitionen serverloser Funktionen |
|
||||
| `*.role.ts` | Rollendefinitionen |
|
||||
| Dateiendung | Entitätstyp |
|
||||
| ----------------------- | ------------------------------------- |
|
||||
| `*.object.ts` | Benutzerdefinierte Objektdefinitionen |
|
||||
| `*.function.ts` | Definitionen serverloser Funktionen |
|
||||
| `*.front-component.tsx` | Front component definitions |
|
||||
| `*.role.ts` | Rollendefinitionen |
|
||||
|
||||
### Unterstützte Ordnerorganisationen
|
||||
|
||||
@@ -121,12 +119,14 @@ Sie können Ihre Entitäten nach einem der folgenden Muster organisieren:
|
||||
**Traditionell (nach Typ):**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── objects/
|
||||
│ └── postCard.object.ts
|
||||
├── functions/
|
||||
│ └── createPostCard.function.ts
|
||||
├── components/
|
||||
│ └── card.front-component.tsx
|
||||
└── roles/
|
||||
└── admin.role.ts
|
||||
```
|
||||
@@ -134,44 +134,45 @@ src/app/
|
||||
**Feature-basiert:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
└── post-card/
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── postCardAdmin.role.ts
|
||||
```
|
||||
|
||||
**Flach:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── admin.role.ts
|
||||
```
|
||||
|
||||
Auf hoher Ebene:
|
||||
|
||||
* **package.json**: Deklariert App-Name, Version, Engines (Node 24+, Yarn 4) und fügt `twenty-sdk` sowie Skripte wie `dev`, `sync`, `generate`, `create-entity`, `logs`, `uninstall` und `auth` hinzu, die an die lokale `twenty`-CLI delegieren.
|
||||
* **package.json**: Declares the app name, version, engines (Node 24+, Yarn 4), and adds `twenty-sdk` plus scripts like `app:dev`, `app:generate`, `entity:add`, `function:logs`, `function:execute`, `app:uninstall`, and `auth:login` that delegate to the local `twenty` CLI.
|
||||
* **.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.
|
||||
* **src/app/**: Der Hauptort, an dem Sie Ihre Anwendung als Code definieren:
|
||||
* **src/**: The main place where you define your application-as-code:
|
||||
* `application.config.ts`: Globale Konfiguration für Ihre App (Metadaten und Laufzeit-Anbindung). Siehe unten „Anwendungskonfiguration“.
|
||||
* `*.role.ts`: Rollendefinitionen, die von Ihren serverlosen Funktionen verwendet werden. Siehe unten „Standard-Funktionsrolle“.
|
||||
* `*.object.ts`: Benutzerdefinierte Objektdefinitionen.
|
||||
* `*.function.ts`: Definitionen serverloser Funktionen.
|
||||
* **src/utils/**: Optionaler Ordner für Handler-Implementierungen und Utilities.
|
||||
* `*.front-component.tsx`: Front component definitions.
|
||||
|
||||
Spätere Befehle fügen weitere Dateien und Ordner hinzu:
|
||||
|
||||
* `yarn app:generate` erstellt einen `generated/`-Ordner (typisierter Twenty-Client + Workspace-Typen).
|
||||
* `yarn app:create-entity` fügt unter `src/app/` Entitätsdefinitionsdateien für Ihre benutzerdefinierten Objekte, Funktionen oder Rollen hinzu.
|
||||
l
|
||||
* `yarn entity:add` will add entity definition files under `src/` for your custom objects, functions, front components, or roles.
|
||||
|
||||
## Authentifizierung
|
||||
|
||||
@@ -302,63 +303,12 @@ Hauptpunkte:
|
||||
* 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 app:create-entity` neue Objekte erzeugen; der Assistent führt Sie durch Benennung, Felder und Beziehungen.
|
||||
* You can scaffold new objects using `yarn entity:add`, which guides you through naming, fields, and relationships.
|
||||
|
||||
<Note>
|
||||
**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.
|
||||
</Note>
|
||||
|
||||
<Accordion title="Alternative: Dekoratorbasierte Syntax">
|
||||
Sie können Objekte auch mit TypeScript-Dekoratoren definieren. Dieser Ansatz verwendet klassenbasierte Syntax mit den Dekoratoren `@Object`, `@Field` und `@Relation`:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
type AddressField,
|
||||
Field,
|
||||
FieldType,
|
||||
type FullNameField,
|
||||
Object,
|
||||
OnDeleteAction,
|
||||
Relation,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { type Note } from '../../generated';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post card',
|
||||
labelPlural: 'Post cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
export class PostCard {
|
||||
@Field({
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Relation({
|
||||
universalIdentifier: 'c9e2b4f4-b9ad-4427-9b42-9971b785edfe',
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
label: 'Notes',
|
||||
icon: 'IconComment',
|
||||
inverseSideTargetUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
onDelete: OnDeleteAction.CASCADE,
|
||||
})
|
||||
notes: Note[];
|
||||
}
|
||||
```
|
||||
|
||||
Hinweis: Der Dekorator-Ansatz erfordert `experimentalDecorators` in Ihrer TypeScript-Konfiguration.
|
||||
</Accordion>
|
||||
|
||||
### Anwendungskonfiguration (application.config.ts)
|
||||
|
||||
Jede App hat eine einzelne Datei `application.config.ts`, die Folgendes beschreibt:
|
||||
@@ -469,14 +419,9 @@ Jede Funktionsdatei verwendet `defineFunction()`, um eine Konfiguration mit eine
|
||||
// src/app/createPostCard.function.ts
|
||||
import { defineFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
import Twenty, { type Person } from '~/generated';
|
||||
|
||||
const handler = async (
|
||||
params:
|
||||
| RoutePayload
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload,
|
||||
) => {
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new Twenty(); // generated typed client
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
@@ -507,18 +452,18 @@ export default defineFunction({
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
{
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
type: 'cron',
|
||||
pattern: '0 0 1 1 *',
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
{
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
type: 'databaseEvent',
|
||||
eventName: 'person.updated',
|
||||
updatedFields: ['name'],
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -633,7 +578,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Sie können neue Funktionen auf zwei Arten erstellen:
|
||||
|
||||
* **Generiert**: Führen Sie `yarn app:create-entity` aus und wählen Sie die Option zum Hinzufügen einer neuen Funktion. Dadurch wird eine Starterdatei mit Handler und Konfiguration erzeugt.
|
||||
* **Scaffolded**: Run `yarn entity:add` and choose the option to add a new function. Dadurch wird eine Starterdatei mit Handler und Konfiguration erzeugt.
|
||||
* **Manuell**: Erstellen Sie eine neue `*.function.ts`-Datei und verwenden Sie `defineFunction()` nach demselben Muster.
|
||||
|
||||
### Generierter typisierter Client
|
||||
@@ -641,13 +586,13 @@ Sie können neue Funktionen auf zwei Arten erstellen:
|
||||
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:
|
||||
|
||||
```typescript
|
||||
import Twenty from './generated';
|
||||
import Twenty from '~/generated';
|
||||
|
||||
const client = new Twenty();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
```
|
||||
|
||||
Der Client wird durch `yarn app:generate` erneut generiert. Führen Sie ihn nach Änderungen an Ihren Objekten und nach `yarn app:sync` bzw. beim Onboarding in einen neuen Workspace erneut aus.
|
||||
Der Client wird durch `yarn app:generate` erneut generiert. Re-run after changing your objects or when onboarding to a new workspace.
|
||||
|
||||
#### Laufzeit-Anmeldedaten in serverlosen Funktionen
|
||||
|
||||
@@ -679,25 +624,29 @@ Fügen Sie dann Skripte wie diese hinzu:
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"auth": "twenty auth login",
|
||||
"generate": "twenty app generate",
|
||||
"dev": "twenty app dev",
|
||||
"sync": "twenty app sync",
|
||||
"uninstall": "twenty app uninstall",
|
||||
"logs": "twenty app logs",
|
||||
"create-entity": "twenty app add",
|
||||
"help": "twenty --help"
|
||||
"auth:login": "twenty auth:login",
|
||||
"auth:logout": "twenty auth:logout",
|
||||
"auth:status": "twenty auth:status",
|
||||
"auth:switch": "twenty auth:switch",
|
||||
"auth:list": "twenty auth:list",
|
||||
"app:dev": "twenty app:dev",
|
||||
"app:generate": "twenty app:generate",
|
||||
"app:uninstall": "twenty app:uninstall",
|
||||
"entity:add": "twenty entity:add",
|
||||
"function:logs": "twenty function:logs",
|
||||
"function:execute": "twenty function:execute",
|
||||
"help": "twenty help"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Jetzt können Sie dieselben Befehle über Yarn ausführen, z. B. `yarn app:dev`, `yarn app:sync` usw.
|
||||
Now you can run the same commands via Yarn, e.g. `yarn app:dev`, `yarn app:generate`, etc.
|
||||
|
||||
## Fehlerbehebung
|
||||
|
||||
* Authentifizierungsfehler: Führen Sie `yarn auth:login` aus 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:generate` und anschließend `yarn app:dev` aus.
|
||||
* Types or client missing/outdated: run `yarn app:generate`.
|
||||
* Dev-Modus synchronisiert nicht: Stellen Sie sicher, dass `yarn app:dev` läuft und dass Änderungen von Ihrer Umgebung nicht ignoriert werden.
|
||||
|
||||
Discord-Hilfekanal: https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
|
||||
@@ -49,26 +49,23 @@ yarn app:dev
|
||||
Desde aquí usted puede:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new entity to your application (guided)
|
||||
yarn app:create-entity
|
||||
# Añade una nueva entidad a tu aplicación (guiado)
|
||||
yarn entity:add
|
||||
|
||||
# Generate a typed Twenty client and workspace entity types
|
||||
# Genera un cliente tipado de Twenty y tipos de entidad del espacio de trabajo
|
||||
yarn app:generate
|
||||
|
||||
# Run a one‑time sync (instead of watch mode)
|
||||
yarn app:sync
|
||||
|
||||
# Watch your application's functions logs
|
||||
# Supervisa los registros de funciones de tu aplicación
|
||||
yarn function:logs
|
||||
|
||||
# Execute a function by name
|
||||
yarn function:execute -n my-function -p '{"name": "test"}'
|
||||
# Ejecuta una función por nombre
|
||||
yarn function:execute -n my-function -p '{\"name\": \"test\"}'
|
||||
|
||||
# Uninstall the application from the current workspace
|
||||
# Desinstala la aplicación del espacio de trabajo actual
|
||||
yarn app:uninstall
|
||||
|
||||
# Display commands' help
|
||||
yarn app:help
|
||||
# Muestra la ayuda de los comandos
|
||||
yarn help
|
||||
```
|
||||
|
||||
Consulta también: las páginas de referencia de la CLI para [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) y [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk).
|
||||
@@ -97,22 +94,23 @@ my-twenty-app/
|
||||
tsconfig.json
|
||||
README.md
|
||||
src/
|
||||
app/
|
||||
application.config.ts # Obligatorio - configuración principal de la aplicación
|
||||
default-function.role.ts # Rol predeterminado para las funciones sin servidor
|
||||
// tus entidades (*.object.ts, *.function.ts, *.role.ts)
|
||||
utils/ # Opcional - implementaciones de manejadores y utilidades
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
hello-world.function.ts # Example serverless function
|
||||
hello-world.front-component.tsx # Example front component
|
||||
// your entities (*.object.ts, *.function.ts, *.front-component.tsx, *.role.ts)
|
||||
```
|
||||
|
||||
### Convención sobre configuración
|
||||
|
||||
Las aplicaciones usan un enfoque de **convención sobre configuración** en el que las entidades se detectan por su sufijo de archivo. Esto permite una organización flexible dentro de la carpeta `src/app/`:
|
||||
|
||||
| Sufijo de archivo | Tipo de entidad |
|
||||
| ----------------- | -------------------------------------- |
|
||||
| `*.object.ts` | Definiciones de objetos personalizados |
|
||||
| `*.function.ts` | Definiciones de funciones sin servidor |
|
||||
| `*.role.ts` | Definiciones de roles |
|
||||
| Sufijo de archivo | Tipo de entidad |
|
||||
| ----------------------- | --------------------------------------- |
|
||||
| `*.object.ts` | Definiciones de objetos personalizados |
|
||||
| `*.function.ts` | Definiciones de funciones sin servidor |
|
||||
| `*.front-component.tsx` | Definiciones de componentes de interfaz |
|
||||
| `*.role.ts` | Definiciones de roles |
|
||||
|
||||
### Organizaciones de carpetas compatibles
|
||||
|
||||
@@ -121,12 +119,14 @@ Puedes organizar tus entidades con cualquiera de estos patrones:
|
||||
**Tradicional (por tipo):**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── objects/
|
||||
│ └── postCard.object.ts
|
||||
├── functions/
|
||||
│ └── createPostCard.function.ts
|
||||
├── components/
|
||||
│ └── card.front-component.tsx
|
||||
└── roles/
|
||||
└── admin.role.ts
|
||||
```
|
||||
@@ -134,44 +134,45 @@ src/app/
|
||||
**Basado en funcionalidades:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
└── post-card/
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── postCardAdmin.role.ts
|
||||
```
|
||||
|
||||
**Plano:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── admin.role.ts
|
||||
```
|
||||
|
||||
A grandes rasgos:
|
||||
|
||||
* **package.json**: Declara el nombre de la aplicación, la versión, los entornos (Node 24+, Yarn 4) y agrega `twenty-sdk` además de scripts como `dev`, `sync`, `generate`, `create-entity`, `logs`, `uninstall` y `auth` que delegan en la CLI local `twenty`.
|
||||
* **package.json**: Declares the app name, version, engines (Node 24+, Yarn 4), and adds `twenty-sdk` plus scripts like `app:dev`, `app:generate`, `entity:add`, `function:logs`, `function:execute`, `app:uninstall`, and `auth:login` that delegate to the local `twenty` CLI.
|
||||
* **.gitignore**: Ignora artefactos comunes como `node_modules`, `.yarn`, `generated/` (cliente tipado), `dist/`, `build/`, carpetas de cobertura, archivos de registro y archivos `.env*`.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Bloquean y configuran la cadena de herramientas Yarn 4 utilizada por el proyecto.
|
||||
* **.nvmrc**: Fija la versión de Node.js esperada por el proyecto.
|
||||
* **eslint.config.mjs** y **tsconfig.json**: Proporcionan linting y configuración de TypeScript para las fuentes de TypeScript de tu aplicación.
|
||||
* **README.md**: Un README breve en la raíz de la aplicación con instrucciones básicas.
|
||||
* **src/app/**: El lugar principal donde defines tu aplicación como código:
|
||||
* **src/**: The main place where you define your application-as-code:
|
||||
* `application.config.ts`: Configuración global de tu aplicación (metadatos y vinculación en tiempo de ejecución). Consulta "Configuración de la aplicación" más abajo.
|
||||
* `*.role.ts`: Definiciones de roles usadas por tus funciones sin servidor. Consulta "Rol de función predeterminado" más abajo.
|
||||
* `*.object.ts`: Definiciones de objetos personalizados.
|
||||
* `*.function.ts`: Definiciones de funciones sin servidor.
|
||||
* **src/utils/**: Carpeta opcional para implementaciones de controladores y utilidades.
|
||||
* `*.front-component.tsx`: Front component definitions.
|
||||
|
||||
Comandos posteriores añadirán más archivos y carpetas:
|
||||
|
||||
* `yarn app:generate` creará una carpeta `generated/` (cliente tipado de Twenty + tipos del espacio de trabajo).
|
||||
* `yarn app:create-entity` añadirá archivos de definición de entidades en `src/app/` para tus objetos, funciones o roles personalizados.
|
||||
l
|
||||
* `yarn entity:add` will add entity definition files under `src/` for your custom objects, functions, front components, or roles.
|
||||
|
||||
## Autenticación
|
||||
|
||||
@@ -302,63 +303,12 @@ Puntos clave:
|
||||
* El `universalIdentifier` debe ser único y estable entre implementaciones.
|
||||
* Cada campo requiere `name`, `type`, `label` y su propio `universalIdentifier` estable.
|
||||
* La matriz `fields` es opcional: puedes definir objetos sin campos personalizados.
|
||||
* Puedes generar nuevos objetos usando `yarn app:create-entity`, que te guía por el nombrado, los campos y las relaciones.
|
||||
* You can scaffold new objects using `yarn entity:add`, which guides you through naming, fields, and relationships.
|
||||
|
||||
<Note>
|
||||
**Los campos base se crean automáticamente.** Cuando defines un objeto personalizado, Twenty añade automáticamente campos estándar como `name`, `createdAt`, `updatedAt`, `createdBy`, `position` y `deletedAt`. No necesitas definir estos en tu matriz `fields` — solo agrega tus campos personalizados.
|
||||
</Note>
|
||||
|
||||
<Accordion title="Alternativa: sintaxis basada en decoradores">
|
||||
También puedes definir objetos usando decoradores de TypeScript. Este enfoque usa sintaxis basada en clases con los decoradores `@Object`, `@Field` y `@Relation`:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
type AddressField,
|
||||
Field,
|
||||
FieldType,
|
||||
type FullNameField,
|
||||
Object,
|
||||
OnDeleteAction,
|
||||
Relation,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { type Note } from '../../generated';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post card',
|
||||
labelPlural: 'Post cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
export class PostCard {
|
||||
@Field({
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Relation({
|
||||
universalIdentifier: 'c9e2b4f4-b9ad-4427-9b42-9971b785edfe',
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
label: 'Notes',
|
||||
icon: 'IconComment',
|
||||
inverseSideTargetUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
onDelete: OnDeleteAction.CASCADE,
|
||||
})
|
||||
notes: Note[];
|
||||
}
|
||||
```
|
||||
|
||||
Nota: El enfoque de decoradores requiere `experimentalDecorators` en tu configuración de TypeScript.
|
||||
</Accordion>
|
||||
|
||||
### Configuración de la aplicación (application.config.ts)
|
||||
|
||||
Cada aplicación tiene un único archivo `application.config.ts` que describe:
|
||||
@@ -469,14 +419,9 @@ Cada archivo de función usa `defineFunction()` para exportar una configuración
|
||||
// src/app/createPostCard.function.ts
|
||||
import { defineFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
import Twenty, { type Person } from '~/generated';
|
||||
|
||||
const handler = async (
|
||||
params:
|
||||
| RoutePayload
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload,
|
||||
) => {
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new Twenty(); // generated typed client
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
@@ -507,18 +452,18 @@ export default defineFunction({
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
{
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
type: 'cron',
|
||||
pattern: '0 0 1 1 *',
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
{
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
type: 'databaseEvent',
|
||||
eventName: 'person.updated',
|
||||
updatedFields: ['name'],
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -633,7 +578,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Puedes crear funciones nuevas de dos maneras:
|
||||
|
||||
* **Generado**: Ejecuta `yarn app:create-entity` y elige la opción para añadir una nueva función. Esto genera un archivo inicial con un controlador y configuración.
|
||||
* **Scaffolded**: Run `yarn entity:add` and choose the option to add a new function. Esto genera un archivo inicial con un controlador y configuración.
|
||||
* **Manual**: Crea un nuevo archivo `*.function.ts` y usa `defineFunction()`, siguiendo el mismo patrón.
|
||||
|
||||
### Cliente tipado generado
|
||||
@@ -641,13 +586,13 @@ Puedes crear funciones nuevas de dos maneras:
|
||||
Ejecuta yarn app:generate para crear un cliente tipado local en generated/ basado en el esquema de tu espacio de trabajo. Úsalo en tus funciones:
|
||||
|
||||
```typescript
|
||||
import Twenty from './generated';
|
||||
import Twenty from '~/generated';
|
||||
|
||||
const client = new Twenty();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
```
|
||||
|
||||
El cliente se vuelve a generar con `yarn app:generate`. Vuelve a ejecutarlo después de cambiar tus objetos y de hacer `yarn app:sync`, o al incorporarte a un nuevo espacio de trabajo.
|
||||
El cliente se vuelve a generar con `yarn app:generate`. Re-run after changing your objects or when onboarding to a new workspace.
|
||||
|
||||
#### Credenciales en tiempo de ejecución en funciones sin servidor
|
||||
|
||||
@@ -679,25 +624,29 @@ Luego agrega scripts como estos:
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"auth": "twenty auth login",
|
||||
"generate": "twenty app generate",
|
||||
"dev": "twenty app dev",
|
||||
"sync": "twenty app sync",
|
||||
"uninstall": "twenty app uninstall",
|
||||
"logs": "twenty app logs",
|
||||
"create-entity": "twenty app add",
|
||||
"help": "twenty --help"
|
||||
"auth:login": "twenty auth:login",
|
||||
"auth:logout": "twenty auth:logout",
|
||||
"auth:status": "twenty auth:status",
|
||||
"auth:switch": "twenty auth:switch",
|
||||
"auth:list": "twenty auth:list",
|
||||
"app:dev": "twenty app:dev",
|
||||
"app:generate": "twenty app:generate",
|
||||
"app:uninstall": "twenty app:uninstall",
|
||||
"entity:add": "twenty entity:add",
|
||||
"function:logs": "twenty function:logs",
|
||||
"function:execute": "twenty function:execute",
|
||||
"help": "twenty help"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Ahora puedes ejecutar los mismos comandos mediante Yarn, p. ej., `yarn app:dev`, `yarn app:sync`, etc.
|
||||
Now you can run the same commands via Yarn, e.g. `yarn app:dev`, `yarn app:generate`, etc.
|
||||
|
||||
## Solución de problemas
|
||||
|
||||
* Errores de autenticación: ejecuta `yarn auth:login` y asegúrate de que tu clave de API tenga los permisos necesarios.
|
||||
* No se puede conectar al servidor: verifica la URL de la API y que el servidor de Twenty sea accesible.
|
||||
* Tipos o cliente faltantes/obsoletos: ejecuta `yarn app:generate` y luego `yarn app:dev`.
|
||||
* Types or client missing/outdated: run `yarn app:generate`.
|
||||
* El modo de desarrollo no sincroniza: asegúrate de que `yarn app:dev` esté ejecutándose y de que los cambios no sean ignorados por tu entorno.
|
||||
|
||||
Canal de ayuda en Discord: https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
|
||||
@@ -49,26 +49,23 @@ yarn app:dev
|
||||
À partir d'ici, vous pouvez :
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new entity to your application (guided)
|
||||
yarn app:create-entity
|
||||
# Ajouter une nouvelle entité à votre application (assisté)
|
||||
yarn entity:add
|
||||
|
||||
# Generate a typed Twenty client and workspace entity types
|
||||
# Générer un client Twenty typé et les types d'entité de l'espace de travail
|
||||
yarn app:generate
|
||||
|
||||
# Run a one‑time sync (instead of watch mode)
|
||||
yarn app:sync
|
||||
|
||||
# Watch your application's functions logs
|
||||
# Surveiller les journaux des fonctions de votre application
|
||||
yarn function:logs
|
||||
|
||||
# Execute a function by name
|
||||
# Exécuter une fonction par nom
|
||||
yarn function:execute -n my-function -p '{"name": "test"}'
|
||||
|
||||
# Uninstall the application from the current workspace
|
||||
# Désinstaller l'application de l'espace de travail actuel
|
||||
yarn app:uninstall
|
||||
|
||||
# Display commands' help
|
||||
yarn app:help},{
|
||||
# Afficher l'aide des commandes
|
||||
yarn help
|
||||
```
|
||||
|
||||
Voir aussi : les pages de référence CLI pour [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) et [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk).
|
||||
@@ -97,22 +94,23 @@ my-twenty-app/
|
||||
tsconfig.json
|
||||
README.md
|
||||
src/
|
||||
app/
|
||||
application.config.ts # Obligatoire - configuration principale de l'application
|
||||
default-function.role.ts # Rôle par défaut pour les fonctions serverless
|
||||
// vos entités (*.object.ts, *.function.ts, *.role.ts)
|
||||
utils/ # Optionnel - implémentations de gestionnaires et utilitaires
|
||||
application.config.ts # Obligatoire - configuration principale de l'application
|
||||
default-function.role.ts # Rôle par défaut pour les fonctions serverless
|
||||
hello-world.function.ts # Exemple de fonction serverless
|
||||
hello-world.front-component.tsx # Exemple de composant frontal
|
||||
// vos entités (*.object.ts, *.function.ts, *.front-component.tsx, *.role.ts)
|
||||
```
|
||||
|
||||
### Convention plutôt que configuration
|
||||
|
||||
Les applications adoptent une approche **convention plutôt que configuration** où les entités sont détectées par leur suffixe de fichier. Cela permet une organisation flexible dans le dossier `src/app/` :
|
||||
|
||||
| Suffixe de fichier | Type d’entité |
|
||||
| ------------------ | ------------------------------------- |
|
||||
| `*.object.ts` | Définitions d’objets personnalisés |
|
||||
| `*.function.ts` | Définitions de fonctions sans serveur |
|
||||
| `*.role.ts` | Définitions de rôles |
|
||||
| Suffixe de fichier | Type d’entité |
|
||||
| ----------------------- | ------------------------------------- |
|
||||
| `*.object.ts` | Définitions d’objets personnalisés |
|
||||
| `*.function.ts` | Définitions de fonctions sans serveur |
|
||||
| `*.front-component.tsx` | Définitions des composants frontaux |
|
||||
| `*.role.ts` | Définitions de rôles |
|
||||
|
||||
### Structures de dossiers prises en charge
|
||||
|
||||
@@ -121,12 +119,14 @@ Vous pouvez organiser vos entités selon l’un des schémas suivants :
|
||||
**Traditionnelle (par type) :**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── objects/
|
||||
│ └── postCard.object.ts
|
||||
├── functions/
|
||||
│ └── createPostCard.function.ts
|
||||
├── components/
|
||||
│ └── card.front-component.tsx
|
||||
└── roles/
|
||||
└── admin.role.ts
|
||||
```
|
||||
@@ -134,44 +134,45 @@ src/app/
|
||||
**Par fonctionnalité :**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
└── post-card/
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── postCardAdmin.role.ts
|
||||
```
|
||||
|
||||
**À plat :**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── admin.role.ts
|
||||
```
|
||||
|
||||
Dans les grandes lignes :
|
||||
|
||||
* **package.json** : Déclare le nom de l’application, la version, les moteurs (Node 24+, Yarn 4), et ajoute `twenty-sdk` ainsi que des scripts comme `dev`, `sync`, `generate`, `create-entity`, `logs`, `uninstall` et `auth` qui délèguent à la CLI locale `twenty`.
|
||||
* **package.json**: Declares the app name, version, engines (Node 24+, Yarn 4), and adds `twenty-sdk` plus scripts like `app:dev`, `app:generate`, `entity:add`, `function:logs`, `function:execute`, `app:uninstall`, and `auth:login` that delegate to the local `twenty` CLI.
|
||||
* **.gitignore** : Ignore les artefacts courants tels que `node_modules`, `.yarn`, `generated/` (client typé), `dist/`, `build/`, les dossiers de couverture, les fichiers journaux et les fichiers `.env*`.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/** : Verrouillent et configurent la chaîne d’outils Yarn 4 utilisée par le projet.
|
||||
* **.nvmrc** : Fige la version de Node.js attendue par le projet.
|
||||
* **eslint.config.mjs** et **tsconfig.json** : Fournissent la configuration de linting et TypeScript pour les sources TypeScript de votre application.
|
||||
* **README.md** : Un bref README à la racine de l’application avec des instructions de base.
|
||||
* **src/app/** : L’endroit principal où vous définissez votre application sous forme de code :
|
||||
* **src/**: The main place where you define your application-as-code:
|
||||
* `application.config.ts` : Configuration globale de votre application (métadonnées et liaisons d’exécution). Voir « Configuration de l’application » ci-dessous.
|
||||
* `*.role.ts` : Définitions de rôles utilisées par vos fonctions sans serveur. Voir « Rôle de fonction par défaut » ci-dessous.
|
||||
* `*.object.ts` : Définitions d’objets personnalisés.
|
||||
* `*.function.ts` : Définitions de fonctions sans serveur.
|
||||
* **src/utils/** : Dossier facultatif pour les implémentations de gestionnaires et utilitaires.
|
||||
* `*.front-component.tsx`: Front component definitions.
|
||||
|
||||
Des commandes ultérieures ajouteront d’autres fichiers et dossiers :
|
||||
|
||||
* `yarn app:generate` créera un dossier `generated/` (client Twenty typé + types de l’espace de travail).
|
||||
* `yarn app:create-entity` ajoutera des fichiers de définition d’entité sous `src/app/` pour vos objets, fonctions ou rôles personnalisés.
|
||||
l
|
||||
* `yarn entity:add` will add entity definition files under `src/` for your custom objects, functions, front components, or roles.
|
||||
|
||||
## Authentification
|
||||
|
||||
@@ -302,63 +303,12 @@ Points clés :
|
||||
* Le `universalIdentifier` doit être unique et stable entre les déploiements.
|
||||
* Chaque champ nécessite un `name`, un `type`, un `label` et son propre `universalIdentifier` stable.
|
||||
* Le tableau `fields` est facultatif — vous pouvez définir des objets sans champs personnalisés.
|
||||
* Vous pouvez générer de nouveaux objets avec `yarn app:create-entity`, qui vous guide à travers le nommage, les champs et les relations.
|
||||
* You can scaffold new objects using `yarn entity:add`, which guides you through naming, fields, and relationships.
|
||||
|
||||
<Note>
|
||||
**Les champs de base sont créés automatiquement.** Lorsque vous définissez un objet personnalisé, Twenty ajoute automatiquement des champs standard tels que `name`, `createdAt`, `updatedAt`, `createdBy`, `position` et `deletedAt`. Vous n'avez pas besoin de les définir dans votre tableau `fields` — ajoutez uniquement vos champs personnalisés.
|
||||
</Note>
|
||||
|
||||
<Accordion title="Alternative : syntaxe basée sur des décorateurs">
|
||||
Vous pouvez également définir des objets à l’aide de décorateurs TypeScript. Cette approche utilise une syntaxe basée sur les classes avec les décorateurs `@Object`, `@Field` et `@Relation` :
|
||||
|
||||
```typescript
|
||||
import {
|
||||
type AddressField,
|
||||
Field,
|
||||
FieldType,
|
||||
type FullNameField,
|
||||
Object,
|
||||
OnDeleteAction,
|
||||
Relation,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { type Note } from '../../generated';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post card',
|
||||
labelPlural: 'Post cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
export class PostCard {
|
||||
@Field({
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Relation({
|
||||
universalIdentifier: 'c9e2b4f4-b9ad-4427-9b42-9971b785edfe',
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
label: 'Notes',
|
||||
icon: 'IconComment',
|
||||
inverseSideTargetUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
onDelete: OnDeleteAction.CASCADE,
|
||||
})
|
||||
notes: Note[];
|
||||
}
|
||||
```
|
||||
|
||||
Remarque : l’approche avec décorateurs requiert `experimentalDecorators` dans votre configuration TypeScript.
|
||||
</Accordion>
|
||||
|
||||
### Configuration de l’application (application.config.ts)
|
||||
|
||||
Chaque application dispose d’un seul fichier `application.config.ts` qui décrit :
|
||||
@@ -469,14 +419,9 @@ Chaque fichier de fonction utilise `defineFunction()` pour exporter une configur
|
||||
// src/app/createPostCard.function.ts
|
||||
import { defineFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
import Twenty, { type Person } from '~/generated';
|
||||
|
||||
const handler = async (
|
||||
params:
|
||||
| RoutePayload
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload,
|
||||
) => {
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new Twenty(); // generated typed client
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
@@ -507,18 +452,18 @@ export default defineFunction({
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
{
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
type: 'cron',
|
||||
pattern: '0 0 1 1 *',
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
{
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
type: 'databaseEvent',
|
||||
eventName: 'person.updated',
|
||||
updatedFields: ['name'],
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -633,7 +578,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Vous pouvez créer de nouvelles fonctions de deux façons :
|
||||
|
||||
* **Générée** : Exécutez `yarn app:create-entity` et choisissez l’option pour ajouter une nouvelle fonction. Cela génère un fichier de démarrage avec un gestionnaire et une configuration.
|
||||
* **Scaffolded**: Run `yarn entity:add` and choose the option to add a new function. Cela génère un fichier de démarrage avec un gestionnaire et une configuration.
|
||||
* **Manuelle** : Créez un nouveau fichier `*.function.ts` et utilisez `defineFunction()`, en suivant le même modèle.
|
||||
|
||||
### Client typé généré
|
||||
@@ -641,13 +586,13 @@ Vous pouvez créer de nouvelles fonctions de deux façons :
|
||||
Exécutez yarn app:generate pour créer un client typé local dans generated/ basé sur le schéma de votre espace de travail. Utilisez-le dans vos fonctions :
|
||||
|
||||
```typescript
|
||||
import Twenty from './generated';
|
||||
import Twenty from '~/generated';
|
||||
|
||||
const client = new Twenty();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
```
|
||||
|
||||
Le client est régénéré par `yarn app:generate`. Relancez la commande après avoir modifié vos objets et exécuté `yarn app:sync`, ou lors de l’intégration à un nouvel espace de travail.
|
||||
Le client est régénéré par `yarn app:generate`. Re-run after changing your objects or when onboarding to a new workspace.
|
||||
|
||||
#### Identifiants d’exécution dans les fonctions sans serveur
|
||||
|
||||
@@ -679,25 +624,29 @@ Ajoutez ensuite des scripts comme ceux-ci :
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"auth": "twenty auth login",
|
||||
"generate": "twenty app generate",
|
||||
"dev": "twenty app dev",
|
||||
"sync": "twenty app sync",
|
||||
"uninstall": "twenty app uninstall",
|
||||
"logs": "twenty app logs",
|
||||
"create-entity": "twenty app add",
|
||||
"help": "twenty --help"
|
||||
"auth:login": "twenty auth:login",
|
||||
"auth:logout": "twenty auth:logout",
|
||||
"auth:status": "twenty auth:status",
|
||||
"auth:switch": "twenty auth:switch",
|
||||
"auth:list": "twenty auth:list",
|
||||
"app:dev": "twenty app:dev",
|
||||
"app:generate": "twenty app:generate",
|
||||
"app:uninstall": "twenty app:uninstall",
|
||||
"entity:add": "twenty entity:add",
|
||||
"function:logs": "twenty function:logs",
|
||||
"function:execute": "twenty function:execute",
|
||||
"help": "twenty help"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Vous pouvez désormais exécuter les mêmes commandes via Yarn, par exemple `yarn app:dev`, `yarn app:sync`, etc.
|
||||
Now you can run the same commands via Yarn, e.g. `yarn app:dev`, `yarn app:generate`, etc.
|
||||
|
||||
## Résolution des problèmes
|
||||
|
||||
* Erreurs d’authentification : exécutez `yarn auth:login` et assurez-vous que votre clé API dispose des autorisations requises.
|
||||
* Impossible de se connecter au serveur : vérifiez l’URL de l’API et que le serveur Twenty est accessible.
|
||||
* Types ou client manquants/obsolètes : exécutez `yarn app:generate` puis `yarn app:dev`.
|
||||
* Types or client missing/outdated: run `yarn app:generate`.
|
||||
* Le mode dev ne se synchronise pas : assurez-vous que `yarn app:dev` est en cours d’exécution et que les modifications ne sont pas ignorées par votre environnement.
|
||||
|
||||
Canal d’aide Discord : https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
|
||||
@@ -50,25 +50,22 @@ Da qui puoi:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new entity to your application (guided)
|
||||
yarn app:create-entity
|
||||
yarn entity:add
|
||||
|
||||
# Generate a typed Twenty client and workspace entity types
|
||||
yarn app:generate
|
||||
|
||||
# Run a one‑time sync (instead of watch mode)
|
||||
yarn app:sync
|
||||
|
||||
# Watch your application's functions logs
|
||||
# Watch your application's function logs
|
||||
yarn function:logs
|
||||
|
||||
# Execute a function by name
|
||||
yarn function:execute -n my-function -p '{\"name\": \"test\"}'
|
||||
yarn function:execute -n my-function -p '{"name": "test"}'
|
||||
|
||||
# Uninstall the application from the current workspace
|
||||
yarn app:uninstall
|
||||
|
||||
# Display commands' help
|
||||
yarn app:help
|
||||
yarn help
|
||||
```
|
||||
|
||||
Vedi anche: le pagine di riferimento della CLI per [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) e [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk).
|
||||
@@ -97,22 +94,23 @@ my-twenty-app/
|
||||
tsconfig.json
|
||||
README.md
|
||||
src/
|
||||
app/
|
||||
application.config.ts # Obbligatorio - configurazione principale dell'applicazione
|
||||
default-function.role.ts # Ruolo predefinito per le funzioni serverless
|
||||
// le tue entità (*.object.ts, *.function.ts, *.role.ts)
|
||||
utils/ # Opzionale - implementazioni degli handler e utility
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
hello-world.function.ts # Example serverless function
|
||||
hello-world.front-component.tsx # Example front component
|
||||
// your entities (*.object.ts, *.function.ts, *.front-component.tsx, *.role.ts)
|
||||
```
|
||||
|
||||
### Convenzioni invece della configurazione
|
||||
|
||||
Le applicazioni usano un approccio basato sulle **convenzioni invece della configurazione** in cui le entità vengono rilevate in base al suffisso del file. Questo consente un'organizzazione flessibile all'interno della cartella `src/app/`:
|
||||
|
||||
| Suffisso del file | Tipo di entità |
|
||||
| ----------------- | ------------------------------------- |
|
||||
| `*.object.ts` | Definizioni di oggetti personalizzati |
|
||||
| `*.function.ts` | Definizioni di funzioni serverless |
|
||||
| `*.role.ts` | Definizioni di ruoli |
|
||||
| Suffisso del file | Tipo di entità |
|
||||
| ----------------------- | ------------------------------------- |
|
||||
| `*.object.ts` | Definizioni di oggetti personalizzati |
|
||||
| `*.function.ts` | Definizioni di funzioni serverless |
|
||||
| `*.front-component.tsx` | Front component definitions |
|
||||
| `*.role.ts` | Definizioni di ruoli |
|
||||
|
||||
### Organizzazioni di cartelle supportate
|
||||
|
||||
@@ -121,12 +119,14 @@ Puoi organizzare le tue entità in uno qualsiasi di questi modelli:
|
||||
**Tradizionale (per tipo):**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── objects/
|
||||
│ └── postCard.object.ts
|
||||
├── functions/
|
||||
│ └── createPostCard.function.ts
|
||||
├── components/
|
||||
│ └── card.front-component.tsx
|
||||
└── roles/
|
||||
└── admin.role.ts
|
||||
```
|
||||
@@ -134,44 +134,45 @@ src/app/
|
||||
**Per funzionalità:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
└── post-card/
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── postCardAdmin.role.ts
|
||||
```
|
||||
|
||||
**Struttura piatta:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── admin.role.ts
|
||||
```
|
||||
|
||||
A livello generale:
|
||||
|
||||
* **package.json**: Dichiara il nome dell'app, la versione, i motori (Node 24+, Yarn 4) e aggiunge `twenty-sdk`, oltre a script come `dev`, `sync`, `generate`, `create-entity`, `logs`, `uninstall` e `auth` che delegano alla CLI locale `twenty`.
|
||||
* **package.json**: Declares the app name, version, engines (Node 24+, Yarn 4), and adds `twenty-sdk` plus scripts like `app:dev`, `app:generate`, `entity:add`, `function:logs`, `function:execute`, `app:uninstall`, and `auth:login` that delegate to the local `twenty` CLI.
|
||||
* **.gitignore**: Ignora i file generati comuni come `node_modules`, `.yarn`, `generated/` (client tipizzato), `dist/`, `build/`, cartelle di coverage, file di log e file `.env*`.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Bloccano e configurano la toolchain Yarn 4 utilizzata dal progetto.
|
||||
* **.nvmrc**: Fissa la versione di Node.js prevista dal progetto.
|
||||
* **eslint.config.mjs** e **tsconfig.json**: Forniscono linting e configurazione TypeScript per i sorgenti TypeScript della tua app.
|
||||
* **README.md**: Un breve README nella radice dell'app con istruzioni di base.
|
||||
* **src/app/**: Il luogo principale in cui definisci la tua applicazione come codice:
|
||||
* **src/**: The main place where you define your application-as-code:
|
||||
* `application.config.ts`: Configurazione globale della tua app (metadati e collegamenti di runtime). Vedi "Configurazione dell'applicazione" qui sotto.
|
||||
* `*.role.ts`: Definizioni di ruoli usate dalle tue funzioni serverless. Vedi "Ruolo funzione predefinito" qui sotto.
|
||||
* `*.object.ts`: Definizioni di oggetti personalizzati.
|
||||
* `*.function.ts`: Definizioni di funzioni serverless.
|
||||
* **src/utils/**: Cartella opzionale per le implementazioni degli handler e le utility.
|
||||
* `*.front-component.tsx`: Front component definitions.
|
||||
|
||||
Comandi successivi aggiungeranno altri file e cartelle:
|
||||
|
||||
* `yarn app:generate` creerà una cartella `generated/` (client Twenty tipizzato + tipi dello spazio di lavoro).
|
||||
* `yarn app:create-entity` aggiungerà file di definizione delle entità sotto `src/app/` per i tuoi oggetti, funzioni o ruoli personalizzati.
|
||||
l
|
||||
* `yarn entity:add` will add entity definition files under `src/` for your custom objects, functions, front components, or roles.
|
||||
|
||||
## Autenticazione
|
||||
|
||||
@@ -302,63 +303,12 @@ Punti chiave:
|
||||
* Il `universalIdentifier` deve essere univoco e stabile tra i deployment.
|
||||
* Ogni campo richiede un `name`, `type`, `label` e il proprio `universalIdentifier` stabile.
|
||||
* L'array `fields` è facoltativo: puoi definire oggetti senza campi personalizzati.
|
||||
* Puoi generare nuovi oggetti con `yarn app:create-entity`, che ti guida nella denominazione, nei campi e nelle relazioni.
|
||||
* You can scaffold new objects using `yarn entity:add`, which guides you through naming, fields, and relationships.
|
||||
|
||||
<Note>
|
||||
**I campi base vengono creati automaticamente.** Quando definisci un oggetto personalizzato, Twenty aggiunge automaticamente i campi standard come `name`, `createdAt`, `updatedAt`, `createdBy`, `position` e `deletedAt`. Non è necessario definirli nel tuo array `fields` — aggiungi solo i tuoi campi personalizzati.
|
||||
</Note>
|
||||
|
||||
<Accordion title="Alternativa: sintassi basata sui decorator">
|
||||
Puoi anche definire oggetti utilizzando i decorator di TypeScript. Questo approccio utilizza una sintassi basata sulle classi con i decorator `@Object`, `@Field` e `@Relation`:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
type AddressField,
|
||||
Field,
|
||||
FieldType,
|
||||
type FullNameField,
|
||||
Object,
|
||||
OnDeleteAction,
|
||||
Relation,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { type Note } from '../../generated';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post card',
|
||||
labelPlural: 'Post cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
export class PostCard {
|
||||
@Field({
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Relation({
|
||||
universalIdentifier: 'c9e2b4f4-b9ad-4427-9b42-9971b785edfe',
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
label: 'Notes',
|
||||
icon: 'IconComment',
|
||||
inverseSideTargetUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
onDelete: OnDeleteAction.CASCADE,
|
||||
})
|
||||
notes: Note[];
|
||||
}
|
||||
```
|
||||
|
||||
Nota: L'approccio con i decorator richiede `experimentalDecorators` nella configurazione di TypeScript.
|
||||
</Accordion>
|
||||
|
||||
### Configurazione dell'applicazione (application.config.ts)
|
||||
|
||||
Ogni app ha un singolo file `application.config.ts` che descrive:
|
||||
@@ -469,14 +419,9 @@ Ogni file di funzione usa `defineFunction()` per esportare una configurazione co
|
||||
// src/app/createPostCard.function.ts
|
||||
import { defineFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
import Twenty, { type Person } from '~/generated';
|
||||
|
||||
const handler = async (
|
||||
params:
|
||||
| RoutePayload
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload,
|
||||
) => {
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new Twenty(); // generated typed client
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
@@ -507,18 +452,18 @@ export default defineFunction({
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
{
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
type: 'cron',
|
||||
pattern: '0 0 1 1 *',
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
{
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
type: 'databaseEvent',
|
||||
eventName: 'person.updated',
|
||||
updatedFields: ['name'],
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -633,7 +578,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Puoi creare nuove funzioni in due modi:
|
||||
|
||||
* **Generata dallo scaffolder**: Esegui `yarn app:create-entity` e scegli l'opzione per aggiungere una nuova funzione. Questo genera un file iniziale con un handler e una configurazione.
|
||||
* **Scaffolded**: Run `yarn entity:add` and choose the option to add a new function. Questo genera un file iniziale con un handler e una configurazione.
|
||||
* **Manuale**: Crea un nuovo file `*.function.ts` e usa `defineFunction()`, seguendo lo stesso schema.
|
||||
|
||||
### Client tipizzato generato
|
||||
@@ -641,13 +586,13 @@ Puoi creare nuove funzioni in due modi:
|
||||
Esegui yarn app:generate per creare un client tipizzato locale in generated/ basato sullo schema del tuo spazio di lavoro. Usalo nelle tue funzioni:
|
||||
|
||||
```typescript
|
||||
import Twenty from './generated';
|
||||
import Twenty from '~/generated';
|
||||
|
||||
const client = new Twenty();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
```
|
||||
|
||||
Il client viene rigenerato da `yarn app:generate`. Eseguilo nuovamente dopo aver modificato i tuoi oggetti e aver eseguito `yarn app:sync`, oppure quando effettui l'onboarding su un nuovo spazio di lavoro.
|
||||
Il client viene rigenerato da `yarn app:generate`. Re-run after changing your objects or when onboarding to a new workspace.
|
||||
|
||||
#### Credenziali di runtime nelle funzioni serverless
|
||||
|
||||
@@ -679,25 +624,29 @@ Quindi aggiungi script come questi:
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"auth": "twenty auth login",
|
||||
"generate": "twenty app generate",
|
||||
"dev": "twenty app dev",
|
||||
"sync": "twenty app sync",
|
||||
"uninstall": "twenty app uninstall",
|
||||
"logs": "twenty app logs",
|
||||
"create-entity": "twenty app add",
|
||||
"help": "twenty --help"
|
||||
"auth:login": "twenty auth:login",
|
||||
"auth:logout": "twenty auth:logout",
|
||||
"auth:status": "twenty auth:status",
|
||||
"auth:switch": "twenty auth:switch",
|
||||
"auth:list": "twenty auth:list",
|
||||
"app:dev": "twenty app:dev",
|
||||
"app:generate": "twenty app:generate",
|
||||
"app:uninstall": "twenty app:uninstall",
|
||||
"entity:add": "twenty entity:add",
|
||||
"function:logs": "twenty function:logs",
|
||||
"function:execute": "twenty function:execute",
|
||||
"help": "twenty help"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Ora puoi eseguire gli stessi comandi tramite Yarn, ad esempio `yarn app:dev`, `yarn app:sync`, ecc.
|
||||
Now you can run the same commands via Yarn, e.g. `yarn app:dev`, `yarn app:generate`, etc.
|
||||
|
||||
## Risoluzione dei problemi
|
||||
|
||||
* Errori di autenticazione: esegui `yarn auth:login` e assicurati che la tua chiave API abbia i permessi richiesti.
|
||||
* Impossibile connettersi al server: verifica l'URL dell'API e che il server Twenty sia raggiungibile.
|
||||
* Tipi o client mancanti/obsoleti: esegui `yarn app:generate` e poi `yarn app:dev`.
|
||||
* Types or client missing/outdated: run `yarn app:generate`.
|
||||
* Modalità di sviluppo non in sincronizzazione: assicurati che `yarn app:dev` sia in esecuzione e che le modifiche non vengano ignorate dal tuo ambiente.
|
||||
|
||||
Canale di supporto su Discord: https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
|
||||
@@ -49,26 +49,23 @@ yarn app:dev
|
||||
そこで次のことができます:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# アプリケーションに新しいエンティティを追加(ガイド付き)
|
||||
yarn app:create-entity
|
||||
# Add a new entity to your application (guided)
|
||||
yarn entity:add
|
||||
|
||||
# 型付きの Twenty クライアントとワークスペースのエンティティ型を生成
|
||||
# Generate a typed Twenty client and workspace entity types
|
||||
yarn app:generate
|
||||
|
||||
# 1回限りの同期を実行(ウォッチモードの代わり)
|
||||
yarn app:sync
|
||||
|
||||
# アプリケーションの関数のログを監視
|
||||
# Watch your application's function logs
|
||||
yarn function:logs
|
||||
|
||||
# 名前で関数を実行
|
||||
yarn function:execute -n my-function -p '{\"name\": \"test\"}'
|
||||
# Execute a function by name
|
||||
yarn function:execute -n my-function -p '{"name": "test"}'
|
||||
|
||||
# 現在のワークスペースからアプリケーションをアンインストール
|
||||
# Uninstall the application from the current workspace
|
||||
yarn app:uninstall
|
||||
|
||||
# コマンドのヘルプを表示
|
||||
yarn app:help
|
||||
# Display commands' help
|
||||
yarn help
|
||||
```
|
||||
|
||||
参考: [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) および [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk) の CLI リファレンスページをご覧ください。
|
||||
@@ -97,22 +94,23 @@ my-twenty-app/
|
||||
tsconfig.json
|
||||
README.md
|
||||
src/
|
||||
app/
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
// your entities (*.object.ts, *.function.ts, *.role.ts)
|
||||
utils/ # Optional - handler implementations & utilities
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
hello-world.function.ts # Example serverless function
|
||||
hello-world.front-component.tsx # Example front component
|
||||
// your entities (*.object.ts, *.function.ts, *.front-component.tsx, *.role.ts)
|
||||
```
|
||||
|
||||
### コンベンション優先
|
||||
|
||||
アプリケーションは **コンベンション優先(設定より規約)** のアプローチを採用し、エンティティはファイルのサフィックスで検出されます。 これにより、`src/app/` フォルダー内を柔軟に構成できます:
|
||||
|
||||
| ファイルサフィックス | エンティティタイプ |
|
||||
| --------------- | ------------- |
|
||||
| `*.object.ts` | カスタムオブジェクトの定義 |
|
||||
| `*.function.ts` | サーバーレス関数の定義 |
|
||||
| `*.role.ts` | ロールの定義 |
|
||||
| ファイルサフィックス | エンティティタイプ |
|
||||
| ----------------------- | --------------------------- |
|
||||
| `*.object.ts` | カスタムオブジェクトの定義 |
|
||||
| `*.function.ts` | サーバーレス関数の定義 |
|
||||
| `*.front-component.tsx` | Front component definitions |
|
||||
| `*.role.ts` | ロールの定義 |
|
||||
|
||||
### サポートされるフォルダー構成
|
||||
|
||||
@@ -121,12 +119,14 @@ my-twenty-app/
|
||||
**従来型(タイプ別):**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── objects/
|
||||
│ └── postCard.object.ts
|
||||
├── functions/
|
||||
│ └── createPostCard.function.ts
|
||||
├── components/
|
||||
│ └── card.front-component.tsx
|
||||
└── roles/
|
||||
└── admin.role.ts
|
||||
```
|
||||
@@ -134,44 +134,45 @@ src/app/
|
||||
**機能単位:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
└── post-card/
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── postCardAdmin.role.ts
|
||||
```
|
||||
|
||||
**フラット:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── admin.role.ts
|
||||
```
|
||||
|
||||
概要:
|
||||
|
||||
* **package.json**: アプリ名、バージョン、エンジン(Node 24+、Yarn 4)を宣言し、`twenty-sdk` と、`dev`、`sync`、`generate`、`create-entity`、`logs`、`uninstall`、`auth` などのスクリプトを追加します。これらはローカルの `twenty` CLI に委譲されます。
|
||||
* **package.json**: Declares the app name, version, engines (Node 24+, Yarn 4), and adds `twenty-sdk` plus scripts like `app:dev`, `app:generate`, `entity:add`, `function:logs`, `function:execute`, `app:uninstall`, and `auth:login` that delegate to the local `twenty` CLI.
|
||||
* **.gitignore**: `node_modules`、`.yarn`、`generated/`(型付きクライアント)、`dist/`、`build/`、カバレッジ用フォルダー、ログファイル、`.env*` ファイルなどの一般的な生成物を無視します。
|
||||
* **yarn.lock**、**.yarnrc.yml**、**.yarn/**: プロジェクトで使用する Yarn 4 ツールチェーンをロックおよび構成します。
|
||||
* **.nvmrc**: プロジェクトで想定する Node.js バージョンを固定します。
|
||||
* **eslint.config.mjs** と **tsconfig.json**: アプリの TypeScript ソース向けの Lint と TypeScript 設定を提供します。
|
||||
* **README.md**: アプリのルートにある、基本的な手順を記した短い README。
|
||||
* **src/app/**: アプリケーションをコードとして定義する主な場所:
|
||||
* **src/**: The main place where you define your application-as-code:
|
||||
* `application.config.ts`: アプリのグローバル設定(メタデータとランタイムの接続)。 「アプリケーション設定」を参照してください。
|
||||
* `*.role.ts`: サーバーレス関数で使用するロール定義。 「デフォルトの関数ロール」を参照してください。
|
||||
* `*.object.ts`: カスタムオブジェクトの定義。
|
||||
* `*.function.ts`: サーバーレス関数の定義。
|
||||
* **src/utils/**: ハンドラーの実装やユーティリティ用の任意フォルダー。
|
||||
* `*.front-component.tsx`: Front component definitions.
|
||||
|
||||
後続のコマンドにより、さらにファイルやフォルダーが追加されます:
|
||||
|
||||
* `yarn app:generate` は `generated/` フォルダー(型付きの Twenty クライアント + ワークスペースの型)を作成します。
|
||||
* `yarn app:create-entity` は、カスタムオブジェクト、関数、ロール用のエンティティ定義ファイルを `src/app/` 配下に追加します。
|
||||
l
|
||||
* `yarn entity:add` will add entity definition files under `src/` for your custom objects, functions, front components, or roles.
|
||||
|
||||
## 認証
|
||||
|
||||
@@ -302,63 +303,12 @@ export default defineObject({
|
||||
* `universalIdentifier` は、デプロイをまたいで一意かつ安定している必要があります。
|
||||
* 各フィールドには、`name`、`type`、`label`、および自身の安定した `universalIdentifier` が必要です。
|
||||
* `fields` 配列は任意です。カスタムフィールドなしでオブジェクトを定義できます。
|
||||
* `yarn app:create-entity` を使用すれば、新しいオブジェクトをスキャフォルドできます。名前、フィールド、リレーションシップの設定がガイドされます。
|
||||
* You can scaffold new objects using `yarn entity:add`, which guides you through naming, fields, and relationships.
|
||||
|
||||
<Note>
|
||||
**ベースフィールドは自動作成されます。** カスタムオブジェクトを定義すると、Twenty は `name`、`createdAt`、`updatedAt`、`createdBy`、`position`、`deletedAt` などの標準フィールドを自動的に追加します。 これらを `fields` 配列で定義する必要はありません。カスタムフィールドのみを追加してください。
|
||||
</Note>
|
||||
|
||||
<Accordion title="代替: デコレーター ベースの構文">
|
||||
TypeScript のデコレーターを使ってオブジェクトを定義することもできます。 この方法では、`@Object`、`@Field`、`@Relation` デコレーターを用いたクラスベースの構文を使用します:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
type AddressField,
|
||||
Field,
|
||||
FieldType,
|
||||
type FullNameField,
|
||||
Object,
|
||||
OnDeleteAction,
|
||||
Relation,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { type Note } from '../../generated';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post card',
|
||||
labelPlural: 'Post cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
export class PostCard {
|
||||
@Field({
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Relation({
|
||||
universalIdentifier: 'c9e2b4f4-b9ad-4427-9b42-9971b785edfe',
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
label: 'Notes',
|
||||
icon: 'IconComment',
|
||||
inverseSideTargetUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
onDelete: OnDeleteAction.CASCADE,
|
||||
})
|
||||
notes: Note[];
|
||||
}
|
||||
```
|
||||
|
||||
注記: デコレーター方式では、TypeScript 設定で `experimentalDecorators` が必要です。
|
||||
</Accordion>
|
||||
|
||||
### アプリケーション設定(application.config.ts)
|
||||
|
||||
すべてのアプリには、次の内容を記述する単一の `application.config.ts` ファイルがあります:
|
||||
@@ -469,14 +419,9 @@ export default defineRole({
|
||||
// src/app/createPostCard.function.ts
|
||||
import { defineFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
import Twenty, { type Person } from '~/generated';
|
||||
|
||||
const handler = async (
|
||||
params:
|
||||
| RoutePayload
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload,
|
||||
) => {
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new Twenty(); // generated typed client
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
@@ -507,18 +452,18 @@ export default defineFunction({
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
{
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
type: 'cron',
|
||||
pattern: '0 0 1 1 *',
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
{
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
type: 'databaseEvent',
|
||||
eventName: 'person.updated',
|
||||
updatedFields: ['name'],
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -633,7 +578,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
新しい関数は次の 2 通りで作成できます:
|
||||
|
||||
* **スキャフォルド**: `yarn app:create-entity` を実行し、新しい関数を追加するオプションを選択します。 これにより、ハンドラーと設定を備えたスターターファイルが生成されます。
|
||||
* **Scaffolded**: Run `yarn entity:add` and choose the option to add a new function. これにより、ハンドラーと設定を備えたスターターファイルが生成されます。
|
||||
* **手動**: 新しい `*.function.ts` ファイルを作成し、同じパターンで `defineFunction()` を使用します。
|
||||
|
||||
### 生成された型付きクライアント
|
||||
@@ -641,13 +586,13 @@ const handler = async (event: RoutePayload) => {
|
||||
ワークスペースのスキーマに基づき、generated/ にローカルの型付きクライアントを作成するには yarn app:generate を実行します。 関数内で使用します:
|
||||
|
||||
```typescript
|
||||
import Twenty from './generated';
|
||||
import Twenty from '~/generated';
|
||||
|
||||
const client = new Twenty();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
```
|
||||
|
||||
このクライアントは `yarn app:generate` によって再生成されます。 オブジェクトを変更して `yarn app:sync` した後、または新しいワークスペースにオンボードする際には再実行してください。
|
||||
このクライアントは `yarn app:generate` によって再生成されます。 Re-run after changing your objects or when onboarding to a new workspace.
|
||||
|
||||
#### サーバーレス関数における実行時認証情報
|
||||
|
||||
@@ -679,25 +624,29 @@ yarn add -D twenty-sdk
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"auth": "twenty auth login",
|
||||
"generate": "twenty app generate",
|
||||
"dev": "twenty app dev",
|
||||
"sync": "twenty app sync",
|
||||
"uninstall": "twenty app uninstall",
|
||||
"logs": "twenty app logs",
|
||||
"create-entity": "twenty app add",
|
||||
"help": "twenty --help"
|
||||
"auth:login": "twenty auth:login",
|
||||
"auth:logout": "twenty auth:logout",
|
||||
"auth:status": "twenty auth:status",
|
||||
"auth:switch": "twenty auth:switch",
|
||||
"auth:list": "twenty auth:list",
|
||||
"app:dev": "twenty app:dev",
|
||||
"app:generate": "twenty app:generate",
|
||||
"app:uninstall": "twenty app:uninstall",
|
||||
"entity:add": "twenty entity:add",
|
||||
"function:logs": "twenty function:logs",
|
||||
"function:execute": "twenty function:execute",
|
||||
"help": "twenty help"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
これで Yarn 経由で同じコマンド(例:`yarn app:dev`、`yarn app:sync` など)を実行できます。
|
||||
Now you can run the same commands via Yarn, e.g. `yarn app:dev`, `yarn app:generate`, etc.
|
||||
|
||||
## トラブルシューティング
|
||||
|
||||
* 認証エラー: `yarn auth:login` を実行し、API キーに必要な権限があることを確認してください。
|
||||
* サーバーに接続できません: API URL と、Twenty サーバーに到達可能であることを確認してください。
|
||||
* 型やクライアントがない/古い: `yarn app:generate` を実行してから `yarn app:dev` を実行してください。
|
||||
* Types or client missing/outdated: run `yarn app:generate`.
|
||||
* 開発モードで同期されない: `yarn app:dev` が実行中であり、環境によって変更が無視されていないことを確認してください。
|
||||
|
||||
Discord ヘルプチャンネル: https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
|
||||
@@ -50,15 +50,12 @@ yarn app:dev
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new entity to your application (guided)
|
||||
yarn app:create-entity
|
||||
yarn entity:add
|
||||
|
||||
# Generate a typed Twenty client and workspace entity types
|
||||
yarn app:generate
|
||||
|
||||
# Run a one‑time sync (instead of watch mode)
|
||||
yarn app:sync
|
||||
|
||||
# Watch your application's functions logs
|
||||
# Watch your application's function logs
|
||||
yarn function:logs
|
||||
|
||||
# Execute a function by name
|
||||
@@ -68,7 +65,7 @@ yarn function:execute -n my-function -p '{"name": "test"}'
|
||||
yarn app:uninstall
|
||||
|
||||
# Display commands' help
|
||||
yarn app:help
|
||||
yarn help
|
||||
```
|
||||
|
||||
참고: [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) 및 [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk)의 CLI 참고 페이지도 확인하세요.
|
||||
@@ -97,22 +94,23 @@ my-twenty-app/
|
||||
tsconfig.json
|
||||
README.md
|
||||
src/
|
||||
app/
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
// your entities (*.object.ts, *.function.ts, *.role.ts)
|
||||
utils/ # Optional - handler implementations & utilities
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
hello-world.function.ts # Example serverless function
|
||||
hello-world.front-component.tsx # Example front component
|
||||
// your entities (*.object.ts, *.function.ts, *.front-component.tsx, *.role.ts)
|
||||
```
|
||||
|
||||
### 설정보다 관례
|
||||
|
||||
애플리케이션은 파일 접미사로 엔티티를 감지하는 **관례 우선** 접근 방식을 사용합니다. 이를 통해 `src/app/` 폴더 내에서 유연하게 구성할 수 있습니다:
|
||||
|
||||
| 파일 접미사 | 엔티티 유형 |
|
||||
| --------------- | ------------ |
|
||||
| `*.object.ts` | 사용자 정의 객체 정의 |
|
||||
| `*.function.ts` | 서버리스 함수 정의 |
|
||||
| `*.role.ts` | 역할 정의 |
|
||||
| 파일 접미사 | 엔티티 유형 |
|
||||
| ----------------------- | --------------------------- |
|
||||
| `*.object.ts` | 사용자 정의 객체 정의 |
|
||||
| `*.function.ts` | 서버리스 함수 정의 |
|
||||
| `*.front-component.tsx` | Front component definitions |
|
||||
| `*.role.ts` | 역할 정의 |
|
||||
|
||||
### 지원되는 폴더 구성 방식
|
||||
|
||||
@@ -121,12 +119,14 @@ my-twenty-app/
|
||||
**전통적(유형별):**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── objects/
|
||||
│ └── postCard.object.ts
|
||||
├── functions/
|
||||
│ └── createPostCard.function.ts
|
||||
├── components/
|
||||
│ └── card.front-component.tsx
|
||||
└── roles/
|
||||
└── admin.role.ts
|
||||
```
|
||||
@@ -134,44 +134,45 @@ src/app/
|
||||
**기능 기반:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
└── post-card/
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── postCardAdmin.role.ts
|
||||
```
|
||||
|
||||
**플랫:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── admin.role.ts
|
||||
```
|
||||
|
||||
개요:
|
||||
|
||||
* **package.json**: 앱 이름, 버전, 엔진(Node 24+, Yarn 4)을 선언하고, `twenty-sdk`와 함께 `dev`, `sync`, `generate`, `create-entity`, `logs`, `uninstall`, `auth` 같은 스크립트를 추가합니다. 이 스크립트들은 로컬 `twenty` CLI에 위임됩니다.
|
||||
* **package.json**: Declares the app name, version, engines (Node 24+, Yarn 4), and adds `twenty-sdk` plus scripts like `app:dev`, `app:generate`, `entity:add`, `function:logs`, `function:execute`, `app:uninstall`, and `auth:login` that delegate to the local `twenty` CLI.
|
||||
* **.gitignore**: `node_modules`, `.yarn`, `generated/`(타입드 클라이언트), `dist/`, `build/`, 커버리지 폴더, 로그 파일, `.env*` 파일 등의 일반 산출물을 무시합니다.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: 프로젝트에서 사용하는 Yarn 4 툴체인을 고정하고 구성합니다.
|
||||
* **.nvmrc**: 프로젝트에서 예상하는 Node.js 버전을 고정합니다.
|
||||
* **eslint.config.mjs** 및 **tsconfig.json**: 앱의 TypeScript 소스에 대한 린팅 및 TypeScript 구성을 제공합니다.
|
||||
* **README.md**: 앱 루트에 기본 안내를 담은 간단한 README입니다.
|
||||
* **src/app/**: 애플리케이션을 코드로 정의하는 주요 위치:
|
||||
* **src/**: The main place where you define your application-as-code:
|
||||
* `application.config.ts`: 앱의 전역 구성(메타데이터 및 런타임 연결)입니다. 아래의 "Application config"를 참조하세요.
|
||||
* `*.role.ts`: 서버리스 함수에서 사용하는 역할 정의. 아래의 "Default function role"을 참조하세요.
|
||||
* `*.object.ts`: 사용자 정의 객체 정의.
|
||||
* `*.function.ts`: 서버리스 함수 정의.
|
||||
* **src/utils/**: 핸들러 구현 및 유틸리티를 위한 선택적 폴더.
|
||||
* `*.front-component.tsx`: Front component definitions.
|
||||
|
||||
이후 명령을 실행하면 더 많은 파일과 폴더가 추가됩니다:
|
||||
|
||||
* `yarn app:generate`는 `generated/` 폴더를 생성합니다(타입드 Twenty 클라이언트 + 워크스페이스 타입).
|
||||
* `yarn app:create-entity`는 사용자 정의 객체, 함수, 역할에 대한 엔티티 정의 파일을 `src/app/` 아래에 추가합니다.
|
||||
l
|
||||
* `yarn entity:add` will add entity definition files under `src/` for your custom objects, functions, front components, or roles.
|
||||
|
||||
## 인증
|
||||
|
||||
@@ -302,63 +303,12 @@ export default defineObject({
|
||||
* `universalIdentifier`는 배포 전반에서 고유하고 안정적이어야 합니다.
|
||||
* 각 필드는 `name`, `type`, `label` 및 고유하고 안정적인 `universalIdentifier`가 필요합니다.
|
||||
* `fields` 배열은 선택 사항입니다. 사용자 정의 필드 없이도 객체를 정의할 수 있습니다.
|
||||
* `yarn app:create-entity`를 사용하여 새 객체를 스캐폴딩할 수 있으며, 이름, 필드, 관계 설정 과정을 안내합니다.
|
||||
* You can scaffold new objects using `yarn entity:add`, which guides you through naming, fields, and relationships.
|
||||
|
||||
<Note>
|
||||
**기본 필드는 자동으로 생성됩니다.** 사용자 정의 객체를 정의하면 Twenty가 `name`, `createdAt`, `updatedAt`, `createdBy`, `position`, `deletedAt` 등의 표준 필드를 자동으로 추가합니다. 이 필드들은 `fields` 배열에 정의할 필요가 없습니다. 사용자 정의 필드만 추가하세요.
|
||||
</Note>
|
||||
|
||||
<Accordion title="대안: 데코레이터 기반 문법">
|
||||
TypeScript 데코레이터를 사용하여 객체를 정의할 수도 있습니다. 이 접근 방식은 `@Object`, `@Field`, `@Relation` 데코레이터를 사용하는 클래스 기반 문법을 사용합니다:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
type AddressField,
|
||||
Field,
|
||||
FieldType,
|
||||
type FullNameField,
|
||||
Object,
|
||||
OnDeleteAction,
|
||||
Relation,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { type Note } from '../../generated';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post card',
|
||||
labelPlural: 'Post cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
export class PostCard {
|
||||
@Field({
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Relation({
|
||||
universalIdentifier: 'c9e2b4f4-b9ad-4427-9b42-9971b785edfe',
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
label: 'Notes',
|
||||
icon: 'IconComment',
|
||||
inverseSideTargetUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
onDelete: OnDeleteAction.CASCADE,
|
||||
})
|
||||
notes: Note[];
|
||||
}
|
||||
```
|
||||
|
||||
참고: 데코레이터 접근 방식은 TypeScript 구성에서 `experimentalDecorators`가 필요합니다.
|
||||
</Accordion>
|
||||
|
||||
### 애플리케이션 구성(application.config.ts)
|
||||
|
||||
모든 앱에는 다음을 설명하는 단일 `application.config.ts` 파일이 있습니다:
|
||||
@@ -469,14 +419,9 @@ export default defineRole({
|
||||
// src/app/createPostCard.function.ts
|
||||
import { defineFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
import Twenty, { type Person } from '~/generated';
|
||||
|
||||
const handler = async (
|
||||
params:
|
||||
| RoutePayload
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload,
|
||||
) => {
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new Twenty(); // generated typed client
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
@@ -507,18 +452,18 @@ export default defineFunction({
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
{
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
type: 'cron',
|
||||
pattern: '0 0 1 1 *',
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
{
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
type: 'databaseEvent',
|
||||
eventName: 'person.updated',
|
||||
updatedFields: ['name'],
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -633,7 +578,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
새 함수를 만드는 방법은 두 가지입니다:
|
||||
|
||||
* **스캐폴딩**: `yarn app:create-entity`를 실행하고 새 함수를 추가하는 옵션을 선택하세요. 이렇게 하면 핸들러와 구성이 포함된 시작 파일이 생성됩니다.
|
||||
* **Scaffolded**: Run `yarn entity:add` and choose the option to add a new function. 이렇게 하면 핸들러와 구성이 포함된 시작 파일이 생성됩니다.
|
||||
* **수동**: 새 `*.function.ts` 파일을 만들고 동일한 패턴에 따라 `defineFunction()`을 사용하세요.
|
||||
|
||||
### 생성된 타입드 클라이언트
|
||||
@@ -641,13 +586,13 @@ const handler = async (event: RoutePayload) => {
|
||||
워크스페이스 스키마를 기반으로 generated/에 로컬 타입드 클라이언트를 생성하려면 yarn app:generate를 실행하세요. 함수에서 사용하세요:
|
||||
|
||||
```typescript
|
||||
import Twenty from './generated';
|
||||
import Twenty from '~/generated';
|
||||
|
||||
const client = new Twenty();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
```
|
||||
|
||||
클라이언트는 `yarn app:generate`로 다시 생성됩니다. 객체를 변경하고 `yarn app:sync`를 실행한 후 또는 새 워크스페이스에 온보딩할 때 다시 실행하세요.
|
||||
클라이언트는 `yarn app:generate`로 다시 생성됩니다. Re-run after changing your objects or when onboarding to a new workspace.
|
||||
|
||||
#### 서버리스 함수의 런타임 자격 증명
|
||||
|
||||
@@ -679,25 +624,29 @@ yarn add -D twenty-sdk
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"auth": "twenty auth login",
|
||||
"generate": "twenty app generate",
|
||||
"dev": "twenty app dev",
|
||||
"sync": "twenty app sync",
|
||||
"uninstall": "twenty app uninstall",
|
||||
"logs": "twenty app logs",
|
||||
"create-entity": "twenty app add",
|
||||
"help": "twenty --help"
|
||||
"auth:login": "twenty auth:login",
|
||||
"auth:logout": "twenty auth:logout",
|
||||
"auth:status": "twenty auth:status",
|
||||
"auth:switch": "twenty auth:switch",
|
||||
"auth:list": "twenty auth:list",
|
||||
"app:dev": "twenty app:dev",
|
||||
"app:generate": "twenty app:generate",
|
||||
"app:uninstall": "twenty app:uninstall",
|
||||
"entity:add": "twenty entity:add",
|
||||
"function:logs": "twenty function:logs",
|
||||
"function:execute": "twenty function:execute",
|
||||
"help": "twenty help"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
이제 Yarn을 통해 동일한 명령을 실행할 수 있습니다. 예: `yarn app:dev`, `yarn app:sync` 등
|
||||
Now you can run the same commands via Yarn, e.g. `yarn app:dev`, `yarn app:generate`, etc.
|
||||
|
||||
## 문제 해결
|
||||
|
||||
* 인증 오류: `yarn auth:login`를 실행하고 API 키에 필요한 권한이 있는지 확인하세요.
|
||||
* 서버에 연결할 수 없음: API URL과 Twenty 서버에 접근 가능한지 확인하세요.
|
||||
* 타입 또는 클라이언트가 없거나 오래됨: `yarn app:generate`를 실행한 다음 `yarn app:dev`를 실행하세요.
|
||||
* Types or client missing/outdated: run `yarn app:generate`.
|
||||
* 개발 모드가 동기화되지 않음: `yarn app:dev`가 실행 중인지, 환경에서 변경 사항을 무시하지 않는지 확인하세요.
|
||||
|
||||
Discord 도움말 채널: https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
|
||||
@@ -49,26 +49,23 @@ yarn app:dev
|
||||
A partir daqui você pode:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Adicionar uma nova entidade à sua aplicação (assistido)
|
||||
yarn app:create-entity
|
||||
# Add a new entity to your application (guided)
|
||||
yarn entity:add
|
||||
|
||||
# Gerar um cliente Twenty tipado e tipos de entidades do espaço de trabalho
|
||||
# Generate a typed Twenty client and workspace entity types
|
||||
yarn app:generate
|
||||
|
||||
# Executar uma sincronização única (em vez do modo de monitoramento)
|
||||
yarn app:sync
|
||||
|
||||
# Acompanhar os logs das funções da sua aplicação
|
||||
# Watch your application's function logs
|
||||
yarn function:logs
|
||||
|
||||
# Executar uma função pelo nome
|
||||
# Execute a function by name
|
||||
yarn function:execute -n my-function -p '{"name": "test"}'
|
||||
|
||||
# Desinstalar a aplicação do espaço de trabalho atual
|
||||
# Uninstall the application from the current workspace
|
||||
yarn app:uninstall
|
||||
|
||||
# Exibir a ajuda dos comandos
|
||||
yarn app:help
|
||||
# Display commands' help
|
||||
yarn help
|
||||
```
|
||||
|
||||
Veja também: as páginas de referência da CLI para [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) e [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk).
|
||||
@@ -97,22 +94,23 @@ my-twenty-app/
|
||||
tsconfig.json
|
||||
README.md
|
||||
src/
|
||||
app/
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
// your entities (*.object.ts, *.function.ts, *.role.ts)
|
||||
utils/ # Optional - handler implementations & utilities
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
hello-world.function.ts # Example serverless function
|
||||
hello-world.front-component.tsx # Example front component
|
||||
// your entities (*.object.ts, *.function.ts, *.front-component.tsx, *.role.ts)
|
||||
```
|
||||
|
||||
### Convenção sobre configuração
|
||||
|
||||
Os aplicativos usam uma abordagem de **convenção sobre configuração** em que as entidades são detectadas pelo sufixo do arquivo. Isso permite organização flexível dentro da pasta `src/app/`:
|
||||
|
||||
| Sufixo de arquivo | Tipo de entidade |
|
||||
| ----------------- | ------------------------------------ |
|
||||
| `*.object.ts` | Definições de objetos personalizados |
|
||||
| `*.function.ts` | Definições de funções serverless |
|
||||
| `*.role.ts` | Definições de papéis |
|
||||
| Sufixo de arquivo | Tipo de entidade |
|
||||
| ----------------------- | ------------------------------------ |
|
||||
| `*.object.ts` | Definições de objetos personalizados |
|
||||
| `*.function.ts` | Definições de funções serverless |
|
||||
| `*.front-component.tsx` | Front component definitions |
|
||||
| `*.role.ts` | Definições de papéis |
|
||||
|
||||
### Organizações de pastas suportadas
|
||||
|
||||
@@ -121,12 +119,14 @@ Você pode organizar suas entidades em qualquer um destes padrões:
|
||||
**Tradicional (por tipo):**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── objects/
|
||||
│ └── postCard.object.ts
|
||||
├── functions/
|
||||
│ └── createPostCard.function.ts
|
||||
├── components/
|
||||
│ └── card.front-component.tsx
|
||||
└── roles/
|
||||
└── admin.role.ts
|
||||
```
|
||||
@@ -134,44 +134,45 @@ src/app/
|
||||
**Baseada em funcionalidades:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
└── post-card/
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── postCardAdmin.role.ts
|
||||
```
|
||||
|
||||
**Plana:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── admin.role.ts
|
||||
```
|
||||
|
||||
Em alto nível:
|
||||
|
||||
* **package.json**: Declara o nome do app, versão, engines (Node 24+, Yarn 4), e adiciona `twenty-sdk` além de scripts como `dev`, `sync`, `generate`, `create-entity`, `logs`, `uninstall` e `auth` que delegam para a CLI `twenty` local.
|
||||
* **package.json**: Declares the app name, version, engines (Node 24+, Yarn 4), and adds `twenty-sdk` plus scripts like `app:dev`, `app:generate`, `entity:add`, `function:logs`, `function:execute`, `app:uninstall`, and `auth:login` that delegate to the local `twenty` CLI.
|
||||
* **.gitignore**: Ignora artefatos comuns como `node_modules`, `.yarn`, `generated/` (cliente tipado), `dist/`, `build/`, pastas de cobertura, arquivos de log e arquivos `.env*`.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Bloqueiam e configuram a ferramenta Yarn 4 usada pelo projeto.
|
||||
* **.nvmrc**: Fixa a versão do Node.js esperada pelo projeto.
|
||||
* **eslint.config.mjs** e **tsconfig.json**: Fornecem lint e configuração do TypeScript para os fontes TypeScript do seu aplicativo.
|
||||
* **README.md**: Um README curto na raiz do aplicativo com instruções básicas.
|
||||
* **src/app/**: O local principal onde você define seu aplicativo como código:
|
||||
* **src/**: The main place where you define your application-as-code:
|
||||
* `application.config.ts`: Configuração global do seu aplicativo (metadados e conexões de execução). Veja "Configuração do aplicativo" abaixo.
|
||||
* `*.role.ts`: Definições de papéis usados pelas suas funções serverless. Veja "Papel de função padrão" abaixo.
|
||||
* `*.object.ts`: Definições de objetos personalizados.
|
||||
* `*.function.ts`: Definições de funções serverless.
|
||||
* **src/utils/**: Pasta opcional para implementações de handlers e utilitários.
|
||||
* `*.front-component.tsx`: Front component definitions.
|
||||
|
||||
Comandos posteriores adicionarão mais arquivos e pastas:
|
||||
|
||||
* `yarn app:generate` criará uma pasta `generated/` (cliente tipado do Twenty + tipos do workspace).
|
||||
* `yarn app:create-entity` adicionará arquivos de definição de entidades em `src/app/` para seus objetos, funções ou papéis personalizados.
|
||||
l
|
||||
* `yarn entity:add` will add entity definition files under `src/` for your custom objects, functions, front components, or roles.
|
||||
|
||||
## Autenticação
|
||||
|
||||
@@ -302,63 +303,12 @@ Pontos-chave:
|
||||
* O `universalIdentifier` deve ser exclusivo e estável entre implantações.
|
||||
* Cada campo requer `name`, `type`, `label` e seu próprio `universalIdentifier` estável.
|
||||
* O array `fields` é opcional — você pode definir objetos sem campos personalizados.
|
||||
* Você pode criar novos objetos usando `yarn app:create-entity`, que orienta você sobre nomeação, campos e relacionamentos.
|
||||
* You can scaffold new objects using `yarn entity:add`, which guides you through naming, fields, and relationships.
|
||||
|
||||
<Note>
|
||||
**Os campos base são criados automaticamente.** Quando você define um objeto personalizado, o Twenty adiciona automaticamente campos padrão como `name`, `createdAt`, `updatedAt`, `createdBy`, `position` e `deletedAt`. Você não precisa definir esses no seu array `fields` — adicione apenas seus campos personalizados.
|
||||
</Note>
|
||||
|
||||
<Accordion title="Alternativa: Sintaxe baseada em decoradores">
|
||||
Você também pode definir objetos usando decoradores do TypeScript. Essa abordagem usa sintaxe baseada em classe com os decoradores `@Object`, `@Field` e `@Relation`:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
type AddressField,
|
||||
Field,
|
||||
FieldType,
|
||||
type FullNameField,
|
||||
Object,
|
||||
OnDeleteAction,
|
||||
Relation,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { type Note } from '../../generated';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post card',
|
||||
labelPlural: 'Post cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
export class PostCard {
|
||||
@Field({
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Relation({
|
||||
universalIdentifier: 'c9e2b4f4-b9ad-4427-9b42-9971b785edfe',
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
label: 'Notes',
|
||||
icon: 'IconComment',
|
||||
inverseSideTargetUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
onDelete: OnDeleteAction.CASCADE,
|
||||
})
|
||||
notes: Note[];
|
||||
}
|
||||
```
|
||||
|
||||
Observação: A abordagem com decoradores requer `experimentalDecorators` na sua configuração do TypeScript.
|
||||
</Accordion>
|
||||
|
||||
### Configuração do aplicativo (application.config.ts)
|
||||
|
||||
Todo aplicativo tem um único arquivo `application.config.ts` que descreve:
|
||||
@@ -469,14 +419,9 @@ Cada arquivo de função usa `defineFunction()` para exportar uma configuração
|
||||
// src/app/createPostCard.function.ts
|
||||
import { defineFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
import Twenty, { type Person } from '~/generated';
|
||||
|
||||
const handler = async (
|
||||
params:
|
||||
| RoutePayload
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload,
|
||||
) => {
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new Twenty(); // generated typed client
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
@@ -507,18 +452,18 @@ export default defineFunction({
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
{
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
type: 'cron',
|
||||
pattern: '0 0 1 1 *',
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
{
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
type: 'databaseEvent',
|
||||
eventName: 'person.updated',
|
||||
updatedFields: ['name'],
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -633,7 +578,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Você pode criar novas funções de duas formas:
|
||||
|
||||
* **Gerado automaticamente**: Execute `yarn app:create-entity` e escolha a opção para adicionar uma nova função. Isso gera um arquivo inicial com um handler e configuração.
|
||||
* **Scaffolded**: Run `yarn entity:add` and choose the option to add a new function. Isso gera um arquivo inicial com um handler e configuração.
|
||||
* **Manual**: Crie um novo arquivo `*.function.ts` e use `defineFunction()`, seguindo o mesmo padrão.
|
||||
|
||||
### Cliente tipado gerado
|
||||
@@ -641,13 +586,13 @@ Você pode criar novas funções de duas formas:
|
||||
Execute yarn app:generate para criar um cliente tipado local em generated/ com base no esquema do seu workspace. Use-o em suas funções:
|
||||
|
||||
```typescript
|
||||
import Twenty from './generated';
|
||||
import Twenty from '~/generated';
|
||||
|
||||
const client = new Twenty();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
```
|
||||
|
||||
O cliente é regenerado pelo `yarn app:generate`. Execute novamente após alterar seus objetos e executar `yarn app:sync`, ou ao ingressar em um novo workspace.
|
||||
O cliente é regenerado pelo `yarn app:generate`. Re-run after changing your objects or when onboarding to a new workspace.
|
||||
|
||||
#### Credenciais em tempo de execução em funções serverless
|
||||
|
||||
@@ -679,25 +624,29 @@ Em seguida, adicione scripts como estes:
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"auth": "twenty auth login",
|
||||
"generate": "twenty app generate",
|
||||
"dev": "twenty app dev",
|
||||
"sync": "twenty app sync",
|
||||
"uninstall": "twenty app uninstall",
|
||||
"logs": "twenty app logs",
|
||||
"create-entity": "twenty app add",
|
||||
"help": "twenty --help"
|
||||
"auth:login": "twenty auth:login",
|
||||
"auth:logout": "twenty auth:logout",
|
||||
"auth:status": "twenty auth:status",
|
||||
"auth:switch": "twenty auth:switch",
|
||||
"auth:list": "twenty auth:list",
|
||||
"app:dev": "twenty app:dev",
|
||||
"app:generate": "twenty app:generate",
|
||||
"app:uninstall": "twenty app:uninstall",
|
||||
"entity:add": "twenty entity:add",
|
||||
"function:logs": "twenty function:logs",
|
||||
"function:execute": "twenty function:execute",
|
||||
"help": "twenty help"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Agora você pode executar os mesmos comandos via Yarn, por exemplo, `yarn app:dev`, `yarn app:sync`, etc.
|
||||
Now you can run the same commands via Yarn, e.g. `yarn app:dev`, `yarn app:generate`, etc.
|
||||
|
||||
## Resolução de Problemas
|
||||
|
||||
* Erros de autenticação: execute `yarn auth:login` e certifique-se de que sua chave de API tenha as permissões necessárias.
|
||||
* Não é possível conectar ao servidor: verifique a URL da API e se o servidor do Twenty está acessível.
|
||||
* Tipos ou cliente ausentes/desatualizados: execute `yarn app:generate` e depois `yarn app:dev`.
|
||||
* Types or client missing/outdated: run `yarn app:generate`.
|
||||
* Modo de desenvolvimento não sincronizando: certifique-se de que `yarn app:dev` esteja em execução e de que as alterações não estejam sendo ignoradas pelo seu ambiente.
|
||||
|
||||
Canal de ajuda no Discord: https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
|
||||
@@ -49,26 +49,23 @@ yarn app:dev
|
||||
De aici puteți:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new entity to your application (guided)
|
||||
yarn app:create-entity
|
||||
# Adaugă o entitate nouă în aplicația ta (ghidat)
|
||||
yarn entity:add
|
||||
|
||||
# Generate a typed Twenty client and workspace entity types
|
||||
# Generează un client Twenty tipat și tipurile de entități ale spațiului de lucru
|
||||
yarn app:generate
|
||||
|
||||
# Run a one‑time sync (instead of watch mode)
|
||||
yarn app:sync
|
||||
|
||||
# Watch your application's functions logs
|
||||
# Urmărește jurnalele funcțiilor aplicației tale
|
||||
yarn function:logs
|
||||
|
||||
# Execute a function by name
|
||||
# Execută o funcție după nume
|
||||
yarn function:execute -n my-function -p '{"name": "test"}'
|
||||
|
||||
# Uninstall the application from the current workspace
|
||||
# Dezinstalează aplicația din spațiul de lucru curent
|
||||
yarn app:uninstall
|
||||
|
||||
# Display commands' help
|
||||
yarn app:help},{
|
||||
# Afișează ajutorul pentru comenzi
|
||||
yarn help},{
|
||||
```
|
||||
|
||||
Consultați și: paginile de referință CLI pentru [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) și [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk).
|
||||
@@ -97,22 +94,23 @@ my-twenty-app/
|
||||
tsconfig.json
|
||||
README.md
|
||||
src/
|
||||
app/
|
||||
application.config.ts # Obligatoriu - configurația principală a aplicației
|
||||
default-function.role.ts # Rolul implicit pentru funcțiile serverless
|
||||
// entitățile tale (*.object.ts, *.function.ts, *.role.ts)
|
||||
utils/ # Opțional - implementări de handleri și utilitare
|
||||
application.config.ts # Obligatoriu - configurația principală a aplicației
|
||||
default-function.role.ts # Rolul implicit pentru funcțiile serverless
|
||||
hello-world.function.ts # Exemplu de funcție serverless
|
||||
hello-world.front-component.tsx # Exemplu de componentă de interfață
|
||||
// entitățile tale (*.object.ts, *.function.ts, *.front-component.tsx, *.role.ts)
|
||||
```
|
||||
|
||||
### Convenție în locul configurării
|
||||
|
||||
Aplicațiile folosesc o abordare bazată pe convenție în locul configurării, în care entitățile sunt detectate după sufixul fișierului. Aceasta permite o organizare flexibilă în folderul `src/app/`:
|
||||
|
||||
| Sufixul fișierului | Tipul entității |
|
||||
| ------------------ | ---------------------------------- |
|
||||
| `*.object.ts` | Definiții de obiecte personalizate |
|
||||
| `*.function.ts` | Definiții de funcții serverless |
|
||||
| `*.role.ts` | Definiții de rol |
|
||||
| Sufixul fișierului | Tipul entității |
|
||||
| ----------------------- | ---------------------------------------- |
|
||||
| `*.object.ts` | Definiții de obiecte personalizate |
|
||||
| `*.function.ts` | Definiții de funcții serverless |
|
||||
| `*.front-component.tsx` | Definiții ale componentelor de interfață |
|
||||
| `*.role.ts` | Definiții de rol |
|
||||
|
||||
### Structuri de foldere acceptate
|
||||
|
||||
@@ -121,12 +119,14 @@ Vă puteți organiza entitățile în oricare dintre aceste modele:
|
||||
**Tradițional (după tip):**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── objects/
|
||||
│ └── postCard.object.ts
|
||||
├── functions/
|
||||
│ └── createPostCard.function.ts
|
||||
├── components/
|
||||
│ └── card.front-component.tsx
|
||||
└── roles/
|
||||
└── admin.role.ts
|
||||
```
|
||||
@@ -134,44 +134,45 @@ src/app/
|
||||
**Bazat pe funcționalități:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
└── post-card/
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── postCardAdmin.role.ts
|
||||
```
|
||||
|
||||
**Plat:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── admin.role.ts
|
||||
```
|
||||
|
||||
Pe scurt:
|
||||
|
||||
* **package.json**: Declară numele aplicației, versiunea, motoarele (Node 24+, Yarn 4) și adaugă `twenty-sdk` plus scripturi precum `dev`, `sync`, `generate`, `create-entity`, `logs`, `uninstall` și `auth` care deleagă către CLI-ul local `twenty`.
|
||||
* **package.json**: Declares the app name, version, engines (Node 24+, Yarn 4), and adds `twenty-sdk` plus scripts like `app:dev`, `app:generate`, `entity:add`, `function:logs`, `function:execute`, `app:uninstall`, and `auth:login` that delegate to the local `twenty` CLI.
|
||||
* **.gitignore**: Ignoră artefacte comune precum `node_modules`, `.yarn`, `generated/` (client tipizat), `dist/`, `build/`, foldere de coverage, fișiere jurnal și fișiere `.env*`.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Blochează și configurează lanțul de instrumente Yarn 4 folosit de proiect.
|
||||
* **.nvmrc**: Fixează versiunea Node.js așteptată de proiect.
|
||||
* **eslint.config.mjs** și **tsconfig.json**: Oferă linting și configurație TypeScript pentru fișierele TypeScript ale aplicației.
|
||||
* **README.md**: Un README scurt în rădăcina aplicației, cu instrucțiuni de bază.
|
||||
* **src/app/**: Locul principal unde vă definiți aplicația sub formă de cod:
|
||||
* **src/**: The main place where you define your application-as-code:
|
||||
* `application.config.ts`: Configurație globală pentru aplicație (metadate și conectare la runtime). Vezi "Configurația aplicației" mai jos.
|
||||
* `*.role.ts`: Definiții de rol folosite de funcțiile dvs. serverless. Vezi "Rol implicit pentru funcții" mai jos.
|
||||
* `*.object.ts`: Definiții de obiecte personalizate.
|
||||
* `*.function.ts`: Definiții de funcții serverless.
|
||||
* **src/utils/**: Folder opțional pentru implementări de handleri și utilitare.
|
||||
* `*.front-component.tsx`: Front component definitions.
|
||||
|
||||
Comenzile ulterioare vor adăuga mai multe fișiere și foldere:
|
||||
|
||||
* `yarn app:generate` va crea un folder `generated/` (client Twenty tipizat + tipuri pentru spațiul de lucru).
|
||||
* `yarn app:create-entity` va adăuga fișiere de definire a entităților în `src/app/` pentru obiectele, funcțiile sau rolurile personalizate.
|
||||
l
|
||||
* `yarn entity:add` will add entity definition files under `src/` for your custom objects, functions, front components, or roles.
|
||||
|
||||
## Autentificare
|
||||
|
||||
@@ -302,63 +303,12 @@ Puncte cheie:
|
||||
* `universalIdentifier` trebuie să fie unic și stabil între implementări.
|
||||
* Fiecare câmp necesită un `name`, un `type`, un `label` și propriul `universalIdentifier` stabil.
|
||||
* Matricea `fields` este opțională — puteți defini obiecte fără câmpuri personalizate.
|
||||
* Puteți genera obiecte noi folosind `yarn app:create-entity`, care vă ghidează prin denumire, câmpuri și relații.
|
||||
* You can scaffold new objects using `yarn entity:add`, which guides you through naming, fields, and relationships.
|
||||
|
||||
<Note>
|
||||
**Câmpurile de bază sunt create automat.** Când definiți un obiect personalizat, Twenty adaugă automat câmpuri standard precum `name`, `createdAt`, `updatedAt`, `createdBy`, `position` și `deletedAt`. Nu trebuie să le definiți în tabloul `fields` — adăugați doar câmpurile personalizate proprii.
|
||||
</Note>
|
||||
|
||||
<Accordion title="Alternativă: Sintaxă bazată pe decoratori">
|
||||
Puteți defini obiecte și folosind decoratori TypeScript. Această abordare folosește o sintaxă bazată pe clase cu decoratorii `@Object`, `@Field` și `@Relation`:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
type AddressField,
|
||||
Field,
|
||||
FieldType,
|
||||
type FullNameField,
|
||||
Object,
|
||||
OnDeleteAction,
|
||||
Relation,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { type Note } from '../../generated';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post card',
|
||||
labelPlural: 'Post cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
export class PostCard {
|
||||
@Field({
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Relation({
|
||||
universalIdentifier: 'c9e2b4f4-b9ad-4427-9b42-9971b785edfe',
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
label: 'Notes',
|
||||
icon: 'IconComment',
|
||||
inverseSideTargetUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
onDelete: OnDeleteAction.CASCADE,
|
||||
})
|
||||
notes: Note[];
|
||||
}
|
||||
```
|
||||
|
||||
Notă: Abordarea cu decoratori necesită `experimentalDecorators` în configurația TypeScript.
|
||||
</Accordion>
|
||||
|
||||
### Configurația aplicației (application.config.ts)
|
||||
|
||||
Fiecare aplicație are un singur fișier `application.config.ts` care descrie:
|
||||
@@ -469,14 +419,9 @@ Fiecare fișier de funcție folosește `defineFunction()` pentru a exporta o con
|
||||
// src/app/createPostCard.function.ts
|
||||
import { defineFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
import Twenty, { type Person } from '~/generated';
|
||||
|
||||
const handler = async (
|
||||
params:
|
||||
| RoutePayload
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload,
|
||||
) => {
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new Twenty(); // generated typed client
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
@@ -507,18 +452,18 @@ export default defineFunction({
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
{
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
type: 'cron',
|
||||
pattern: '0 0 1 1 *',
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
{
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
type: 'databaseEvent',
|
||||
eventName: 'person.updated',
|
||||
updatedFields: ['name'],
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -633,7 +578,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Puteți crea funcții noi în două moduri:
|
||||
|
||||
* **Generat**: Rulați `yarn app:create-entity` și alegeți opțiunea de a adăuga o funcție nouă. Aceasta generează un fișier inițial cu un handler și o configurație.
|
||||
* **Scaffolded**: Run `yarn entity:add` and choose the option to add a new function. Aceasta generează un fișier inițial cu un handler și o configurație.
|
||||
* **Manual**: Creați un fișier nou `*.function.ts` și folosiți `defineFunction()`, urmând același model.
|
||||
|
||||
### Client tipizat generat
|
||||
@@ -641,13 +586,13 @@ Puteți crea funcții noi în două moduri:
|
||||
Rulați yarn app:generate pentru a crea un client tipizat local în generated/, pe baza schemei spațiului de lucru. Folosiți-l în funcțiile dvs.:
|
||||
|
||||
```typescript
|
||||
import Twenty from './generated';
|
||||
import Twenty from '~/generated';
|
||||
|
||||
const client = new Twenty();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
```
|
||||
|
||||
Clientul este regenerat de `yarn app:generate`. Rulați din nou după ce vă modificați obiectele și rulați `yarn app:sync` sau când vă integrați într-un spațiu de lucru nou.
|
||||
Clientul este regenerat de `yarn app:generate`. Re-run after changing your objects or when onboarding to a new workspace.
|
||||
|
||||
#### Acreditări la runtime în funcțiile serverless
|
||||
|
||||
@@ -679,25 +624,29 @@ Apoi adăugați scripturi ca acestea:
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"auth": "twenty auth login",
|
||||
"generate": "twenty app generate",
|
||||
"dev": "twenty app dev",
|
||||
"sync": "twenty app sync",
|
||||
"uninstall": "twenty app uninstall",
|
||||
"logs": "twenty app logs",
|
||||
"create-entity": "twenty app add",
|
||||
"help": "twenty --help"
|
||||
"auth:login": "twenty auth:login",
|
||||
"auth:logout": "twenty auth:logout",
|
||||
"auth:status": "twenty auth:status",
|
||||
"auth:switch": "twenty auth:switch",
|
||||
"auth:list": "twenty auth:list",
|
||||
"app:dev": "twenty app:dev",
|
||||
"app:generate": "twenty app:generate",
|
||||
"app:uninstall": "twenty app:uninstall",
|
||||
"entity:add": "twenty entity:add",
|
||||
"function:logs": "twenty function:logs",
|
||||
"function:execute": "twenty function:execute",
|
||||
"help": "twenty help"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Acum puteți rula aceleași comenzi prin Yarn, de ex. `yarn app:dev`, `yarn app:sync`, etc.
|
||||
Now you can run the same commands via Yarn, e.g. `yarn app:dev`, `yarn app:generate`, etc.
|
||||
|
||||
## Depanare
|
||||
|
||||
* Erori de autentificare: rulați `yarn auth:login` și asigurați-vă că cheia API are permisiunile necesare.
|
||||
* Nu se poate conecta la server: verificați URL-ul API și că serverul Twenty este accesibil.
|
||||
* Tipuri sau client lipsă/învechite: rulați `yarn app:generate` și apoi `yarn app:dev`.
|
||||
* Types or client missing/outdated: run `yarn app:generate`.
|
||||
* Modul dev nu sincronizează: asigurați-vă că `yarn app:dev` rulează și că modificările nu sunt ignorate de mediul dvs.
|
||||
|
||||
Canal de ajutor pe Discord: https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
|
||||
@@ -49,26 +49,23 @@ yarn app:dev
|
||||
Отсюда вы можете:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Добавить новую сущность в ваше приложение (с мастером)
|
||||
yarn app:create-entity
|
||||
# Add a new entity to your application (guided)
|
||||
yarn entity:add
|
||||
|
||||
# Сгенерировать типизированный клиент Twenty и типы сущностей рабочего пространства
|
||||
# Generate a typed Twenty client and workspace entity types
|
||||
yarn app:generate
|
||||
|
||||
# Выполнить разовую синхронизацию (вместо watch‑режима)
|
||||
yarn app:sync
|
||||
|
||||
# Просматривать логи функций вашего приложения
|
||||
# Watch your application's function logs
|
||||
yarn function:logs
|
||||
|
||||
# Выполнить функцию по имени
|
||||
# Execute a function by name
|
||||
yarn function:execute -n my-function -p '{"name": "test"}'
|
||||
|
||||
# Удалить приложение из текущего рабочего пространства
|
||||
# Uninstall the application from the current workspace
|
||||
yarn app:uninstall
|
||||
|
||||
# Показать справку по командам
|
||||
yarn app:help
|
||||
# Display commands' help
|
||||
yarn help
|
||||
```
|
||||
|
||||
Смотрите также: страницы справки CLI для [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) и [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk).
|
||||
@@ -97,22 +94,23 @@ my-twenty-app/
|
||||
tsconfig.json
|
||||
README.md
|
||||
src/
|
||||
app/
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
// your entities (*.object.ts, *.function.ts, *.role.ts)
|
||||
utils/ # Optional - handler implementations & utilities
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
hello-world.function.ts # Example serverless function
|
||||
hello-world.front-component.tsx # Example front component
|
||||
// your entities (*.object.ts, *.function.ts, *.front-component.tsx, *.role.ts)
|
||||
```
|
||||
|
||||
### Соглашения важнее конфигурации
|
||||
|
||||
Приложения используют подход **соглашения важнее конфигурации**, при котором сущности определяются по суффиксу файла. Это позволяет гибко организовать структуру в папке `src/app/`:
|
||||
|
||||
| Суффикс файла | Тип сущности |
|
||||
| --------------- | ------------------------------------- |
|
||||
| `*.object.ts` | Определения пользовательских объектов |
|
||||
| `*.function.ts` | Определения бессерверных функций |
|
||||
| `*.role.ts` | Определения ролей |
|
||||
| Суффикс файла | Тип сущности |
|
||||
| ----------------------- | ------------------------------------- |
|
||||
| `*.object.ts` | Определения пользовательских объектов |
|
||||
| `*.function.ts` | Определения бессерверных функций |
|
||||
| `*.front-component.tsx` | Front component definitions |
|
||||
| `*.role.ts` | Определения ролей |
|
||||
|
||||
### Поддерживаемые способы организации папок
|
||||
|
||||
@@ -121,12 +119,14 @@ my-twenty-app/
|
||||
**Традиционный (по типам):**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── objects/
|
||||
│ └── postCard.object.ts
|
||||
├── functions/
|
||||
│ └── createPostCard.function.ts
|
||||
├── components/
|
||||
│ └── card.front-component.tsx
|
||||
└── roles/
|
||||
└── admin.role.ts
|
||||
```
|
||||
@@ -134,44 +134,45 @@ src/app/
|
||||
**По функциональности:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
└── post-card/
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── postCardAdmin.role.ts
|
||||
```
|
||||
|
||||
**Плоский:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── admin.role.ts
|
||||
```
|
||||
|
||||
В общих чертах:
|
||||
|
||||
* **package.json**: Объявляет имя приложения, версию, движки (Node 24+, Yarn 4) и добавляет `twenty-sdk`, а также скрипты вроде `dev`, `sync`, `generate`, `create-entity`, `logs`, `uninstall` и `auth`, которые делегируют выполнение локальному CLI `twenty`.
|
||||
* **package.json**: Declares the app name, version, engines (Node 24+, Yarn 4), and adds `twenty-sdk` plus scripts like `app:dev`, `app:generate`, `entity:add`, `function:logs`, `function:execute`, `app:uninstall`, and `auth:login` that delegate to the local `twenty` CLI.
|
||||
* **.gitignore**: Игнорирует распространённые артефакты, такие как `node_modules`, `.yarn`, `generated/` (типизированный клиент), `dist/`, `build/`, каталоги coverage, файлы журналов и файлы `.env*`.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Фиксируют и настраивают используемый в проекте инструментарий Yarn 4.
|
||||
* **.nvmrc**: Фиксирует версию Node.js, ожидаемую проектом.
|
||||
* **eslint.config.mjs** и **tsconfig.json**: Обеспечивают линтинг и конфигурацию TypeScript для исходников вашего приложения на TypeScript.
|
||||
* **README.md**: Короткий README в корне приложения с базовыми инструкциями.
|
||||
* **src/app/**: Основное место, где вы определяете приложение как код:
|
||||
* **src/**: The main place where you define your application-as-code:
|
||||
* `application.config.ts`: Глобальная конфигурация вашего приложения (метаданные и параметры выполнения). См. раздел «Конфигурация приложения» ниже.
|
||||
* `*.role.ts`: Определения ролей, используемых вашими бессерверными функциями. См. раздел «Роль функции по умолчанию» ниже.
|
||||
* `*.object.ts`: Определения пользовательских объектов.
|
||||
* `*.function.ts`: Определения бессерверных функций.
|
||||
* **src/utils/**: Необязательная папка для реализаций обработчиков и утилит.
|
||||
* `*.front-component.tsx`: Front component definitions.
|
||||
|
||||
Позднее команды добавят больше файлов и папок:
|
||||
|
||||
* `yarn app:generate` создаст папку `generated/` (типизированный клиент Twenty + типы рабочего пространства).
|
||||
* `yarn app:create-entity` добавит файлы определений сущностей в `src/app/` для ваших пользовательских объектов, функций или ролей.
|
||||
l
|
||||
* `yarn entity:add` will add entity definition files under `src/` for your custom objects, functions, front components, or roles.
|
||||
|
||||
## Аутентификация
|
||||
|
||||
@@ -302,63 +303,12 @@ export default defineObject({
|
||||
* `universalIdentifier` должен быть уникальным и стабильным между развёртываниями.
|
||||
* Каждому полю требуются `name`, `type`, `label` и собственный стабильный `universalIdentifier`.
|
||||
* Массив `fields` необязателен — вы можете определять объекты без пользовательских полей.
|
||||
* Вы можете сгенерировать новые объекты с помощью `yarn app:create-entity`, который проведёт вас через выбор именования, полей и связей.
|
||||
* You can scaffold new objects using `yarn entity:add`, which guides you through naming, fields, and relationships.
|
||||
|
||||
<Note>
|
||||
**Базовые поля создаются автоматически.** Когда вы определяете пользовательский объект, Twenty автоматически добавляет стандартные поля, такие как `name`, `createdAt`, `updatedAt`, `createdBy`, `position` и `deletedAt`. Вам не нужно определять их в массиве `fields` — добавляйте только свои пользовательские поля.
|
||||
</Note>
|
||||
|
||||
<Accordion title="Альтернатива: синтаксис на декораторах">
|
||||
Вы также можете определять объекты с помощью декораторов TypeScript. Этот подход использует классовый синтаксис с декораторами `@Object`, `@Field` и `@Relation`:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
type AddressField,
|
||||
Field,
|
||||
FieldType,
|
||||
type FullNameField,
|
||||
Object,
|
||||
OnDeleteAction,
|
||||
Relation,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { type Note } from '../../generated';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post card',
|
||||
labelPlural: 'Post cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
export class PostCard {
|
||||
@Field({
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Relation({
|
||||
universalIdentifier: 'c9e2b4f4-b9ad-4427-9b42-9971b785edfe',
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
label: 'Notes',
|
||||
icon: 'IconComment',
|
||||
inverseSideTargetUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
onDelete: OnDeleteAction.CASCADE,
|
||||
})
|
||||
notes: Note[];
|
||||
}
|
||||
```
|
||||
|
||||
Примечание: подход с декораторами требует `experimentalDecorators` в конфигурации TypeScript.
|
||||
</Accordion>
|
||||
|
||||
### Конфигурация приложения (application.config.ts)
|
||||
|
||||
У каждого приложения есть единственный файл `application.config.ts`, который описывает:
|
||||
@@ -469,14 +419,9 @@ export default defineRole({
|
||||
// src/app/createPostCard.function.ts
|
||||
import { defineFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
import Twenty, { type Person } from '~/generated';
|
||||
|
||||
const handler = async (
|
||||
params:
|
||||
| RoutePayload
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload,
|
||||
) => {
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new Twenty(); // generated typed client
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
@@ -507,18 +452,18 @@ export default defineFunction({
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
{
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
type: 'cron',
|
||||
pattern: '0 0 1 1 *',
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
{
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
type: 'databaseEvent',
|
||||
eventName: 'person.updated',
|
||||
updatedFields: ['name'],
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -633,7 +578,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Вы можете создать новые функции двумя способами:
|
||||
|
||||
* **Сгенерировано**: Запустите `yarn app:create-entity` и выберите опцию добавления новой функции. Это создаёт стартовый файл с обработчиком и конфигурацией.
|
||||
* **Scaffolded**: Run `yarn entity:add` and choose the option to add a new function. Это создаёт стартовый файл с обработчиком и конфигурацией.
|
||||
* **Вручную**: Создайте новый файл `*.function.ts` и используйте `defineFunction()`, следуя тому же шаблону.
|
||||
|
||||
### Сгенерированный типизированный клиент
|
||||
@@ -641,13 +586,13 @@ const handler = async (event: RoutePayload) => {
|
||||
Запустите yarn app:generate, чтобы создать локальный типизированный клиент в generated/ на основе схемы вашего рабочего пространства. Используйте его в своих функциях:
|
||||
|
||||
```typescript
|
||||
import Twenty from './generated';
|
||||
import Twenty from '~/generated';
|
||||
|
||||
const client = new Twenty();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
```
|
||||
|
||||
Клиент повторно генерируется командой `yarn app:generate`. Запускайте повторно после изменения ваших объектов и `yarn app:sync` или при подключении к новому рабочему пространству.
|
||||
Клиент повторно генерируется командой `yarn app:generate`. Re-run after changing your objects or when onboarding to a new workspace.
|
||||
|
||||
#### Учётные данные времени выполнения в бессерверных функциях
|
||||
|
||||
@@ -679,25 +624,29 @@ yarn add -D twenty-sdk
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"auth": "twenty auth login",
|
||||
"generate": "twenty app generate",
|
||||
"dev": "twenty app dev",
|
||||
"sync": "twenty app sync",
|
||||
"uninstall": "twenty app uninstall",
|
||||
"logs": "twenty app logs",
|
||||
"create-entity": "twenty app add",
|
||||
"help": "twenty --help"
|
||||
"auth:login": "twenty auth:login",
|
||||
"auth:logout": "twenty auth:logout",
|
||||
"auth:status": "twenty auth:status",
|
||||
"auth:switch": "twenty auth:switch",
|
||||
"auth:list": "twenty auth:list",
|
||||
"app:dev": "twenty app:dev",
|
||||
"app:generate": "twenty app:generate",
|
||||
"app:uninstall": "twenty app:uninstall",
|
||||
"entity:add": "twenty entity:add",
|
||||
"function:logs": "twenty function:logs",
|
||||
"function:execute": "twenty function:execute",
|
||||
"help": "twenty help"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Теперь вы можете запускать те же команды через Yarn, например, `yarn app:dev`, `yarn app:sync` и т. д.
|
||||
Now you can run the same commands via Yarn, e.g. `yarn app:dev`, `yarn app:generate`, etc.
|
||||
|
||||
## Устранение неполадок
|
||||
|
||||
* Ошибки аутентификации: выполните `yarn auth:login` и убедитесь, что у вашего ключа API есть необходимые права.
|
||||
* Не удаётся подключиться к серверу: проверьте URL API и доступность сервера Twenty.
|
||||
* Отсутствующие/устаревшие типы или клиент: выполните `yarn app:generate`, затем `yarn app:dev`.
|
||||
* Types or client missing/outdated: run `yarn app:generate`.
|
||||
* Режим разработки не синхронизируется: убедитесь, что запущен `yarn app:dev`, и что ваша среда не игнорирует изменения.
|
||||
|
||||
Канал помощи в Discord: https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
|
||||
@@ -50,15 +50,12 @@ Buradan şunları yapabilirsiniz:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new entity to your application (guided)
|
||||
yarn app:create-entity
|
||||
yarn entity:add
|
||||
|
||||
# Generate a typed Twenty client and workspace entity types
|
||||
yarn app:generate
|
||||
|
||||
# Run a one‑time sync (instead of watch mode)
|
||||
yarn app:sync
|
||||
|
||||
# Watch your application's functions logs
|
||||
# Watch your application's function logs
|
||||
yarn function:logs
|
||||
|
||||
# Execute a function by name
|
||||
@@ -68,7 +65,7 @@ yarn function:execute -n my-function -p '{"name": "test"}'
|
||||
yarn app:uninstall
|
||||
|
||||
# Display commands' help
|
||||
yarn app:help
|
||||
yarn help
|
||||
```
|
||||
|
||||
Ayrıca bkz.: [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) ve [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk) için CLI başvuru sayfaları.
|
||||
@@ -97,22 +94,23 @@ my-twenty-app/
|
||||
tsconfig.json
|
||||
README.md
|
||||
src/
|
||||
app/
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
// your entities (*.object.ts, *.function.ts, *.role.ts)
|
||||
utils/ # Optional - handler implementations & utilities
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
hello-world.function.ts # Example serverless function
|
||||
hello-world.front-component.tsx # Example front component
|
||||
// your entities (*.object.ts, *.function.ts, *.front-component.tsx, *.role.ts)
|
||||
```
|
||||
|
||||
### Sözleşme-öncelikli yapılandırma
|
||||
|
||||
Uygulamalar, varlıkların dosya sonekiyle algılandığı **sözleşme-öncelikli yapılandırma** yaklaşımını kullanır. Bu, `src/app/` klasörü içinde esnek bir düzenlemeye olanak tanır:
|
||||
|
||||
| Dosya soneki | Varlık türü |
|
||||
| --------------- | ----------------------------- |
|
||||
| `*.object.ts` | Özel nesne tanımları |
|
||||
| `*.function.ts` | Sunucusuz fonksiyon tanımları |
|
||||
| `*.role.ts` | Rol tanımları |
|
||||
| Dosya soneki | Varlık türü |
|
||||
| ----------------------- | ----------------------------- |
|
||||
| `*.object.ts` | Özel nesne tanımları |
|
||||
| `*.function.ts` | Sunucusuz fonksiyon tanımları |
|
||||
| `*.front-component.tsx` | Front component definitions |
|
||||
| `*.role.ts` | Rol tanımları |
|
||||
|
||||
### Desteklenen klasör düzenleri
|
||||
|
||||
@@ -121,12 +119,14 @@ Varlıklarınızı şu desenlerden herhangi birine göre düzenleyebilirsiniz:
|
||||
**Geleneksel (türe göre):**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── objects/
|
||||
│ └── postCard.object.ts
|
||||
├── functions/
|
||||
│ └── createPostCard.function.ts
|
||||
├── components/
|
||||
│ └── card.front-component.tsx
|
||||
└── roles/
|
||||
└── admin.role.ts
|
||||
```
|
||||
@@ -134,44 +134,45 @@ src/app/
|
||||
**Özelliğe dayalı:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
└── post-card/
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── postCardAdmin.role.ts
|
||||
```
|
||||
|
||||
**Düz:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── admin.role.ts
|
||||
```
|
||||
|
||||
Genel hatlarıyla:
|
||||
|
||||
* **package.json**: Uygulama adını, sürümünü, motorları (Node 24+, Yarn 4) bildirir ve yerel `twenty` CLI’ına yetki devreden `dev`, `sync`, `generate`, `create-entity`, `logs`, `uninstall` ve `auth` gibi betiklerin yanı sıra `twenty-sdk` ekler.
|
||||
* **package.json**: Declares the app name, version, engines (Node 24+, Yarn 4), and adds `twenty-sdk` plus scripts like `app:dev`, `app:generate`, `entity:add`, `function:logs`, `function:execute`, `app:uninstall`, and `auth:login` that delegate to the local `twenty` CLI.
|
||||
* **.gitignore**: `node_modules`, `.yarn`, `generated/` (türlendirilmiş istemci), `dist/`, `build/`, kapsam klasörleri, günlük dosyaları ve `.env*` dosyaları gibi yaygın artifaktları yok sayar.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Proje tarafından kullanılan Yarn 4 araç zincirini kilitler ve yapılandırır.
|
||||
* **.nvmrc**: Projenin beklediği Node.js sürümünü sabitler.
|
||||
* **eslint.config.mjs** ve **tsconfig.json**: Uygulamanızın TypeScript kaynakları için linting ve TypeScript yapılandırması sağlar.
|
||||
* **README.md**: Uygulama kökünde temel talimatların yer aldığı kısa bir README.
|
||||
* **src/app/**: Uygulamanızı kod olarak tanımladığınız ana yer:
|
||||
* **src/**: The main place where you define your application-as-code:
|
||||
* `application.config.ts`: Uygulamanız için genel yapılandırma (meta veriler ve çalışma zamanı bağlantıları). Aşağıda "Uygulama yapılandırması"na bakın.
|
||||
* `*.role.ts`: Sunucusuz fonksiyonlarınız tarafından kullanılan rol tanımları. Aşağıda "Varsayılan fonksiyon rolü"ne bakın.
|
||||
* `*.object.ts`: Özel nesne tanımları.
|
||||
* `*.function.ts`: Sunucusuz fonksiyon tanımları.
|
||||
* **src/utils/**: İşleyici uygulamaları ve yardımcılar için isteğe bağlı klasör.
|
||||
* `*.front-component.tsx`: Front component definitions.
|
||||
|
||||
İlerideki komutlar daha fazla dosya ve klasör ekleyecektir:
|
||||
|
||||
* `yarn app:generate`, `generated/` klasörünü oluşturur (türlendirilmiş Twenty istemcisi + çalışma alanı türleri).
|
||||
* `yarn app:create-entity`, özel nesneleriniz, fonksiyonlarınız veya rolleriniz için `src/app/` altında varlık tanım dosyaları ekler.
|
||||
l
|
||||
* `yarn entity:add` will add entity definition files under `src/` for your custom objects, functions, front components, or roles.
|
||||
|
||||
## Kimlik Doğrulama
|
||||
|
||||
@@ -302,63 +303,12 @@ export default defineObject({
|
||||
* `universalIdentifier` dağıtımlar arasında benzersiz ve kararlı olmalıdır.
|
||||
* Her alan bir `name`, `type`, `label` ve kendi kararlı `universalIdentifier` değerini gerektirir.
|
||||
* `fields` dizisi isteğe bağlıdır — özel alanlar olmadan da nesneler tanımlayabilirsiniz.
|
||||
* `yarn app:create-entity` kullanarak, adlandırma, alanlar ve ilişkiler konusunda sizi yönlendirerek yeni nesneler oluşturabilirsiniz.
|
||||
* You can scaffold new objects using `yarn entity:add`, which guides you through naming, fields, and relationships.
|
||||
|
||||
<Note>
|
||||
**Temel alanlar otomatik olarak oluşturulur.** Özel bir nesne tanımladığınızda Twenty, `name`, `createdAt`, `updatedAt`, `createdBy`, `position` ve `deletedAt` gibi standart alanları otomatik olarak ekler. Bunları `fields` dizinizde tanımlamanız gerekmez — yalnızca özel alanlarınızı ekleyin.
|
||||
</Note>
|
||||
|
||||
<Accordion title="Alternatif: Dekoratör tabanlı söz dizimi">
|
||||
Nesneleri TypeScript dekoratörlerini kullanarak da tanımlayabilirsiniz. Bu yaklaşım, `@Object`, `@Field` ve `@Relation` dekoratörleriyle sınıf tabanlı söz dizimi kullanır:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
type AddressField,
|
||||
Field,
|
||||
FieldType,
|
||||
type FullNameField,
|
||||
Object,
|
||||
OnDeleteAction,
|
||||
Relation,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { type Note } from '../../generated';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post card',
|
||||
labelPlural: 'Post cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
export class PostCard {
|
||||
@Field({
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Relation({
|
||||
universalIdentifier: 'c9e2b4f4-b9ad-4427-9b42-9971b785edfe',
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
label: 'Notes',
|
||||
icon: 'IconComment',
|
||||
inverseSideTargetUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
onDelete: OnDeleteAction.CASCADE,
|
||||
})
|
||||
notes: Note[];
|
||||
}
|
||||
```
|
||||
|
||||
Not: Dekoratör yaklaşımı, TypeScript yapılandırmanızda `experimentalDecorators` gerektirir.
|
||||
</Accordion>
|
||||
|
||||
### Uygulama yapılandırması (application.config.ts)
|
||||
|
||||
Her uygulamanın aşağıdakileri açıklayan tek bir `application.config.ts` dosyası vardır:
|
||||
@@ -469,14 +419,9 @@ Her fonksiyon dosyası, bir işleyici ve isteğe bağlı tetikleyiciler içeren
|
||||
// src/app/createPostCard.function.ts
|
||||
import { defineFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
import Twenty, { type Person } from '~/generated';
|
||||
|
||||
const handler = async (
|
||||
params:
|
||||
| RoutePayload
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload,
|
||||
) => {
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new Twenty(); // generated typed client
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
@@ -507,18 +452,18 @@ export default defineFunction({
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
{
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
type: 'cron',
|
||||
pattern: '0 0 1 1 *',
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
{
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
type: 'databaseEvent',
|
||||
eventName: 'person.updated',
|
||||
updatedFields: ['name'],
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -633,7 +578,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Yeni fonksiyonları iki şekilde oluşturabilirsiniz:
|
||||
|
||||
* **Şablondan**: `yarn app:create-entity` çalıştırın ve yeni bir fonksiyon ekleme seçeneğini seçin. Bu, bir işleyici ve yapılandırma içeren bir başlangıç dosyası oluşturur.
|
||||
* **Scaffolded**: Run `yarn entity:add` and choose the option to add a new function. Bu, bir işleyici ve yapılandırma içeren bir başlangıç dosyası oluşturur.
|
||||
* **Manuel**: Yeni bir `*.function.ts` dosyası oluşturun ve aynı deseni izleyerek `defineFunction()` kullanın.
|
||||
|
||||
### Oluşturulmuş türlendirilmiş istemci
|
||||
@@ -641,13 +586,13 @@ Yeni fonksiyonları iki şekilde oluşturabilirsiniz:
|
||||
Çalışma alanı şemanıza göre generated/ içinde yerel bir türlendirilmiş istemci oluşturmak için yarn app:generate çalıştırın. Fonksiyonlarınızda kullanın:
|
||||
|
||||
```typescript
|
||||
import Twenty from './generated';
|
||||
import Twenty from '~/generated';
|
||||
|
||||
const client = new Twenty();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
```
|
||||
|
||||
İstemci `yarn app:generate` tarafından yeniden oluşturulur. Nesnelerinizi değiştirip `yarn app:sync` çalıştırdıktan sonra veya yeni bir çalışma alanına katılırken yeniden çalıştırın.
|
||||
İstemci `yarn app:generate` tarafından yeniden oluşturulur. Re-run after changing your objects or when onboarding to a new workspace.
|
||||
|
||||
#### Sunucusuz fonksiyonlarda çalışma zamanı kimlik bilgileri
|
||||
|
||||
@@ -679,25 +624,29 @@ Ardından şu gibi betikler ekleyin:
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"auth": "twenty auth login",
|
||||
"generate": "twenty app generate",
|
||||
"dev": "twenty app dev",
|
||||
"sync": "twenty app sync",
|
||||
"uninstall": "twenty app uninstall",
|
||||
"logs": "twenty app logs",
|
||||
"create-entity": "twenty app add",
|
||||
"help": "twenty --help"
|
||||
"auth:login": "twenty auth:login",
|
||||
"auth:logout": "twenty auth:logout",
|
||||
"auth:status": "twenty auth:status",
|
||||
"auth:switch": "twenty auth:switch",
|
||||
"auth:list": "twenty auth:list",
|
||||
"app:dev": "twenty app:dev",
|
||||
"app:generate": "twenty app:generate",
|
||||
"app:uninstall": "twenty app:uninstall",
|
||||
"entity:add": "twenty entity:add",
|
||||
"function:logs": "twenty function:logs",
|
||||
"function:execute": "twenty function:execute",
|
||||
"help": "twenty help"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Artık aynı komutları Yarn üzerinden çalıştırabilirsiniz; örn. `yarn app:dev`, `yarn app:sync` vb.
|
||||
Now you can run the same commands via Yarn, e.g. `yarn app:dev`, `yarn app:generate`, etc.
|
||||
|
||||
## Sorun Giderme
|
||||
|
||||
* Kimlik doğrulama hataları: `yarn auth:login` çalıştırın ve API anahtarınızın gerekli izinlere sahip olduğundan emin olun.
|
||||
* Sunucuya bağlanılamıyor: API URL’sini ve Twenty sunucusunun erişilebilir olduğunu doğrulayın.
|
||||
* Türler veya istemci eksik/eski: `yarn app:generate` ve ardından `yarn app:dev` çalıştırın.
|
||||
* Types or client missing/outdated: run `yarn app:generate`.
|
||||
* Geliştirme modu eşitlenmiyor: `yarn app:dev`'in çalıştığından ve değişikliklerin ortamınız tarafından yok sayılmadığından emin olun.
|
||||
|
||||
Discord Yardım Kanalı: https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
|
||||
@@ -50,15 +50,12 @@ yarn app:dev
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new entity to your application (guided)
|
||||
yarn app:create-entity
|
||||
yarn entity:add
|
||||
|
||||
# Generate a typed Twenty client and workspace entity types
|
||||
yarn app:generate
|
||||
|
||||
# Run a one‑time sync (instead of watch mode)
|
||||
yarn app:sync
|
||||
|
||||
# Watch your application's functions logs
|
||||
# Watch your application's function logs
|
||||
yarn function:logs
|
||||
|
||||
# Execute a function by name
|
||||
@@ -68,7 +65,7 @@ yarn function:execute -n my-function -p '{"name": "test"}'
|
||||
yarn app:uninstall
|
||||
|
||||
# Display commands' help
|
||||
yarn app:help
|
||||
yarn help
|
||||
```
|
||||
|
||||
另请参阅:[create-twenty-app](https://www.npmjs.com/package/create-twenty-app) 和 [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk) 的 CLI 参考页面。
|
||||
@@ -97,22 +94,23 @@ my-twenty-app/
|
||||
tsconfig.json
|
||||
README.md
|
||||
src/
|
||||
app/
|
||||
application.config.ts # 必需 - 主应用程序配置
|
||||
default-function.role.ts # 用于无服务器函数的默认角色
|
||||
// 你的实体 (*.object.ts, *.function.ts, *.role.ts)
|
||||
utils/ # 可选 - 处理器实现与实用工具
|
||||
application.config.ts # Required - main application configuration
|
||||
default-function.role.ts # Default role for serverless functions
|
||||
hello-world.function.ts # Example serverless function
|
||||
hello-world.front-component.tsx # Example front component
|
||||
// your entities (*.object.ts, *.function.ts, *.front-component.tsx, *.role.ts)
|
||||
```
|
||||
|
||||
### 约定优于配置
|
||||
|
||||
应用采用**约定优于配置**的方式,根据文件后缀检测实体。 这使得可以在 `src/app/` 文件夹内灵活组织:
|
||||
|
||||
| 文件后缀 | 实体类型 |
|
||||
| --------------- | -------- |
|
||||
| `*.object.ts` | 自定义对象定义 |
|
||||
| `*.function.ts` | 无服务器函数定义 |
|
||||
| `*.role.ts` | 角色定义 |
|
||||
| 文件后缀 | 实体类型 |
|
||||
| ----------------------- | --------------------------- |
|
||||
| `*.object.ts` | 自定义对象定义 |
|
||||
| `*.function.ts` | 无服务器函数定义 |
|
||||
| `*.front-component.tsx` | Front component definitions |
|
||||
| `*.role.ts` | 角色定义 |
|
||||
|
||||
### 支持的文件夹组织方式
|
||||
|
||||
@@ -121,12 +119,14 @@ my-twenty-app/
|
||||
**传统(按类型):**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── objects/
|
||||
│ └── postCard.object.ts
|
||||
├── functions/
|
||||
│ └── createPostCard.function.ts
|
||||
├── components/
|
||||
│ └── card.front-component.tsx
|
||||
└── roles/
|
||||
└── admin.role.ts
|
||||
```
|
||||
@@ -134,44 +134,45 @@ src/app/
|
||||
**基于特性:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
└── post-card/
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── postCardAdmin.role.ts
|
||||
```
|
||||
|
||||
**扁平:**
|
||||
|
||||
```text
|
||||
src/app/
|
||||
src/
|
||||
├── application.config.ts
|
||||
├── postCard.object.ts
|
||||
├── createPostCard.function.ts
|
||||
├── card.front-component.tsx
|
||||
└── admin.role.ts
|
||||
```
|
||||
|
||||
总体来说:
|
||||
|
||||
* **package.json**:声明应用名称、版本、运行时(Node 24+、Yarn 4),并添加 `twenty-sdk` 以及 `dev`、`sync`、`generate`、`create-entity`、`logs`、`uninstall`、`auth` 等脚本,这些脚本会委托给本地的 `twenty` CLI。
|
||||
* **package.json**: Declares the app name, version, engines (Node 24+, Yarn 4), and adds `twenty-sdk` plus scripts like `app:dev`, `app:generate`, `entity:add`, `function:logs`, `function:execute`, `app:uninstall`, and `auth:login` that delegate to the local `twenty` CLI.
|
||||
* **.gitignore**:忽略常见产物,如 `node_modules`、`.yarn`、`generated/`(类型化客户端)、`dist/`、`build/`、覆盖率文件夹、日志文件以及 `.env*` 文件。
|
||||
* **yarn.lock**、**.yarnrc.yml**、**.yarn/**:锁定并配置项目使用的 Yarn 4 工具链。
|
||||
* **.nvmrc**:固定项目期望的 Node.js 版本。
|
||||
* **eslint.config.mjs** 和 **tsconfig.json**:为应用的 TypeScript 源码提供 Lint 与 TypeScript 配置。
|
||||
* **README.md**:应用根目录中的简短 README,包含基本说明。
|
||||
* **src/app/**:你以代码形式定义应用的主要位置:
|
||||
* **src/**: The main place where you define your application-as-code:
|
||||
* `application.config.ts`:应用的全局配置(元数据和运行时关联)。 参见下方“应用配置”。
|
||||
* `*.role.ts`:你的无服务器函数所使用的角色定义。 参见下方“默认函数角色”。
|
||||
* `*.object.ts`:自定义对象定义。
|
||||
* `*.function.ts`:无服务器函数定义。
|
||||
* **src/utils/**:可选文件夹,用于处理程序实现和实用工具。
|
||||
* `*.front-component.tsx`: Front component definitions.
|
||||
|
||||
后续命令将添加更多文件和文件夹:
|
||||
|
||||
* `yarn app:generate` 将创建一个 `generated/` 文件夹(类型化 Twenty 客户端 + 工作空间类型)。
|
||||
* `yarn app:create-entity` 将为你的自定义对象、函数或角色在 `src/app/` 下添加实体定义文件。
|
||||
l
|
||||
* `yarn entity:add` will add entity definition files under `src/` for your custom objects, functions, front components, or roles.
|
||||
|
||||
## 身份验证
|
||||
|
||||
@@ -302,63 +303,12 @@ export default defineObject({
|
||||
* `universalIdentifier` 必须在各次部署间保持唯一且稳定。
|
||||
* 每个字段都需要 `name`、`type`、`label` 以及其自身稳定的 `universalIdentifier`。
|
||||
* `fields` 数组是可选的——你可以定义没有自定义字段的对象。
|
||||
* 你可以使用 `yarn app:create-entity` 脚手架创建新对象,它会引导你完成命名、字段和关系。
|
||||
* You can scaffold new objects using `yarn entity:add`, which guides you through naming, fields, and relationships.
|
||||
|
||||
<Note>
|
||||
**基础字段会自动创建。** 当你定义自定义对象时,Twenty 会自动添加 `name`、`createdAt`、`updatedAt`、`createdBy`、`position`、`deletedAt` 等标准字段。 你无需在 `fields` 数组中定义这些字段——只需添加你的自定义字段。
|
||||
</Note>
|
||||
|
||||
<Accordion title="替代方案:基于装饰器的语法">
|
||||
你也可以使用 TypeScript 装饰器来定义对象。 该方式使用基于类的语法以及 `@Object`、`@Field`、`@Relation` 装饰器:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
type AddressField,
|
||||
Field,
|
||||
FieldType,
|
||||
type FullNameField,
|
||||
Object,
|
||||
OnDeleteAction,
|
||||
Relation,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { type Note } from '../../generated';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post card',
|
||||
labelPlural: 'Post cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
export class PostCard {
|
||||
@Field({
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Relation({
|
||||
universalIdentifier: 'c9e2b4f4-b9ad-4427-9b42-9971b785edfe',
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
label: 'Notes',
|
||||
icon: 'IconComment',
|
||||
inverseSideTargetUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
onDelete: OnDeleteAction.CASCADE,
|
||||
})
|
||||
notes: Note[];
|
||||
}
|
||||
```
|
||||
|
||||
注意:装饰器方式需要在 TypeScript 配置中启用 `experimentalDecorators`。
|
||||
</Accordion>
|
||||
|
||||
### 应用配置(application.config.ts)
|
||||
|
||||
每个应用都有一个 `application.config.ts` 文件,用于描述:
|
||||
@@ -469,14 +419,9 @@ export default defineRole({
|
||||
// src/app/createPostCard.function.ts
|
||||
import { defineFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
import Twenty, { type Person } from '~/generated';
|
||||
|
||||
const handler = async (
|
||||
params:
|
||||
| RoutePayload
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload,
|
||||
) => {
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new Twenty(); // generated typed client
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
@@ -507,18 +452,18 @@ export default defineFunction({
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
{
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
type: 'cron',
|
||||
pattern: '0 0 1 1 *',
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
{
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
type: 'databaseEvent',
|
||||
eventName: 'person.updated',
|
||||
updatedFields: ['name'],
|
||||
},
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -633,7 +578,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
你可以通过两种方式创建新函数:
|
||||
|
||||
* **脚手架生成**:运行 `yarn app:create-entity` 并选择添加新函数的选项。 这将生成一个包含处理程序和配置的入门文件。
|
||||
* **Scaffolded**: Run `yarn entity:add` and choose the option to add a new function. 这将生成一个包含处理程序和配置的入门文件。
|
||||
* **手动**:创建一个新的 `*.function.ts` 文件,并使用 `defineFunction()`,遵循相同的模式。
|
||||
|
||||
### 生成的类型化客户端
|
||||
@@ -641,13 +586,13 @@ const handler = async (event: RoutePayload) => {
|
||||
运行 yarn app:generate,根据你的工作空间模式在 generated/ 中创建本地类型化客户端。 在你的函数中使用它:
|
||||
|
||||
```typescript
|
||||
import Twenty from './generated';
|
||||
import Twenty from '~/generated';
|
||||
|
||||
const client = new Twenty();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
```
|
||||
|
||||
客户端会通过 `yarn app:generate` 重新生成。 在更改对象并执行 `yarn app:sync` 之后,或在接入新工作空间时,请重新运行。
|
||||
客户端会通过 `yarn app:generate` 重新生成。 Re-run after changing your objects or when onboarding to a new workspace.
|
||||
|
||||
#### 无服务器函数中的运行时凭据
|
||||
|
||||
@@ -679,25 +624,29 @@ yarn add -D twenty-sdk
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"auth": "twenty auth login",
|
||||
"generate": "twenty app generate",
|
||||
"dev": "twenty app dev",
|
||||
"sync": "twenty app sync",
|
||||
"uninstall": "twenty app uninstall",
|
||||
"logs": "twenty app logs",
|
||||
"create-entity": "twenty app add",
|
||||
"help": "twenty --help"
|
||||
"auth:login": "twenty auth:login",
|
||||
"auth:logout": "twenty auth:logout",
|
||||
"auth:status": "twenty auth:status",
|
||||
"auth:switch": "twenty auth:switch",
|
||||
"auth:list": "twenty auth:list",
|
||||
"app:dev": "twenty app:dev",
|
||||
"app:generate": "twenty app:generate",
|
||||
"app:uninstall": "twenty app:uninstall",
|
||||
"entity:add": "twenty entity:add",
|
||||
"function:logs": "twenty function:logs",
|
||||
"function:execute": "twenty function:execute",
|
||||
"help": "twenty help"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
现在你可以通过 Yarn 运行相同的命令,例如 `yarn app:dev`、`yarn app:sync` 等。
|
||||
Now you can run the same commands via Yarn, e.g. `yarn app:dev`, `yarn app:generate`, etc.
|
||||
|
||||
## 故障排除
|
||||
|
||||
* 身份验证错误:运行 `yarn auth:login`,并确保你的 API 密钥具有所需权限。
|
||||
* 无法连接到服务器:请验证 API URL,并确保 Twenty 服务器可达。
|
||||
* 类型或客户端缺失/过期:运行 `yarn app:generate`,然后运行 `yarn app:dev`。
|
||||
* Types or client missing/outdated: run `yarn app:generate`.
|
||||
* 开发模式未同步:确保 `yarn app:dev` 正在运行,并且你的环境不会忽略变更。
|
||||
|
||||
Discord 帮助频道:https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
|
||||
Reference in New Issue
Block a user