Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfc0a4d5fc | ||
|
|
92c8965dd3 | ||
|
|
f19b3bfd38 | ||
|
|
0aaffe3212 | ||
|
|
66857ca77b | ||
|
|
76582dc04a | ||
|
|
a2099d22b5 | ||
|
|
a7b10b281c | ||
|
|
3eabdf302e | ||
|
|
8bb98c309a | ||
|
|
8f34a02fea | ||
|
|
61fdb613e6 | ||
|
|
7947b1b843 | ||
|
|
2b399fc94e | ||
|
|
44ba7725ae | ||
|
|
65e01400c0 |
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: الأخطاء والطلبات وطلبات السحب
|
||||
icon: bug
|
||||
icon: خلل
|
||||
info: أبلغ عن المشكلات، واطلب الميزات، وساهم بالشفرة البرمجية
|
||||
---
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Commands
|
||||
title: أوامر
|
||||
icon: terminal
|
||||
description: Useful commands for developing Twenty.
|
||||
description: أوامر مفيدة لتطوير Twenty.
|
||||
---
|
||||
|
||||
Commands can be run from the repository root using `npx nx`. Use `npx nx run {project}:{command}` for explicit targeting.
|
||||
يمكن تشغيل الأوامر من جذر المستودع باستخدام `npx nx`. استخدم `npx nx run {project}:{command}` للاستهداف الصريح.
|
||||
|
||||
## Starting the App
|
||||
## بدء التطبيق
|
||||
|
||||
```bash
|
||||
npx nx start twenty-front # Frontend dev server (http://localhost:3001)
|
||||
@@ -14,7 +14,7 @@ npx nx start twenty-server # Backend server (http://localhost:3000)
|
||||
npx nx run twenty-server:worker # Background worker
|
||||
```
|
||||
|
||||
## Database
|
||||
## قاعدة البيانات
|
||||
|
||||
```bash
|
||||
npx nx database:reset twenty-server # Reset and seed database
|
||||
@@ -22,7 +22,7 @@ npx nx run twenty-server:database:migrate:prod # Run migrations
|
||||
npx nx run twenty-server:database:migrate:generate --name <name> --type <fast|slow> # Generate a migration
|
||||
```
|
||||
|
||||
## Linting
|
||||
## فحص الشيفرة
|
||||
|
||||
```bash
|
||||
npx nx lint:diff-with-main twenty-front # Lint changed files (fastest)
|
||||
@@ -30,14 +30,14 @@ npx nx lint:diff-with-main twenty-server
|
||||
npx nx lint twenty-front --configuration=fix # Auto-fix
|
||||
```
|
||||
|
||||
## Type Checking
|
||||
## التحقق من الأنواع
|
||||
|
||||
```bash
|
||||
npx nx typecheck twenty-front
|
||||
npx nx typecheck twenty-server
|
||||
```
|
||||
|
||||
## "الاختبار"
|
||||
## الاختبار
|
||||
|
||||
```bash
|
||||
# Frontend
|
||||
@@ -61,14 +61,14 @@ npx nx run twenty-front:graphql:generate # Regenerate typ
|
||||
npx nx run twenty-front:graphql:generate --configuration=metadata # Metadata schema
|
||||
```
|
||||
|
||||
## "الترجمات"
|
||||
## الترجمات
|
||||
|
||||
```bash
|
||||
npx nx run twenty-front:lingui:extract # Extract strings
|
||||
npx nx run twenty-front:lingui:compile # Compile translations
|
||||
```
|
||||
|
||||
## Build
|
||||
## البناء
|
||||
|
||||
```bash
|
||||
npx nx build twenty-shared # Must be built first
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
title: دليل الأسلوب
|
||||
icon: paintbrush
|
||||
description: Code conventions and best practices for contributing to Twenty.
|
||||
icon: فرشاة الرسم
|
||||
description: اتفاقيات الشيفرة وأفضل الممارسات للمساهمة في Twenty.
|
||||
---
|
||||
|
||||
## React
|
||||
|
||||
### Functional components only
|
||||
### المكوّنات الوظيفية فقط
|
||||
|
||||
Always use TSX functional components with named exports.
|
||||
استخدم دائمًا مكوّنات TSX الوظيفية مع تصديرات مسمّاة.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
@@ -23,9 +23,9 @@ export function MyComponent() {
|
||||
};
|
||||
```
|
||||
|
||||
### الإزاحة
|
||||
### الخصائص
|
||||
|
||||
Create a type named `{ComponentName}Props`. Use destructuring. Don't use `React.FC`.
|
||||
أنشئ نوعًا باسم `{ComponentName}Props`. استخدم التفكيك. لا تستخدم `React.FC`.
|
||||
|
||||
```tsx
|
||||
type MyComponentProps = {
|
||||
@@ -35,7 +35,7 @@ type MyComponentProps = {
|
||||
export const MyComponent = ({ name }: MyComponentProps) => <div>Hello {name}</div>;
|
||||
```
|
||||
|
||||
### No single-variable prop spreading
|
||||
### لا تستخدم نشر الخصائص من متغير واحد
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
@@ -45,9 +45,9 @@ const MyComponent = (props: MyComponentProps) => <Other {...props} />;
|
||||
const MyComponent = ({ prop1, prop2 }: MyComponentProps) => <Other {...{ prop1, prop2 }} />;
|
||||
```
|
||||
|
||||
## "إدارة الحالة"
|
||||
## إدارة الحالة
|
||||
|
||||
### Jotai atoms for global state
|
||||
### ذرات Jotai للحالة العامة
|
||||
|
||||
```tsx
|
||||
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
|
||||
@@ -59,16 +59,16 @@ export const myAtomState = createAtomState<string>({
|
||||
});
|
||||
```
|
||||
|
||||
* Prefer atoms over prop drilling
|
||||
* Don't use `useRef` for state — use `useState` or atoms
|
||||
* Use atom families and selectors for lists
|
||||
* فضّل الذرات على تمرير الخصائص عبر المستويات (prop drilling)
|
||||
* لا تستخدم `useRef` للحالة — استخدم `useState` أو الذرات
|
||||
* استخدم عائلات الذرات والمحددات للقوائم
|
||||
|
||||
### Avoid unnecessary re-renders
|
||||
### تجنّب عمليات إعادة التصيير غير الضرورية
|
||||
|
||||
* Extract `useEffect` and data fetching into sibling sidecar components
|
||||
* Prefer event handlers (`handleClick`, `handleChange`) over `useEffect`
|
||||
* Don't use `React.memo()` — fix the root cause instead
|
||||
* Limit `useCallback` / `useMemo` usage
|
||||
* انقل `useEffect` وجلب البيانات إلى مكوّنات جانبية شقيقة (sidecar)
|
||||
* فضّل معالِجات الأحداث (`handleClick`, `handleChange`) على `useEffect`
|
||||
* لا تستخدم `React.memo()` — أصلِح السبب الجذري بدلًا من ذلك
|
||||
* حدّد استخدام `useCallback` / `useMemo`
|
||||
|
||||
```tsx
|
||||
// ❌ Bad — useEffect in the same component causes re-renders
|
||||
@@ -94,11 +94,11 @@ export const Page = () => {
|
||||
|
||||
## TypeScript
|
||||
|
||||
* **`type` over `interface`** — more flexible, easier to compose
|
||||
* **String literals over enums** — except for GraphQL codegen enums and internal library APIs
|
||||
* **No `any`** — strict TypeScript enforced
|
||||
* **No type imports** — use regular imports (enforced by Oxlint `typescript/consistent-type-imports`)
|
||||
* **Use [Zod](https://github.com/colinhacks/zod)** for runtime validation of untyped objects
|
||||
* **`type` بدلًا من `interface`** — أكثر مرونة وأسهل في التركيب
|
||||
* **النصوص الحرفية بدل التعدادات** — باستثناء تعدادات codegen الخاصة بـ GraphQL وواجهات برمجة تطبيقات المكتبة الداخلية
|
||||
* **بدون `any`** — يتم فرض TypeScript الصارم
|
||||
* **عدم استيراد الأنواع** — استخدم استيرادات عادية (مفروض بواسطة Oxlint `typescript/consistent-type-imports`)
|
||||
* **استخدم [Zod](https://github.com/colinhacks/zod)** للتحقق وقت التشغيل من الكائنات غير محددة النوع
|
||||
|
||||
## JavaScript
|
||||
|
||||
@@ -112,17 +112,17 @@ onClick?.();
|
||||
|
||||
## التسمية
|
||||
|
||||
* **Variables**: camelCase, descriptive (`email` not `value`, `fieldMetadata` not `fm`)
|
||||
* **Constants**: SCREAMING_SNAKE_CASE
|
||||
* **Types/Classes**: PascalCase
|
||||
* **Files/directories**: kebab-case (`.component.tsx`, `.service.ts`, `.entity.ts`)
|
||||
* **Event handlers**: `handleClick` (not `onClick` for the handler function)
|
||||
* **Component props**: prefix with component name (`ButtonProps`)
|
||||
* **Styled components**: prefix with `Styled` (`StyledTitle`)
|
||||
* **المتغيرات**: camelCase، وصفية (`email` وليس `value`، `fieldMetadata` وليس `fm`)
|
||||
* **الثوابت**: SCREAMING_SNAKE_CASE
|
||||
* **الأنواع/الفئات**: PascalCase
|
||||
* **الملفات/المجلدات**: kebab-case (`.component.tsx`, `.service.ts`, `.entity.ts`)
|
||||
* **معالجات الأحداث**: `handleClick` (وليس `onClick` لدالة المعالج)
|
||||
* **خصائص المكوّن**: ابدأ باسم المكوّن (`ButtonProps`)
|
||||
* **مكوّنات Styled**: ابدأ بـ `Styled` (`StyledTitle`)
|
||||
|
||||
## التنسيق
|
||||
|
||||
Use [Linaria](https://github.com/callstack/linaria) styled components. Use theme values — avoid hardcoded `px`, `rem`, or colors.
|
||||
استخدم مكوّنات [Linaria](https://github.com/callstack/linaria) المنسقة. استخدم قيم السمة — وتجنّب القيم المضمّنة صراحة مثل `px` و`rem` أو الألوان.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
@@ -142,7 +142,7 @@ const StyledButton = styled.button`
|
||||
|
||||
## استيرادات
|
||||
|
||||
Use aliases instead of relative paths:
|
||||
استخدم الأسماء المستعارة بدل المسارات النسبية:
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
@@ -153,7 +153,7 @@ import { Foo } from '~/testing/decorators/Foo';
|
||||
import { Bar } from '@/modules/bar/components/Bar';
|
||||
```
|
||||
|
||||
## Folder Structure
|
||||
## هيكلية المجلدات
|
||||
|
||||
```
|
||||
front
|
||||
@@ -171,6 +171,6 @@ front
|
||||
└── ui/ # Reusable UI components (display, input, feedback, ...)
|
||||
```
|
||||
|
||||
* Modules can import from other modules, but `ui/` should stay dependency-free
|
||||
* Use `internal/` subfolders for module-private code
|
||||
* Components under 300 lines, services under 500 lines
|
||||
* يمكن للوحدات الاستيراد من وحدات أخرى، لكن يجب أن يبقى `ui/` خاليًا من التبعيات
|
||||
* استخدم المجلدات الفرعية `internal/` للشيفرة الخاصة بالوحدة
|
||||
* المكوّنات أقل من 300 سطر، والخدمات أقل من 500 سطر
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
---
|
||||
title: واجهات برمجة التطبيقات
|
||||
icon: plug
|
||||
description: REST and GraphQL APIs generated from your workspace schema.
|
||||
description: واجهات برمجة تطبيقات REST وGraphQL مُولَّدة من مخطط مساحة عملك.
|
||||
---
|
||||
|
||||
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
|
||||
|
||||
## Schema-per-tenant APIs
|
||||
## واجهات برمجة تطبيقات بمخطط لكل مستأجر
|
||||
|
||||
There is no static API reference for Twenty. Each workspace has its own schema — when you add a custom object (say `Invoice`), it immediately gets REST and GraphQL endpoints identical to built-in objects like `Company` or `Person`. The API is generated from the schema, so endpoints use your object and field names directly — no opaque IDs.
|
||||
لا توجد مرجعية ثابتة لواجهة برمجة التطبيقات الخاصة بـ Twenty. لكل مساحة عمل مخططها الخاص — عند إضافة كائن مخصص (مثل `Invoice`)، يحصل فورًا على نقاط نهاية REST وGraphQL مطابقة لتلك الخاصة بالكائنات المدمجة مثل `Company` أو `Person`. تُولَّد واجهة برمجة التطبيقات من المخطط، لذا تستخدم نقاط النهاية أسماء الكائنات والحقول لديك مباشرة — بدون معرّفات غامضة.
|
||||
|
||||
Your workspace-specific API documentation is available under **Settings → API & Webhooks** after creating an API key. It includes an interactive playground where you can execute real calls against your data.
|
||||
وثائق واجهة برمجة التطبيقات الخاصة بمساحة عملك متاحة ضمن **الإعدادات → واجهات برمجة التطبيقات وخطافات الويب** بعد إنشاء مفتاح API. يتضمن ساحة تجريبية تفاعلية يمكنك من خلالها تنفيذ استدعاءات حقيقية على بياناتك.
|
||||
|
||||
## Two APIs
|
||||
## واجهتا برمجة تطبيقات
|
||||
|
||||
**Core API** — `/rest/` and `/graphql/`
|
||||
**واجهة برمجة التطبيقات الأساسية** — `/rest/` و`/graphql/`
|
||||
|
||||
CRUD on records: People, Companies, Opportunities, your custom objects. Query, filter, traverse relations.
|
||||
عمليات CRUD على السجلات: الأشخاص، الشركات، الفرص، وكائناتك المخصصة. استعلام، تصفية، والتنقل عبر العلاقات.
|
||||
|
||||
**Metadata API** — `/rest/metadata/` and `/metadata/`
|
||||
**واجهة برمجة تطبيقات البيانات الوصفية** — `/rest/metadata/` و`/metadata/`
|
||||
|
||||
Schema management: create/modify/delete objects, fields, and relations. This is how you programmatically change your data model.
|
||||
إدارة المخطط: إنشاء/تعديل/حذف الكائنات والحقول والعلاقات. هذه هي الطريقة لتغيير نموذج بياناتك برمجيًا.
|
||||
|
||||
Both are available as REST and GraphQL. GraphQL adds batch upserts and the ability to traverse relations in a single query. Same underlying data either way.
|
||||
كلاهما متاحان عبر REST وGraphQL. تضيف GraphQL عمليات upsert على دفعات وإمكانية التنقل عبر العلاقات في استعلام واحد. نفس البيانات الأساسية بأي من الطريقتين.
|
||||
|
||||
## Base URLs
|
||||
## عناوين URL الأساسية
|
||||
|
||||
| البيئة | عنوان URL الأساسي |
|
||||
| ----------- | ------------------------- |
|
||||
| Cloud | `https://api.twenty.com/` |
|
||||
| Self-Hosted | `https://{your-domain}/` |
|
||||
| البيئة | عنوان URL الأساسي |
|
||||
| ----------------- | ------------------------- |
|
||||
| السحابة | `https://api.twenty.com/` |
|
||||
| الاستضافة الذاتية | `https://{your-domain}/` |
|
||||
|
||||
## المصادقة
|
||||
|
||||
@@ -37,19 +37,19 @@ Both are available as REST and GraphQL. GraphQL adds batch upserts and the abili
|
||||
Authorization: Bearer YOUR_API_KEY
|
||||
```
|
||||
|
||||
Create an API key in **Settings → API & Webhooks → + Create key**. Copy it immediately — it's shown once. Keys can be scoped to a specific role under **Settings → Roles → Assignment tab** to limit what they can access.
|
||||
أنشئ مفتاح API من **الإعدادات → واجهات برمجة التطبيقات وخطافات الويب → + Create key**. انسخه فورًا — يُعرَض مرة واحدة فقط. يمكن تقييد نطاق المفاتيح بدور محدد ضمن **الإعدادات → الأدوار → علامة التبويب Assignment** للحد مما يمكنها الوصول إليه.
|
||||
|
||||
<VimeoEmbed videoId="928786722" title="إنشاء مفتاح API" />
|
||||
|
||||
For OAuth-based access (external apps acting on behalf of users), see [OAuth](/l/ar/developers/extend/oauth).
|
||||
للوصول المعتمد على OAuth (تطبيقات خارجية تتصرف نيابةً عن المستخدمين)، راجع [OAuth](/l/ar/developers/extend/oauth).
|
||||
|
||||
## Batch operations
|
||||
## عمليات الدفعات
|
||||
|
||||
Both REST and GraphQL support batching up to 60 records per request — create, update, or delete. GraphQL also supports batch upsert (create-or-update in one call) using plural names like `CreateCompanies`.
|
||||
يدعم كلٌّ من REST وGraphQL التجميع لما يصل إلى 60 سجلًا لكل طلب — إنشاء أو تحديث أو حذف. كما تدعم GraphQL عملية upsert على دفعات (إنشاء-أو-تحديث في استدعاء واحد) باستخدام أسماء جمع مثل `CreateCompanies`.
|
||||
|
||||
## Rate limits
|
||||
## حدود المعدل
|
||||
|
||||
| الحد | القيمة |
|
||||
| ---------- | ------------------ |
|
||||
| Requests | 100 per minute |
|
||||
| Batch size | 60 سجل لكل استدعاء |
|
||||
| الحد | القيمة |
|
||||
| ---------- | ---------------------- |
|
||||
| الطلبات | 100 استدعاء في الدقيقة |
|
||||
| حجم الدفعة | 60 سجل لكل استدعاء |
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
title: الهيكلية
|
||||
description: How Twenty apps work — sandboxing, lifecycle, and the building blocks.
|
||||
description: كيف تعمل تطبيقات Twenty — العزل، دورة الحياة، واللبنات الأساسية.
|
||||
icon: sitemap
|
||||
---
|
||||
|
||||
Twenty apps are TypeScript packages that extend your workspace with custom objects, logic, UI components, and AI capabilities. They run on the Twenty platform with full sandboxing and permission controls.
|
||||
تطبيقات Twenty هي حزم TypeScript توسّع مساحة عملك بكائنات مخصّصة، ومنطق، ومكوّنات واجهة مستخدم (UI)، وقدرات ذكاء اصطناعي. تعمل على منصة Twenty مع عزل كامل وضوابط الأذونات.
|
||||
|
||||
## How apps work
|
||||
## كيف تعمل التطبيقات
|
||||
|
||||
An app is a collection of **entities** declared using `defineEntity()` functions from the `twenty-sdk` package. The SDK detects these declarations via AST analysis at build time and produces a **manifest** — a complete description of what your app adds to a workspace.
|
||||
التطبيق عبارة عن مجموعة من **الكيانات** يتم إعلانها باستخدام دوال `defineEntity()` من حزمة `twenty-sdk`. يكتشف SDK هذه التصريحات عبر تحليل AST وقت البناء وينتج **ملف بيان** — وصفًا كاملًا لما يضيفه تطبيقك إلى مساحة العمل.
|
||||
|
||||
```
|
||||
your-app/
|
||||
@@ -29,32 +29,32 @@ your-app/
|
||||
```
|
||||
|
||||
<Note>
|
||||
**File organization is up to you.** Entity detection is AST-based — the SDK finds `export default defineEntity(...)` calls regardless of where the file lives. The folder structure above is a convention, not a requirement.
|
||||
**تنظيم الملفات متروك لك.** يعتمد اكتشاف الكيانات على AST — يعثر SDK على استدعاءات `export default defineEntity(...)` بغض النظر عن مكان وجود الملف. بنية المجلدات أعلاه هي اصطلاح وليست متطلبًا.
|
||||
</Note>
|
||||
|
||||
## Entity types
|
||||
## أنواع الكيانات
|
||||
|
||||
| كيان | الغرض | وثائق |
|
||||
| ------------------------ | ----------------------------------------- | ------------------------------------------------------------ |
|
||||
| **Application** | App identity, permissions, variables | [Data Model](/l/ar/developers/extend/apps/data-model) |
|
||||
| **Role** | Permission sets for objects and fields | [Data Model](/l/ar/developers/extend/apps/data-model) |
|
||||
| **الكائن** | Custom data tables with fields | [Data Model](/l/ar/developers/extend/apps/data-model) |
|
||||
| **الحقل** | Extend existing objects, define relations | [Data Model](/l/ar/developers/extend/apps/data-model) |
|
||||
| **Logic Function** | Server-side TypeScript with triggers | [الوظائف المنطقية](/l/ar/developers/extend/apps/logic-functions) |
|
||||
| **Front Component** | Sandboxed React UI in Twenty's page | [Front Components](/l/ar/developers/extend/apps/front-components) |
|
||||
| **Skill** | Reusable AI agent instructions | [Skills & Agents](/l/ar/developers/extend/apps/skills-and-agents) |
|
||||
| **Agent** | AI assistants with custom prompts | [Skills & Agents](/l/ar/developers/extend/apps/skills-and-agents) |
|
||||
| **View** | Pre-configured record list views | [Layout](/l/ar/developers/extend/apps/layout) |
|
||||
| **Navigation Menu Item** | Custom sidebar entries | [Layout](/l/ar/developers/extend/apps/layout) |
|
||||
| **Page Layout** | Custom record page tabs and widgets | [Layout](/l/ar/developers/extend/apps/layout) |
|
||||
| كيان | الغرض | وثائق |
|
||||
| ---------------------- | ------------------------------------------------------ | -------------------------------------------------------------- |
|
||||
| **تطبيق** | هوية التطبيق، الأذونات، المتغيرات | [نموذج البيانات](/l/ar/developers/extend/apps/data-model) |
|
||||
| **دور** | مجموعات الأذونات للكائنات والحقول | [نموذج البيانات](/l/ar/developers/extend/apps/data-model) |
|
||||
| **الكائن** | جداول بيانات مخصّصة مع حقول | [نموذج البيانات](/l/ar/developers/extend/apps/data-model) |
|
||||
| **الحقل** | توسيع الكائنات الموجودة، تعريف العلاقات | [نموذج البيانات](/l/ar/developers/extend/apps/data-model) |
|
||||
| **دالة منطقية** | TypeScript على جانب الخادم مع مشغّلات | [الوظائف المنطقية](/l/ar/developers/extend/apps/logic-functions) |
|
||||
| **مكوّن أمامي** | واجهة مستخدم React معزولة داخل صفحة Twenty. | [المكوّنات الأمامية](/l/ar/developers/extend/apps/front-components) |
|
||||
| **مهارة** | تعليمات قابلة لإعادة الاستخدام لوكلاء الذكاء الاصطناعي | [المهارات والوكلاء](/l/ar/developers/extend/apps/skills-and-agents) |
|
||||
| **وكيل** | مساعدو الذكاء الاصطناعي بموجهات مخصّصة | [المهارات والوكلاء](/l/ar/developers/extend/apps/skills-and-agents) |
|
||||
| **عرض** | عروض قوائم السجلات المكوّنة مسبقًا | [التخطيط](/l/ar/developers/extend/apps/layout) |
|
||||
| **عنصر قائمة التنقّل** | عناصر الشريط الجانبي المخصّصة | [التخطيط](/l/ar/developers/extend/apps/layout) |
|
||||
| **تخطيط الصفحة** | علامات تبويب وعناصر واجهة مخصّصة لصفحة السجل | [التخطيط](/l/ar/developers/extend/apps/layout) |
|
||||
|
||||
## Sandboxing
|
||||
## العزل
|
||||
|
||||
* **Logic functions** run in isolated Node.js processes on the server. They only access data through the typed API client, scoped to the app's role permissions.
|
||||
* **Front components** run in Web Workers using Remote DOM — sandboxed from the main page but rendering native DOM elements (not iframes). They communicate with Twenty via a message-passing host API.
|
||||
* **Permissions** are enforced at the API level. The runtime token (`TWENTY_APP_ACCESS_TOKEN`) is derived from the role defined in `defineApplication()`.
|
||||
* **الدوال المنطقية** تعمل في عمليات Node.js معزولة على الخادم. لا تصل إلى البيانات إلا عبر عميل API مضبوط الأنواع، ومقيَّد بأذونات دور التطبيق.
|
||||
* **المكوّنات الأمامية** تعمل ضمن Web Workers باستخدام Remote DOM — معزولة عن الصفحة الرئيسية لكنها تعرض عناصر DOM الأصلية (وليس iframes). تتواصل مع Twenty عبر واجهة API للمضيف تعتمد تمرير الرسائل.
|
||||
* **الأذونات** تُطبَّق على مستوى واجهة API. يُشتق رمز وقت التشغيل (`TWENTY_APP_ACCESS_TOKEN`) من الدور المعرَّف في `defineApplication()`.
|
||||
|
||||
## App lifecycle
|
||||
## دورة حياة التطبيق
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
@@ -73,32 +73,32 @@ your-app/
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
* **`yarn twenty dev`** — watches your source files and live-syncs changes to a connected Twenty server. The typed API client is regenerated automatically when the schema changes.
|
||||
* **`yarn twenty build`** — compiles TypeScript, bundles logic functions and front components with esbuild, and produces a manifest.
|
||||
* **Pre/post-install hooks** — optional logic functions that run during installation. See [Logic Functions](/l/ar/developers/extend/apps/logic-functions) for details.
|
||||
* **`yarn twenty dev`** — يراقب ملفات المصدر لديك ويزامن التغييرات مباشرةً إلى خادم Twenty متصل. يُعاد توليد عميل API مضبوط الأنواع تلقائيًا عند تغيّر المخطط.
|
||||
* **`yarn twenty build`** — يجمّع TypeScript، ويضمّن الدوال المنطقية والمكوّنات الأمامية باستخدام esbuild، وينتج ملف بيان.
|
||||
* **خطّافات ما قبل/ما بعد التثبيت** — دوال منطقية اختيارية تعمل أثناء التثبيت. راجع [الدوال المنطقية](/l/ar/developers/extend/apps/logic-functions) للحصول على التفاصيل.
|
||||
|
||||
## الخطوات التالية
|
||||
|
||||
<CardGroup cols={٢}>
|
||||
<Card title="نموذج البيانات" icon="database" href="/l/ar/developers/extend/apps/data-model">
|
||||
Define objects, fields, roles, and relations.
|
||||
عرّف الكائنات والحقول والأدوار والعلاقات.
|
||||
</Card>
|
||||
<Card title="الوظائف المنطقية" icon="bolt" href="/l/ar/developers/extend/apps/logic-functions">
|
||||
Server-side functions with HTTP, cron, and event triggers.
|
||||
دوال على جانب الخادم مع HTTP وcron ومشغّلات الأحداث.
|
||||
</Card>
|
||||
<Card title="المكوّنات الأمامية" icon="window-maximize" href="/l/ar/developers/extend/apps/front-components">
|
||||
Sandboxed React components inside Twenty's UI.
|
||||
مكوّنات React معزولة داخل واجهة مستخدم Twenty.
|
||||
</Card>
|
||||
<Card title="التخطيط" icon="table-columns" href="/l/ar/developers/extend/apps/layout">
|
||||
Views, navigation items, and record page layouts.
|
||||
العروض، وعناصر التنقّل، وتخطيطات صفحات السجل.
|
||||
</Card>
|
||||
<Card title="المهارات والوكلاء" icon="robot" href="/l/ar/developers/extend/apps/skills-and-agents">
|
||||
AI skills and agents with custom prompts.
|
||||
مهارات ووكلاء ذكاء اصطناعي بموجهات مخصّصة.
|
||||
</Card>
|
||||
<Card title="CLI & Testing" icon="terminal" href="/l/ar/developers/extend/apps/cli-and-testing">
|
||||
CLI commands, testing, assets, remotes, and CI.
|
||||
<Card title="CLI والاختبار" icon="terminal" href="/l/ar/developers/extend/apps/cli-and-testing">
|
||||
أوامر CLI، والاختبار، والأصول، والوحدات البعيدة، وCI.
|
||||
</Card>
|
||||
<Card title="النشر" icon="rocket" href="/l/ar/developers/extend/apps/publishing">
|
||||
Deploy to a server or publish to the marketplace.
|
||||
انشر إلى خادم أو انشر في السوق.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: المكوّنات الأمامية
|
||||
description: Build React components that render inside Twenty's UI with sandboxed isolation.
|
||||
description: أنشئ مكونات React تُعرَض داخل واجهة مستخدم Twenty ضمن بيئة معزولة (sandbox).
|
||||
icon: window-maximize
|
||||
---
|
||||
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
---
|
||||
title: التخطيط
|
||||
description: Define views, navigation menu items, and page layouts to shape how your app appears in Twenty.
|
||||
description: عرّف طرق العرض، وعناصر قائمة التنقّل، وتخطيطات الصفحات لتشكيل كيفية ظهور تطبيقك في Twenty.
|
||||
icon: table-columns
|
||||
---
|
||||
|
||||
Layout entities control how your app surfaces inside Twenty's UI — what lives in the sidebar, which saved views ship with the app, and how a record detail page is arranged.
|
||||
تتحكّم كيانات التخطيط في كيفية ظهور تطبيقك داخل واجهة مستخدم Twenty — ما الذي يوجد في الشريط الجانبي، وأي العروض المحفوظة تأتي مع التطبيق، وكيف يتم ترتيب صفحة تفاصيل السجل.
|
||||
|
||||
## Layout concepts
|
||||
## مفاهيم التخطيط
|
||||
|
||||
| Concept | What it controls | كيان |
|
||||
| ------------------------ | --------------------------------------------------------------------------------- | -------------------------- |
|
||||
| **View** | A saved list configuration for an object — visible fields, order, filters, groups | `defineView` |
|
||||
| **Navigation Menu Item** | An entry in the left sidebar that links to a view or an external URL | `defineNavigationMenuItem` |
|
||||
| **Page Layout** | The tabs and widgets that make up a record's detail page | `definePageLayout` |
|
||||
| المفهوم | ما الذي يتحكّم فيه | كيان |
|
||||
| ---------------------- | ------------------------------------------------------------------------------- | -------------------------- |
|
||||
| **عرض** | تكوين قائمة محفوظة لكائن — الحقول المرئية، والترتيب، وعوامل التصفية، والمجموعات | `defineView` |
|
||||
| **عنصر قائمة التنقّل** | عنصر في الشريط الجانبي الأيسر يرتبط بعرض أو بعنوان URL خارجي | `defineNavigationMenuItem` |
|
||||
| **تخطيط الصفحة** | علامات التبويب وعناصر الواجهة التي تشكّل صفحة تفاصيل السجل | `definePageLayout` |
|
||||
|
||||
Views, navigation items, and page layouts reference each other by `universalIdentifier`:
|
||||
تشير العروض، وعناصر التنقّل، وتخطيطات الصفحات إلى بعضها البعض عبر `universalIdentifier`:
|
||||
|
||||
* A **navigation menu item** of type `VIEW` points at a `defineView` identifier, so the sidebar link opens that saved view.
|
||||
* A **page layout** of type `RECORD_PAGE` targets an object and can embed [front components](/l/ar/developers/extend/apps/front-components) inside its tabs as widgets.
|
||||
* يشير **عنصر قائمة التنقّل** من النوع `VIEW` إلى معرّف `defineView`، بحيث يفتح رابط الشريط الجانبي ذلك العرض المحفوظ.
|
||||
* يستهدف **تخطيط الصفحة** من النوع `RECORD_PAGE` كائنًا ويمكنه تضمين [مكوّنات الواجهة الأمامية](/l/ar/developers/extend/apps/front-components) داخل علامات التبويب الخاصة به بوصفها عناصر واجهة.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineView" description="تعريف العروض المحفوظة للكائنات">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: المهارات والوكلاء
|
||||
description: Define AI skills and agents for your app.
|
||||
description: عرّف مهارات ووكلاء الذكاء الاصطناعي لتطبيقك.
|
||||
icon: robot
|
||||
---
|
||||
|
||||
@@ -8,7 +8,7 @@ icon: robot
|
||||
Skills and agents are currently in alpha. الميزة تعمل لكنها لا تزال قيد التطور.
|
||||
</Warning>
|
||||
|
||||
Apps can define AI capabilities that live inside the workspace — reusable skill instructions and agents with custom system prompts.
|
||||
يمكن للتطبيقات تعريف قدرات ذكاء اصطناعي تعمل داخل مساحة العمل — تعليمات مهارات قابلة لإعادة الاستخدام ووكلاء بموجهات نظام مخصّصة.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineSkill" description="عرّف مهارات وكلاء الذكاء الاصطناعي">
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
---
|
||||
title: OAuth
|
||||
icon: المفتاح
|
||||
description: Authorization code flow with PKCE and client credentials for server-to-server access.
|
||||
description: تدفق رمز التفويض مع PKCE وبيانات اعتماد العميل للوصول من خادم إلى خادم.
|
||||
---
|
||||
|
||||
Twenty implements OAuth 2.0 with authorization code + PKCE for user-facing apps and client credentials for server-to-server access. Clients are registered dynamically via [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) — no manual setup in a dashboard.
|
||||
تُطبِّق Twenty بروتوكول OAuth 2.0 باستخدام رمز التفويض + PKCE للتطبيقات المواجهة للمستخدم، وبيانات اعتماد العميل للوصول من خادم إلى خادم. يُجرى تسجيل العملاء ديناميكيًا عبر [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) — دون إعداد يدوي في لوحة التحكم.
|
||||
|
||||
## When to Use OAuth
|
||||
## متى تستخدم OAuth
|
||||
|
||||
| السيناريو | Auth Method |
|
||||
| --------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| Internal scripts, automation | [API Key](/l/ar/developers/extend/api#authentication) |
|
||||
| External app acting on behalf of a user | **OAuth — Authorization Code** |
|
||||
| Server-to-server, no user context | **OAuth — Client Credentials** |
|
||||
| Twenty App with UI extensions | [Apps](/l/ar/developers/extend/apps/getting-started) (OAuth is handled automatically) |
|
||||
| السيناريو | طريقة المصادقة |
|
||||
| -------------------------------------------- | ------------------------------------------------------------------------------------ |
|
||||
| البرامج النصية الداخلية، والأتمتة | [مفتاح API](/l/ar/developers/extend/api#authentication) |
|
||||
| تطبيق خارجي يعمل نيابةً عن مستخدم | **OAuth — رمز التفويض** |
|
||||
| من خادم إلى خادم، دون سياق مستخدم | **OAuth — بيانات اعتماد العميل** |
|
||||
| تطبيق Twenty مع امتدادات واجهة المستخدم (UI) | [التطبيقات](/l/ar/developers/extend/apps/getting-started) (يتم التعامل مع OAuth تلقائيًا) |
|
||||
|
||||
## Register a Client
|
||||
## تسجيل عميل
|
||||
|
||||
Twenty supports **dynamic client registration** per [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). No manual setup needed — register programmatically:
|
||||
تدعم Twenty **التسجيل الديناميكي للعملاء** وفقًا لـ[RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). لا حاجة إلى إعداد يدوي — سجّل برمجيًا:
|
||||
|
||||
```bash
|
||||
POST /oauth/register
|
||||
@@ -31,7 +31,7 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**الاستجابة:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -43,23 +43,23 @@ Content-Type: application/json
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Store the `client_secret` securely — it cannot be retrieved later.
|
||||
احفظ `client_secret` بأمان — لا يمكن استرجاعه لاحقًا.
|
||||
</Warning>
|
||||
|
||||
## النطاقات
|
||||
|
||||
| Scope | الوصول |
|
||||
| --------- | ---------------------------------------------------- |
|
||||
| `api` | Full read/write access to the Core and Metadata APIs |
|
||||
| `profile` | Read the authenticated user's profile information |
|
||||
| النطاق | الوصول |
|
||||
| --------- | -------------------------------------------------------------- |
|
||||
| `api` | إمكانية قراءة/كتابة كاملة لواجهات برمجة تطبيقات Core وMetadata |
|
||||
| `profile` | قراءة معلومات ملف تعريف المستخدم المُصادَق عليه |
|
||||
|
||||
Request scopes as a space-separated string: `scope=api profile`
|
||||
اطلب النطاقات كسلسلة مفصولة بمسافات: `scope=api profile`
|
||||
|
||||
## Authorization Code Flow
|
||||
## تدفق رمز التفويض
|
||||
|
||||
Use this flow when your app acts on behalf of a Twenty user.
|
||||
استخدم هذا التدفق عندما يعمل تطبيقك نيابةً عن مستخدم Twenty.
|
||||
|
||||
### 1. Redirect the user to authorize
|
||||
### 1. أعد توجيه المستخدم للتفويض
|
||||
|
||||
```
|
||||
GET /oauth/authorize?
|
||||
@@ -72,29 +72,29 @@ GET /oauth/authorize?
|
||||
code_challenge_method=S256
|
||||
```
|
||||
|
||||
| المعلمة | مطلوب | الوصف |
|
||||
| ----------------------- | -------- | ------------------------------------------------------------ |
|
||||
| `client_id` | نعم | Your registered client ID |
|
||||
| `response_type` | نعم | Must be `code` |
|
||||
| `redirect_uri` | نعم | Must match a registered redirect URI |
|
||||
| `scope` | لا | Space-separated scopes (defaults to `api`) |
|
||||
| `الحالة` | مُوصى به | Random string to prevent CSRF attacks |
|
||||
| `code_challenge` | مُوصى به | PKCE challenge (SHA-256 hash of verifier, base64url-encoded) |
|
||||
| `code_challenge_method` | مُوصى به | Must be `S256` when using PKCE |
|
||||
| المعلمة | مطلوب | الوصف |
|
||||
| ----------------------- | -------- | -------------------------------------------------------- |
|
||||
| `client_id` | نعم | معرّف العميل المسجّل الخاص بك |
|
||||
| `response_type` | نعم | يجب أن يكون `code` |
|
||||
| `redirect_uri` | نعم | يجب أن يطابق عنوان URI لإعادة التوجيه المسجّل |
|
||||
| `scope` | لا | نطاقات مفصولة بمسافات (القيمة الافتراضية هي `api`) |
|
||||
| `state` | مُوصى به | سلسلة عشوائية لمنع هجمات CSRF |
|
||||
| `code_challenge` | مُوصى به | تحدّي PKCE (تجزئة SHA-256 لـ verifier، بترميز base64url) |
|
||||
| `code_challenge_method` | مُوصى به | يجب أن تكون `S256` عند استخدام PKCE |
|
||||
|
||||
The user sees a consent screen and approves or denies access.
|
||||
يرى المستخدم شاشة موافقة ويوافق على الوصول أو يرفضه.
|
||||
|
||||
### ٢. Handle the callback
|
||||
### ٢. معالجة الاستدعاء المرتجع
|
||||
|
||||
After authorization, Twenty redirects back to your `redirect_uri`:
|
||||
بعد التفويض، تعيد Twenty التوجيه إلى `redirect_uri` الخاص بك:
|
||||
|
||||
```
|
||||
https://myapp.com/callback?code=AUTH_CODE&state=random_state_value
|
||||
```
|
||||
|
||||
Verify that `state` matches what you sent.
|
||||
تحقّق من أن قيمة `state` تطابق ما أرسلته.
|
||||
|
||||
### ٣. Exchange the code for tokens
|
||||
### ٣. استبدِل الرمز بالرموز
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -108,7 +108,7 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
code_verifier=YOUR_PKCE_VERIFIER
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**الاستجابة:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -119,14 +119,14 @@ code_verifier=YOUR_PKCE_VERIFIER
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Use the access token
|
||||
### 4. استخدم رمز الوصول
|
||||
|
||||
```bash
|
||||
GET /rest/companies
|
||||
Authorization: Bearer ACCESS_TOKEN
|
||||
```
|
||||
|
||||
### 5. Refresh when expired
|
||||
### 5. حدِّث عند انتهاء الصلاحية
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -138,9 +138,9 @@ client_id=YOUR_CLIENT_ID&
|
||||
client_secret=YOUR_CLIENT_SECRET
|
||||
```
|
||||
|
||||
## Client Credentials Flow
|
||||
## تدفق بيانات اعتماد العميل
|
||||
|
||||
For server-to-server integrations with no user interaction:
|
||||
لعمليات التكامل من خادم إلى خادم دون تفاعل مستخدم:
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -152,38 +152,38 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
scope=api
|
||||
```
|
||||
|
||||
The returned token has workspace-level access, not tied to any specific user.
|
||||
الرمز المُعاد يمتلك وصولًا على مستوى مساحة العمل، وغير مرتبط بأي مستخدم محدّد.
|
||||
|
||||
## Server Discovery
|
||||
## اكتشاف الخادم
|
||||
|
||||
Twenty publishes its OAuth configuration at a standard discovery endpoint:
|
||||
تنشر Twenty إعدادات OAuth الخاصة بها عند نقطة اكتشاف قياسية:
|
||||
|
||||
```
|
||||
GET /.well-known/oauth-authorization-server
|
||||
```
|
||||
|
||||
This returns all endpoints, supported grant types, scopes, and capabilities — useful for building generic OAuth clients.
|
||||
يعيد هذا جميع نقاط النهاية وأنواع المنح المدعومة والنطاقات والقدرات — وهو مفيد لبناء عملاء OAuth عامّين.
|
||||
|
||||
## API Endpoints Summary
|
||||
## ملخص نقاط نهاية API
|
||||
|
||||
| نقطة النهاية | الغرض |
|
||||
| ----------------------------------------- | --------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Server metadata discovery |
|
||||
| `/oauth/register` | Dynamic client registration |
|
||||
| `/oauth/authorize` | User authorization |
|
||||
| `/oauth/token` | Token exchange and refresh |
|
||||
| نقطة النهاية | الغرض |
|
||||
| ----------------------------------------- | -------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | اكتشاف بيانات تعريف الخادم |
|
||||
| `/oauth/register` | التسجيل الديناميكي للعميل |
|
||||
| `/oauth/authorize` | تفويض المستخدم |
|
||||
| `/oauth/token` | مبادلة الرموز وتحديثها |
|
||||
|
||||
| البيئة | عنوان URL الأساسي |
|
||||
| --------------------- | ------------------------ |
|
||||
| **السحابة** | `https://api.twenty.com` |
|
||||
| **الاستضافة الذاتية** | `https://{your-domain}` |
|
||||
|
||||
## OAuth vs API Keys
|
||||
## OAuth مقابل مفاتيح API
|
||||
|
||||
| | مفاتيح واجهة برمجة التطبيقات | OAuth |
|
||||
| ------------------ | ---------------------------- | -------------------------------------- |
|
||||
| **الإعداد** | Generate in Settings | Register a client, implement flow |
|
||||
| **User context** | None (workspace-level) | Specific user's permissions |
|
||||
| **الأفضل لـ** | Scripts, internal tools | External apps, multi-user integrations |
|
||||
| **Token rotation** | يدوي | Automatic via refresh tokens |
|
||||
| **Scoped access** | Full API access | Granular via scopes |
|
||||
| | مفاتيح واجهة برمجة التطبيقات | OAuth |
|
||||
| ------------------------ | -------------------------------- | ------------------------------------------ |
|
||||
| **الإعداد** | إنشاء من الإعدادات | تسجيل عميل، وتنفيذ التدفق |
|
||||
| **سياق المستخدم** | لا يوجد (على مستوى مساحة العمل) | أذونات مستخدم محدّد |
|
||||
| **الأفضل لـ** | البرامج النصية، الأدوات الداخلية | تطبيقات خارجية، وتكاملات متعددة المستخدمين |
|
||||
| **تدوير الرموز** | يدوي | تلقائي عبر رموز التحديث |
|
||||
| **وصول محدود بالنطاقات** | وصول كامل إلى API | تفصيلي عبر النطاقات |
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: خطافات الويب
|
||||
icon: satellite-dish
|
||||
description: Get notified when records change — HTTP POST to your endpoint on every create, update, or delete.
|
||||
description: احصل على إشعار عند تغيّر السجلات — سيتم إرسال طلب HTTP POST إلى endpoint الخاص بك عند كل عملية إنشاء أو تحديث أو حذف.
|
||||
---
|
||||
|
||||
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
|
||||
|
||||
Twenty sends an HTTP POST to your URL whenever a record is created, updated, or deleted. All object types are covered, including custom objects.
|
||||
يقوم Twenty بإرسال طلب HTTP POST إلى URL الخاص بك كلما تم إنشاء سجل أو تحديثه أو حذفه. جميع أنواع الكائنات مشمولة، بما في ذلك الكائنات المخصصة.
|
||||
|
||||
## إنشاء خطاف ويب
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ export const MyComponent = () => {
|
||||
<Tab title="المحددات">
|
||||
|
||||
|
||||
| المحددات | النوع | الوصف |
|
||||
| الخصائص | النوع | الوصف |
|
||||
| ------------------ | ----------------------- | ---------------------------------------------------------------------- |
|
||||
| linkToEntity | نص | الرابط إلى الكيان |
|
||||
| معرف الكيان | نص | المعرف الفريد للكيان |
|
||||
|
||||
@@ -26,9 +26,9 @@ export const MyComponent = () => {
|
||||
<Tab title="المحددات">
|
||||
|
||||
|
||||
| المحددات | النوع | الوصف |
|
||||
| -------- | ----------------- | ------------------------ |
|
||||
| محرر | `BlockNoteEditor` | مثيل أو تكوين محرر الكتل |
|
||||
| الخصائص | النوع | الوصف |
|
||||
| ------- | ----------------- | ------------------------ |
|
||||
| محرر | `BlockNoteEditor` | مثيل أو تكوين محرر الكتل |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ export const MyComponent = () => {
|
||||
<Tab title="المحددات">
|
||||
|
||||
|
||||
| المحددات | النوع | الوصف |
|
||||
| الخصائص | النوع | الوصف |
|
||||
| ----------------------- | ----------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
| معطل | قيمة منطقية | يقوم بتعطيل منتقى الأيقونات إذا تم تعيينه إلى `true` |
|
||||
| عند التغيير | دالة | الدالة الارتجاعية التي تُفعل عندما يختار المستخدم أيقونة. يستقبل كائنًا يحتوي على الخصائص `iconKey` و `Icon` |
|
||||
|
||||
@@ -23,7 +23,7 @@ export const MyComponent = () => {
|
||||
<Tab title="المحددات">
|
||||
|
||||
|
||||
| المحددات | النوع | الوصف |
|
||||
| الخصائص | النوع | الوصف |
|
||||
| ------------ | ----------- | --------------------------------------------------------------------------------- |
|
||||
| صورة | نص | 3946482746 45352F31 274435483129 27442544432A3148464A |
|
||||
| onUpload | دالة | الدالة التي تُستدعى عند قيام المستخدم بتحميل صورة جديدة. تستقبل كائن `File` كوسيط |
|
||||
|
||||
@@ -38,7 +38,7 @@ export const MyComponent = () => {
|
||||
<Tab title="المحددات">
|
||||
|
||||
|
||||
| المحددات | النوع | الوصف |
|
||||
| الخصائص | النوع | الوصف |
|
||||
| ----------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| اسم الفئة | نص | فئة CSS اختيارية للتنسيق الإضافي |
|
||||
| معطل | قيمة منطقية | عند ضبطها على `true`، يتم تعطيل تفاعل المستخدم مع المكون |
|
||||
|
||||
@@ -35,7 +35,7 @@ export const MyComponent = () => {
|
||||
<Tab title="المحددات">
|
||||
|
||||
|
||||
| المحددات | النوع | الوصف |
|
||||
| الخصائص | النوع | الوصف |
|
||||
| --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| اسم الفئة | نص | اسم فئة اختياري لتنسيقات إضافية |
|
||||
| روابط | مصفوفة | مصفوفة من الكائنات، يمثّل كلٌّ منها رابطًا في مسار التنقّل. كل كائن يحتوي على خاصية `children` (محتوى النص للرابط) وخاصية `href` اختيارية (رابط URL للتنقل إليه عند النقر على الرابط) |
|
||||
|
||||
@@ -30,7 +30,7 @@ export const MyComponent = () => {
|
||||
<Tab title="المحددات">
|
||||
|
||||
|
||||
| المحددات | النوع | الوصف |
|
||||
| الخصائص | النوع | الوصف |
|
||||
| ------------- | ----- | ----------------------------------------------------------------- |
|
||||
| الخطوة النشطة | رقم | مؤشر للخطوة النشطة حاليًا. هذا يحدد أي خطوة يجب إبرازها بشكل مرئي |
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Commands
|
||||
title: Příkazy
|
||||
icon: terminal
|
||||
description: Useful commands for developing Twenty.
|
||||
description: Užitečné příkazy pro vývoj Twenty.
|
||||
---
|
||||
|
||||
Commands can be run from the repository root using `npx nx`. Use `npx nx run {project}:{command}` for explicit targeting.
|
||||
Příkazy je možné spouštět z kořene repozitáře pomocí `npx nx`. Pro explicitní cílení použijte `npx nx run {project}:{command}`.
|
||||
|
||||
## Starting the App
|
||||
## Spuštění aplikace
|
||||
|
||||
```bash
|
||||
npx nx start twenty-front # Frontend dev server (http://localhost:3001)
|
||||
@@ -14,7 +14,7 @@ npx nx start twenty-server # Backend server (http://localhost:3000)
|
||||
npx nx run twenty-server:worker # Background worker
|
||||
```
|
||||
|
||||
## Database
|
||||
## Databáze
|
||||
|
||||
```bash
|
||||
npx nx database:reset twenty-server # Reset and seed database
|
||||
@@ -22,7 +22,7 @@ npx nx run twenty-server:database:migrate:prod # Run migrations
|
||||
npx nx run twenty-server:database:migrate:generate --name <name> --type <fast|slow> # Generate a migration
|
||||
```
|
||||
|
||||
## Linting
|
||||
## Lintování
|
||||
|
||||
```bash
|
||||
npx nx lint:diff-with-main twenty-front # Lint changed files (fastest)
|
||||
@@ -30,7 +30,7 @@ npx nx lint:diff-with-main twenty-server
|
||||
npx nx lint twenty-front --configuration=fix # Auto-fix
|
||||
```
|
||||
|
||||
## Type Checking
|
||||
## Kontrola typů
|
||||
|
||||
```bash
|
||||
npx nx typecheck twenty-front
|
||||
@@ -68,7 +68,7 @@ npx nx run twenty-front:lingui:extract # Extract strings
|
||||
npx nx run twenty-front:lingui:compile # Compile translations
|
||||
```
|
||||
|
||||
## Build
|
||||
## Sestavení
|
||||
|
||||
```bash
|
||||
npx nx build twenty-shared # Must be built first
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
title: Stylová příručka
|
||||
icon: paintbrush
|
||||
description: Code conventions and best practices for contributing to Twenty.
|
||||
description: Konvence kódu a osvědčené postupy pro přispívání do Twenty.
|
||||
---
|
||||
|
||||
## React
|
||||
|
||||
### Functional components only
|
||||
### Pouze funkcionální komponenty
|
||||
|
||||
Always use TSX functional components with named exports.
|
||||
Vždy používejte funkcionální komponenty TSX s pojmenovanými exporty.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
@@ -25,7 +25,7 @@ export function MyComponent() {
|
||||
|
||||
### Vlastnosti
|
||||
|
||||
Create a type named `{ComponentName}Props`. Use destructuring. Don't use `React.FC`.
|
||||
Vytvořte typ s názvem `{ComponentName}Props`. Používejte destrukturalizaci. Nepoužívejte `React.FC`.
|
||||
|
||||
```tsx
|
||||
type MyComponentProps = {
|
||||
@@ -35,7 +35,7 @@ type MyComponentProps = {
|
||||
export const MyComponent = ({ name }: MyComponentProps) => <div>Hello {name}</div>;
|
||||
```
|
||||
|
||||
### No single-variable prop spreading
|
||||
### Nepoužívejte prop spreading jediné proměnné
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
@@ -47,7 +47,7 @@ const MyComponent = ({ prop1, prop2 }: MyComponentProps) => <Other {...{ prop1,
|
||||
|
||||
## Správa stavu
|
||||
|
||||
### Jotai atoms for global state
|
||||
### Atomy Jotai pro globální stav
|
||||
|
||||
```tsx
|
||||
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
|
||||
@@ -59,16 +59,16 @@ export const myAtomState = createAtomState<string>({
|
||||
});
|
||||
```
|
||||
|
||||
* Prefer atoms over prop drilling
|
||||
* Don't use `useRef` for state — use `useState` or atoms
|
||||
* Use atom families and selectors for lists
|
||||
* Upřednostňujte atomy před prop drillingem
|
||||
* Nepoužívejte `useRef` pro stav — použijte `useState` nebo atomy
|
||||
* Používejte rodiny atomů a selektory pro seznamy
|
||||
|
||||
### Avoid unnecessary re-renders
|
||||
### Vyhněte se zbytečnému opakovanému vykreslování
|
||||
|
||||
* Extract `useEffect` and data fetching into sibling sidecar components
|
||||
* Prefer event handlers (`handleClick`, `handleChange`) over `useEffect`
|
||||
* Don't use `React.memo()` — fix the root cause instead
|
||||
* Limit `useCallback` / `useMemo` usage
|
||||
* Přesuňte `useEffect` a načítání dat do sesterských sidecar komponent
|
||||
* Upřednostňujte obslužné funkce událostí (`handleClick`, `handleChange`) před `useEffect`
|
||||
* Nepoužívejte `React.memo()` — místo toho opravte kořenovou příčinu
|
||||
* Omezte používání `useCallback` / `useMemo`
|
||||
|
||||
```tsx
|
||||
// ❌ Bad — useEffect in the same component causes re-renders
|
||||
@@ -94,11 +94,11 @@ export const Page = () => {
|
||||
|
||||
## TypeScript
|
||||
|
||||
* **`type` over `interface`** — more flexible, easier to compose
|
||||
* **String literals over enums** — except for GraphQL codegen enums and internal library APIs
|
||||
* **No `any`** — strict TypeScript enforced
|
||||
* **No type imports** — use regular imports (enforced by Oxlint `typescript/consistent-type-imports`)
|
||||
* **Use [Zod](https://github.com/colinhacks/zod)** for runtime validation of untyped objects
|
||||
* **`type` místo `interface`** — flexibilnější, lépe kombinovatelný
|
||||
* **Řetězcové literály místo výčtů** — s výjimkou enumů GraphQL codegenu a interních API knihoven
|
||||
* **Žádné `any`** — vynucený přísný TypeScript
|
||||
* **Žádné importy typů** — používejte běžné importy (vynuceno nástrojem Oxlint `typescript/consistent-type-imports`)
|
||||
* **Používejte [Zod](https://github.com/colinhacks/zod)** pro runtime validaci netypovaných objektů
|
||||
|
||||
## JavaScript
|
||||
|
||||
@@ -112,17 +112,17 @@ onClick?.();
|
||||
|
||||
## Pojmenovávání
|
||||
|
||||
* **Variables**: camelCase, descriptive (`email` not `value`, `fieldMetadata` not `fm`)
|
||||
* **Constants**: SCREAMING_SNAKE_CASE
|
||||
* **Types/Classes**: PascalCase
|
||||
* **Files/directories**: kebab-case (`.component.tsx`, `.service.ts`, `.entity.ts`)
|
||||
* **Event handlers**: `handleClick` (not `onClick` for the handler function)
|
||||
* **Component props**: prefix with component name (`ButtonProps`)
|
||||
* **Styled components**: prefix with `Styled` (`StyledTitle`)
|
||||
* **Proměnné**: camelCase, popisné (`email` nikoli `value`, `fieldMetadata` nikoli `fm`)
|
||||
* **Konstanty**: SCREAMING_SNAKE_CASE
|
||||
* **Typy/Třídy**: PascalCase
|
||||
* **Soubory/adresáře**: kebab-case (`.component.tsx`, `.service.ts`, `.entity.ts`)
|
||||
* **Obslužné funkce událostí**: `handleClick` (nikoli `onClick` pro obslužnou funkci)
|
||||
* **Vlastnosti komponenty (props)**: předponu tvoří název komponenty (`ButtonProps`)
|
||||
* **Stylované komponenty**: předpona `Styled` (`StyledTitle`)
|
||||
|
||||
## Styling
|
||||
|
||||
Use [Linaria](https://github.com/callstack/linaria) styled components. Use theme values — avoid hardcoded `px`, `rem`, or colors.
|
||||
Používejte stylované komponenty [Linaria](https://github.com/callstack/linaria). Používejte hodnoty z tématu — vyhněte se napevno zadaným `px`, `rem` nebo barvám.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
@@ -142,7 +142,7 @@ const StyledButton = styled.button`
|
||||
|
||||
## Importy
|
||||
|
||||
Use aliases instead of relative paths:
|
||||
Používejte aliasy místo relativních cest:
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
@@ -153,7 +153,7 @@ import { Foo } from '~/testing/decorators/Foo';
|
||||
import { Bar } from '@/modules/bar/components/Bar';
|
||||
```
|
||||
|
||||
## Folder Structure
|
||||
## Struktura složek
|
||||
|
||||
```
|
||||
front
|
||||
@@ -171,6 +171,6 @@ front
|
||||
└── ui/ # Reusable UI components (display, input, feedback, ...)
|
||||
```
|
||||
|
||||
* Modules can import from other modules, but `ui/` should stay dependency-free
|
||||
* Use `internal/` subfolders for module-private code
|
||||
* Components under 300 lines, services under 500 lines
|
||||
* Moduly mohou importovat z jiných modulů, ale `ui/` by mělo zůstat bez závislostí
|
||||
* Používejte podadresáře `internal/` pro interní kód modulu
|
||||
* Komponenty do 300 řádků, služby do 500 řádků
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
title: Architektura
|
||||
description: How Twenty apps work — sandboxing, lifecycle, and the building blocks.
|
||||
description: Jak fungují aplikace Twenty — sandboxing, životní cyklus a stavební bloky.
|
||||
icon: sitemap
|
||||
---
|
||||
|
||||
Twenty apps are TypeScript packages that extend your workspace with custom objects, logic, UI components, and AI capabilities. They run on the Twenty platform with full sandboxing and permission controls.
|
||||
Aplikace Twenty jsou balíčky TypeScriptu, které rozšiřují váš pracovní prostor o vlastní objekty, logiku, komponenty UI a funkce AI. Běží na platformě Twenty s plnou izolací (sandboxingem) a řízením oprávnění.
|
||||
|
||||
## How apps work
|
||||
## Jak aplikace fungují
|
||||
|
||||
An app is a collection of **entities** declared using `defineEntity()` functions from the `twenty-sdk` package. The SDK detects these declarations via AST analysis at build time and produces a **manifest** — a complete description of what your app adds to a workspace.
|
||||
Aplikace je kolekce **entit** deklarovaných pomocí funkcí `defineEntity()` z balíčku `twenty-sdk`. SDK tyto deklarace detekuje pomocí analýzy AST při sestavení a vytváří **manifest** — úplný popis toho, co vaše aplikace přidává do pracovního prostoru.
|
||||
|
||||
```
|
||||
your-app/
|
||||
@@ -29,32 +29,32 @@ your-app/
|
||||
```
|
||||
|
||||
<Note>
|
||||
**File organization is up to you.** Entity detection is AST-based — the SDK finds `export default defineEntity(...)` calls regardless of where the file lives. The folder structure above is a convention, not a requirement.
|
||||
**Uspořádání souborů je na vás.** Detekce entit je založená na AST — SDK najde volání `export default defineEntity(...)` bez ohledu na to, kde se soubor nachází. Výše uvedená struktura složek je konvence, nikoli požadavek.
|
||||
</Note>
|
||||
|
||||
## Entity types
|
||||
## Typy entit
|
||||
|
||||
| Entita | Účel | Dokumentace |
|
||||
| ------------------------ | ----------------------------------------- | ------------------------------------------------------------ |
|
||||
| **Application** | App identity, permissions, variables | [Data Model](/l/cs/developers/extend/apps/data-model) |
|
||||
| **Role** | Permission sets for objects and fields | [Data Model](/l/cs/developers/extend/apps/data-model) |
|
||||
| **Objekt** | Custom data tables with fields | [Data Model](/l/cs/developers/extend/apps/data-model) |
|
||||
| **Pole** | Extend existing objects, define relations | [Data Model](/l/cs/developers/extend/apps/data-model) |
|
||||
| **Logic Function** | Server-side TypeScript with triggers | [Logické funkce](/l/cs/developers/extend/apps/logic-functions) |
|
||||
| **Front Component** | Sandboxed React UI in Twenty's page | [Front Components](/l/cs/developers/extend/apps/front-components) |
|
||||
| **Skill** | Reusable AI agent instructions | [Skills & Agents](/l/cs/developers/extend/apps/skills-and-agents) |
|
||||
| **Agent** | AI assistants with custom prompts | [Skills & Agents](/l/cs/developers/extend/apps/skills-and-agents) |
|
||||
| **View** | Pre-configured record list views | [Layout](/l/cs/developers/extend/apps/layout) |
|
||||
| **Navigation Menu Item** | Custom sidebar entries | [Layout](/l/cs/developers/extend/apps/layout) |
|
||||
| **Page Layout** | Custom record page tabs and widgets | [Layout](/l/cs/developers/extend/apps/layout) |
|
||||
| Entita | Účel | Dokumentace |
|
||||
| ----------------------------- | ----------------------------------------------- | ------------------------------------------------------------------ |
|
||||
| **Aplikace** | Identita aplikace, oprávnění, proměnné | [Datový model](/l/cs/developers/extend/apps/data-model) |
|
||||
| **Role** | Sady oprávnění pro objekty a pole | [Datový model](/l/cs/developers/extend/apps/data-model) |
|
||||
| **Objekt** | Vlastní datové tabulky s poli | [Datový model](/l/cs/developers/extend/apps/data-model) |
|
||||
| **Pole** | Rozšíření existujících objektů, definice relací | [Datový model](/l/cs/developers/extend/apps/data-model) |
|
||||
| **Logická funkce** | TypeScript na straně serveru se spouštěči | [Logické funkce](/l/cs/developers/extend/apps/logic-functions) |
|
||||
| **Frontendová komponenta** | Izolované React UI na stránce Twenty | [Frontendové komponenty](/l/cs/developers/extend/apps/front-components) |
|
||||
| **Dovednost** | Znovupoužitelné pokyny pro AI agenty | [Dovednosti a agenti](/l/cs/developers/extend/apps/skills-and-agents) |
|
||||
| **Agent** | AI asistenti s vlastními prompty | [Dovednosti a agenti](/l/cs/developers/extend/apps/skills-and-agents) |
|
||||
| **Pohled** | Předkonfigurovaná zobrazení seznamu záznamů | [Rozvržení](/l/cs/developers/extend/apps/layout) |
|
||||
| **Položka navigační nabídky** | Vlastní položky postranního panelu | [Rozvržení](/l/cs/developers/extend/apps/layout) |
|
||||
| **Rozvržení stránky** | Vlastní karty a widgety na stránce záznamu | [Rozvržení](/l/cs/developers/extend/apps/layout) |
|
||||
|
||||
## Sandboxing
|
||||
## Izolace (sandboxing)
|
||||
|
||||
* **Logic functions** run in isolated Node.js processes on the server. They only access data through the typed API client, scoped to the app's role permissions.
|
||||
* **Front components** run in Web Workers using Remote DOM — sandboxed from the main page but rendering native DOM elements (not iframes). They communicate with Twenty via a message-passing host API.
|
||||
* **Permissions** are enforced at the API level. The runtime token (`TWENTY_APP_ACCESS_TOKEN`) is derived from the role defined in `defineApplication()`.
|
||||
* **Logické funkce** běží v izolovaných procesech Node.js na serveru. K datům přistupují pouze prostřednictvím typovaného klienta API, a to v rozsahu oprávnění role aplikace.
|
||||
* **Frontendové komponenty** běží ve Web Workerech s využitím Remote DOM — jsou oddělené od hlavní stránky, ale vykreslují nativní prvky DOM (nikoli iframy). Komunikují s Twenty prostřednictvím hostitelského API pro předávání zpráv.
|
||||
* **Oprávnění** jsou vynucována na úrovni API. Běhový token (`TWENTY_APP_ACCESS_TOKEN`) je odvozen z role definované v `defineApplication()`.
|
||||
|
||||
## App lifecycle
|
||||
## Životní cyklus aplikace
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
@@ -73,32 +73,32 @@ your-app/
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
* **`yarn twenty dev`** — watches your source files and live-syncs changes to a connected Twenty server. The typed API client is regenerated automatically when the schema changes.
|
||||
* **`yarn twenty build`** — compiles TypeScript, bundles logic functions and front components with esbuild, and produces a manifest.
|
||||
* **Pre/post-install hooks** — optional logic functions that run during installation. See [Logic Functions](/l/cs/developers/extend/apps/logic-functions) for details.
|
||||
* **`yarn twenty dev`** — sleduje vaše zdrojové soubory a průběžně synchronizuje změny s připojeným serverem Twenty. Typovaný klient API se při změně schématu automaticky znovu vygeneruje.
|
||||
* **`yarn twenty build`** — zkompiluje TypeScript, zabalí logické funkce a frontendové komponenty pomocí esbuild a vytvoří manifest.
|
||||
* **Pre/post-install hooks** — volitelné logické funkce, které běží během instalace. Podrobnosti najdete v [Logických funkcích](/l/cs/developers/extend/apps/logic-functions).
|
||||
|
||||
## Další kroky
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Datový model" icon="database" href="/l/cs/developers/extend/apps/data-model">
|
||||
Define objects, fields, roles, and relations.
|
||||
Definujte objekty, pole, role a relace.
|
||||
</Card>
|
||||
<Card title="Logické funkce" icon="bolt" href="/l/cs/developers/extend/apps/logic-functions">
|
||||
Server-side functions with HTTP, cron, and event triggers.
|
||||
Funkce na straně serveru s HTTP, cron a událostními spouštěči.
|
||||
</Card>
|
||||
<Card title="Frontendové komponenty" icon="window-maximize" href="/l/cs/developers/extend/apps/front-components">
|
||||
Sandboxed React components inside Twenty's UI.
|
||||
Izolované komponenty Reactu v uživatelském rozhraní Twenty.
|
||||
</Card>
|
||||
<Card title="Rozvržení" icon="table-columns" href="/l/cs/developers/extend/apps/layout">
|
||||
Views, navigation items, and record page layouts.
|
||||
Pohledy, položky navigace a rozvržení stránek záznamů.
|
||||
</Card>
|
||||
<Card title="Dovednosti a agenti" icon="robot" href="/l/cs/developers/extend/apps/skills-and-agents">
|
||||
AI skills and agents with custom prompts.
|
||||
AI dovednosti a agenti s vlastními prompty.
|
||||
</Card>
|
||||
<Card title="CLI & Testing" icon="terminal" href="/l/cs/developers/extend/apps/cli-and-testing">
|
||||
CLI commands, testing, assets, remotes, and CI.
|
||||
<Card title="CLI a testování" icon="terminal" href="/l/cs/developers/extend/apps/cli-and-testing">
|
||||
Příkazy CLI, testování, prostředky, vzdálené zdroje a CI.
|
||||
</Card>
|
||||
<Card title="Publikování" icon="rocket" href="/l/cs/developers/extend/apps/publishing">
|
||||
Deploy to a server or publish to the marketplace.
|
||||
Nasaďte na server nebo publikujte na tržišti.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
---
|
||||
title: Rozvržení
|
||||
description: Define views, navigation menu items, and page layouts to shape how your app appears in Twenty.
|
||||
description: Definujte pohledy, položky navigační nabídky a rozvržení stránek, abyste utvářeli, jak se vaše aplikace zobrazuje v Twenty.
|
||||
icon: table-columns
|
||||
---
|
||||
|
||||
Layout entities control how your app surfaces inside Twenty's UI — what lives in the sidebar, which saved views ship with the app, and how a record detail page is arranged.
|
||||
Prvky rozvržení řídí, jak se vaše aplikace zobrazuje v uživatelském rozhraní Twenty — co je v postranním panelu, které uložené pohledy jsou součástí aplikace a jak je uspořádána stránka s podrobnostmi záznamu.
|
||||
|
||||
## Layout concepts
|
||||
## Pojmy rozvržení
|
||||
|
||||
| Concept | What it controls | Entita |
|
||||
| ------------------------ | --------------------------------------------------------------------------------- | -------------------------- |
|
||||
| **View** | A saved list configuration for an object — visible fields, order, filters, groups | `defineView` |
|
||||
| **Navigation Menu Item** | An entry in the left sidebar that links to a view or an external URL | `defineNavigationMenuItem` |
|
||||
| **Page Layout** | The tabs and widgets that make up a record's detail page | `definePageLayout` |
|
||||
| Pojem | Co řídí | Entita |
|
||||
| ----------------------------- | ------------------------------------------------------------------------------ | -------------------------- |
|
||||
| **Pohled** | Uložené nastavení seznamu pro objekt — viditelná pole, pořadí, filtry, skupiny | `defineView` |
|
||||
| **Položka navigační nabídky** | Položka v levém postranním panelu, která odkazuje na pohled nebo externí URL | `defineNavigationMenuItem` |
|
||||
| **Rozvržení stránky** | Karty a widgety, které tvoří stránku s podrobnostmi záznamu | `definePageLayout` |
|
||||
|
||||
Views, navigation items, and page layouts reference each other by `universalIdentifier`:
|
||||
Pohledy, položky navigační nabídky a rozvržení stránek se na sebe odkazují pomocí `universalIdentifier`:
|
||||
|
||||
* A **navigation menu item** of type `VIEW` points at a `defineView` identifier, so the sidebar link opens that saved view.
|
||||
* A **page layout** of type `RECORD_PAGE` targets an object and can embed [front components](/l/cs/developers/extend/apps/front-components) inside its tabs as widgets.
|
||||
* Položka **navigační nabídky** typu `VIEW` odkazuje na identifikátor `defineView`, takže odkaz v postranním panelu otevře daný uložený pohled.
|
||||
* **Rozvržení stránky** typu `RECORD_PAGE` cílí na objekt a může vkládat [front components](/l/cs/developers/extend/apps/front-components) do svých karet jako widgety.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineView" description="Definujte uložená zobrazení pro objekty">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Dovednosti a agenti
|
||||
description: Define AI skills and agents for your app.
|
||||
description: Definujte dovednosti a agenty AI pro svou aplikaci.
|
||||
icon: robot
|
||||
---
|
||||
|
||||
@@ -8,7 +8,7 @@ icon: robot
|
||||
Skills and agents are currently in alpha. Funkce funguje, ale stále se vyvíjí.
|
||||
</Warning>
|
||||
|
||||
Apps can define AI capabilities that live inside the workspace — reusable skill instructions and agents with custom system prompts.
|
||||
Aplikace mohou definovat schopnosti AI, které fungují přímo v pracovním prostoru — znovupoužitelné pokyny pro dovednosti a agenty s vlastními systémovými prompty.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineSkill" description="Definujte dovednosti agenta AI">
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
---
|
||||
title: OAuth
|
||||
icon: klíč
|
||||
description: Authorization code flow with PKCE and client credentials for server-to-server access.
|
||||
description: Tok s autorizačním kódem s PKCE a přihlašovacími údaji klienta pro přístup server-to-server.
|
||||
---
|
||||
|
||||
Twenty implements OAuth 2.0 with authorization code + PKCE for user-facing apps and client credentials for server-to-server access. Clients are registered dynamically via [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) — no manual setup in a dashboard.
|
||||
Twenty implementuje OAuth 2.0 s autorizačním kódem + PKCE pro aplikace pro uživatele a přihlašovací údaje klienta pro přístup server-to-server. Klienti se registrují dynamicky přes [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) — žádné ruční nastavení v dashboardu.
|
||||
|
||||
## When to Use OAuth
|
||||
## Kdy použít OAuth
|
||||
|
||||
| Scénář | Auth Method |
|
||||
| --------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| Internal scripts, automation | [API Key](/l/cs/developers/extend/api#authentication) |
|
||||
| External app acting on behalf of a user | **OAuth — Authorization Code** |
|
||||
| Server-to-server, no user context | **OAuth — Client Credentials** |
|
||||
| Twenty App with UI extensions | [Apps](/l/cs/developers/extend/apps/getting-started) (OAuth is handled automatically) |
|
||||
| Scénář | Metoda ověřování |
|
||||
| ---------------------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| Interní skripty, automatizace | [Klíč API](/l/cs/developers/extend/api#authentication) |
|
||||
| Externí aplikace jednající jménem uživatele | **OAuth — autorizační kód** |
|
||||
| Server-to-server, bez uživatelského kontextu | **OAuth — přihlašovací údaje klienta** |
|
||||
| Aplikace Twenty s rozšířeními uživatelského rozhraní | [Aplikace](/l/cs/developers/extend/apps/getting-started) (OAuth je řešen automaticky) |
|
||||
|
||||
## Register a Client
|
||||
## Registrace klienta
|
||||
|
||||
Twenty supports **dynamic client registration** per [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). No manual setup needed — register programmatically:
|
||||
Twenty podporuje **dynamickou registraci klienta** podle [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). Není potřeba žádné ruční nastavení — registrujte programově:
|
||||
|
||||
```bash
|
||||
POST /oauth/register
|
||||
@@ -31,7 +31,7 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**Odpověď:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -43,23 +43,23 @@ Content-Type: application/json
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Store the `client_secret` securely — it cannot be retrieved later.
|
||||
Uložte `client_secret` bezpečně — později jej nelze získat zpět.
|
||||
</Warning>
|
||||
|
||||
## Oprávnění
|
||||
|
||||
| Scope | Přístup |
|
||||
| -------- | ---------------------------------------------------- |
|
||||
| `api` | Full read/write access to the Core and Metadata APIs |
|
||||
| `profil` | Read the authenticated user's profile information |
|
||||
| Oprávnění | Přístup |
|
||||
| --------- | ----------------------------------------------------- |
|
||||
| `api` | Úplný přístup pro čtení i zápis k API Core a Metadata |
|
||||
| `profile` | Čtení informací o profilu ověřeného uživatele |
|
||||
|
||||
Request scopes as a space-separated string: `scope=api profile`
|
||||
Vyžádejte oprávnění jako řetězec oddělený mezerami: `scope=api profile`
|
||||
|
||||
## Authorization Code Flow
|
||||
## Tok s autorizačním kódem
|
||||
|
||||
Use this flow when your app acts on behalf of a Twenty user.
|
||||
Tento tok použijte, když vaše aplikace jedná jménem uživatele Twenty.
|
||||
|
||||
### 1. Redirect the user to authorize
|
||||
### 1. Přesměrujte uživatele k autorizaci
|
||||
|
||||
```
|
||||
GET /oauth/authorize?
|
||||
@@ -72,29 +72,29 @@ GET /oauth/authorize?
|
||||
code_challenge_method=S256
|
||||
```
|
||||
|
||||
| Parametr | Povinné | Popis |
|
||||
| ----------------------- | ---------- | ------------------------------------------------------------ |
|
||||
| `client_id` | Ano | Your registered client ID |
|
||||
| `response_type` | Ano | Must be `code` |
|
||||
| `redirect_uri` | Ano | Must match a registered redirect URI |
|
||||
| `scope` | Ne | Space-separated scopes (defaults to `api`) |
|
||||
| `stav` | Doporučeno | Random string to prevent CSRF attacks |
|
||||
| `code_challenge` | Doporučeno | PKCE challenge (SHA-256 hash of verifier, base64url-encoded) |
|
||||
| `code_challenge_method` | Doporučeno | Must be `S256` when using PKCE |
|
||||
| Parametr | Povinné | Popis |
|
||||
| ----------------------- | ---------- | -------------------------------------------------------------- |
|
||||
| `client_id` | Ano | Vaše registrované ID klienta |
|
||||
| `response_type` | Ano | Musí být `code` |
|
||||
| `redirect_uri` | Ano | Musí odpovídat registrované adrese URI pro přesměrování |
|
||||
| `scope` | Ne | Oprávnění oddělená mezerami (výchozí je `api`) |
|
||||
| `state` | Doporučeno | Náhodný řetězec k prevenci útoků CSRF |
|
||||
| `code_challenge` | Doporučeno | Výzva PKCE (hash SHA-256 z verifieru, kódovaný jako base64url) |
|
||||
| `code_challenge_method` | Doporučeno | Při použití PKCE musí být `S256` |
|
||||
|
||||
The user sees a consent screen and approves or denies access.
|
||||
Uživatel uvidí souhlasovou obrazovku a přístup schválí nebo zamítne.
|
||||
|
||||
### 2. Handle the callback
|
||||
### 2. Zpracujte callback
|
||||
|
||||
After authorization, Twenty redirects back to your `redirect_uri`:
|
||||
Po autorizaci Twenty přesměruje zpět na vaše `redirect_uri`:
|
||||
|
||||
```
|
||||
https://myapp.com/callback?code=AUTH_CODE&state=random_state_value
|
||||
```
|
||||
|
||||
Verify that `state` matches what you sent.
|
||||
Ověřte, že `state` odpovídá tomu, co jste poslali.
|
||||
|
||||
### 3. Exchange the code for tokens
|
||||
### 3. Vyměňte kód za tokeny
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -108,7 +108,7 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
code_verifier=YOUR_PKCE_VERIFIER
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**Odpověď:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -119,14 +119,14 @@ code_verifier=YOUR_PKCE_VERIFIER
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Use the access token
|
||||
### 4. Použijte přístupový token
|
||||
|
||||
```bash
|
||||
GET /rest/companies
|
||||
Authorization: Bearer ACCESS_TOKEN
|
||||
```
|
||||
|
||||
### 5. Refresh when expired
|
||||
### 5. Obnovte po vypršení platnosti
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -138,9 +138,9 @@ client_id=YOUR_CLIENT_ID&
|
||||
client_secret=YOUR_CLIENT_SECRET
|
||||
```
|
||||
|
||||
## Client Credentials Flow
|
||||
## Tok s přihlašovacími údaji klienta
|
||||
|
||||
For server-to-server integrations with no user interaction:
|
||||
Pro integrace server-to-server bez interakce uživatele:
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -152,38 +152,38 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
scope=api
|
||||
```
|
||||
|
||||
The returned token has workspace-level access, not tied to any specific user.
|
||||
Vrácený token má přístup na úrovni pracovního prostoru, není vázán na žádného konkrétního uživatele.
|
||||
|
||||
## Server Discovery
|
||||
## Zjišťování serveru
|
||||
|
||||
Twenty publishes its OAuth configuration at a standard discovery endpoint:
|
||||
Twenty zveřejňuje svou konfiguraci OAuth na standardním koncovém bodu pro zjišťování:
|
||||
|
||||
```
|
||||
GET /.well-known/oauth-authorization-server
|
||||
```
|
||||
|
||||
This returns all endpoints, supported grant types, scopes, and capabilities — useful for building generic OAuth clients.
|
||||
Vrací všechny koncové body, podporované typy grantů, oprávnění a možnosti — užitečné pro tvorbu obecných klientů OAuth.
|
||||
|
||||
## API Endpoints Summary
|
||||
## Přehled koncových bodů API
|
||||
|
||||
| Koncový bod | Účel |
|
||||
| ----------------------------------------- | --------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Server metadata discovery |
|
||||
| `/oauth/register` | Dynamic client registration |
|
||||
| `/oauth/authorize` | User authorization |
|
||||
| `/oauth/token` | Token exchange and refresh |
|
||||
| Koncový bod | Účel |
|
||||
| ----------------------------------------- | ---------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Zjišťování metadat serveru |
|
||||
| `/oauth/register` | Dynamická registrace klienta |
|
||||
| `/oauth/authorize` | Autorizace uživatele |
|
||||
| `/oauth/token` | Výměna a obnovení tokenu |
|
||||
|
||||
| Prostředí | Základní URL |
|
||||
| ------------------- | ------------------------ |
|
||||
| **Cloud** | `https://api.twenty.com` |
|
||||
| **Vlastní hosting** | `https://{your-domain}` |
|
||||
|
||||
## OAuth vs API Keys
|
||||
## OAuth vs klíče API
|
||||
|
||||
| | API Klíče | OAuth |
|
||||
| ------------------ | ----------------------- | -------------------------------------- |
|
||||
| **Nastavení** | Generate in Settings | Register a client, implement flow |
|
||||
| **User context** | None (workspace-level) | Specific user's permissions |
|
||||
| **Vhodné pro** | Scripts, internal tools | External apps, multi-user integrations |
|
||||
| **Token rotation** | Ruční | Automatic via refresh tokens |
|
||||
| **Scoped access** | Full API access | Granular via scopes |
|
||||
| | API Klíče | OAuth |
|
||||
| --------------------------- | ------------------------------------- | ------------------------------------------- |
|
||||
| **Nastavení** | Generovat v Nastavení | Zaregistrovat klienta, implementovat tok |
|
||||
| **Uživatelský kontext** | Žádný (na úrovni pracovního prostoru) | Oprávnění konkrétního uživatele |
|
||||
| **Vhodné pro** | Skripty, interní nástroje | Externí aplikace, víceuživatelské integrace |
|
||||
| **Rotace tokenů** | Ruční | Automaticky prostřednictvím refresh tokenů |
|
||||
| **Přístup podle oprávnění** | Plný přístup k API | Jemně odstupňovaný pomocí oprávnění |
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Webhooky
|
||||
icon: satellite-dish
|
||||
description: Get notified when records change — HTTP POST to your endpoint on every create, update, or delete.
|
||||
description: Dostávejte upozornění při změnách záznamů — HTTP POST na váš koncový bod při každém vytvoření, aktualizaci nebo smazání.
|
||||
---
|
||||
|
||||
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
|
||||
|
||||
Twenty sends an HTTP POST to your URL whenever a record is created, updated, or deleted. All object types are covered, including custom objects.
|
||||
Twenty odešle HTTP POST na vaši adresu URL pokaždé, když je záznam vytvořen, aktualizován nebo smazán. Všechny typy objektů jsou podporovány, včetně vlastních objektů.
|
||||
|
||||
## Vytvořit Webhook
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Řešení potíží
|
||||
icon: wrench
|
||||
icon: klíč
|
||||
---
|
||||
|
||||
## Řešení potíží
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Záznamové stránky},{
|
||||
title: Stránky záznamů
|
||||
description: Přizpůsobte rozvržení jednotlivých stránek detailu záznamu pomocí karet a widgetů.
|
||||
---
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Commands
|
||||
title: Befehle
|
||||
icon: terminal
|
||||
description: Useful commands for developing Twenty.
|
||||
description: Nützliche Befehle für die Entwicklung von Twenty.
|
||||
---
|
||||
|
||||
Commands can be run from the repository root using `npx nx`. Use `npx nx run {project}:{command}` for explicit targeting.
|
||||
Befehle können vom Repository-Stammverzeichnis mit `npx nx` ausgeführt werden. Verwende `npx nx run {project}:{command}` für eine explizite Zielangabe.
|
||||
|
||||
## Starting the App
|
||||
## Die App starten
|
||||
|
||||
```bash
|
||||
npx nx start twenty-front # Frontend dev server (http://localhost:3001)
|
||||
@@ -14,7 +14,7 @@ npx nx start twenty-server # Backend server (http://localhost:3000)
|
||||
npx nx run twenty-server:worker # Background worker
|
||||
```
|
||||
|
||||
## Database
|
||||
## Datenbank
|
||||
|
||||
```bash
|
||||
npx nx database:reset twenty-server # Reset and seed database
|
||||
@@ -30,7 +30,7 @@ npx nx lint:diff-with-main twenty-server
|
||||
npx nx lint twenty-front --configuration=fix # Auto-fix
|
||||
```
|
||||
|
||||
## Type Checking
|
||||
## Typprüfung
|
||||
|
||||
```bash
|
||||
npx nx typecheck twenty-front
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
title: Styleguide
|
||||
icon: paintbrush
|
||||
description: Code conventions and best practices for contributing to Twenty.
|
||||
description: Code-Konventionen und bewährte Verfahren für Beiträge zu Twenty.
|
||||
---
|
||||
|
||||
## React
|
||||
|
||||
### Functional components only
|
||||
### Ausschließlich funktionale Komponenten
|
||||
|
||||
Always use TSX functional components with named exports.
|
||||
Verwenden Sie immer TSX-Funktionskomponenten mit benannten Exporten.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
@@ -25,7 +25,7 @@ export function MyComponent() {
|
||||
|
||||
### Props
|
||||
|
||||
Create a type named `{ComponentName}Props`. Use destructuring. Don't use `React.FC`.
|
||||
Erstellen Sie einen Typ namens `{ComponentName}Props`. Verwenden Sie Destrukturierung. Verwenden Sie `React.FC` nicht.
|
||||
|
||||
```tsx
|
||||
type MyComponentProps = {
|
||||
@@ -35,7 +35,7 @@ type MyComponentProps = {
|
||||
export const MyComponent = ({ name }: MyComponentProps) => <div>Hello {name}</div>;
|
||||
```
|
||||
|
||||
### No single-variable prop spreading
|
||||
### Kein Prop-Spreading mit einer einzelnen Variablen
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
@@ -47,7 +47,7 @@ const MyComponent = ({ prop1, prop2 }: MyComponentProps) => <Other {...{ prop1,
|
||||
|
||||
## Zustandsverwaltung
|
||||
|
||||
### Jotai atoms for global state
|
||||
### Jotai-Atome für globalen Zustand
|
||||
|
||||
```tsx
|
||||
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
|
||||
@@ -59,16 +59,16 @@ export const myAtomState = createAtomState<string>({
|
||||
});
|
||||
```
|
||||
|
||||
* Prefer atoms over prop drilling
|
||||
* Don't use `useRef` for state — use `useState` or atoms
|
||||
* Use atom families and selectors for lists
|
||||
* Bevorzugen Sie Atome gegenüber Prop-Drilling
|
||||
* Verwenden Sie `useRef` nicht für den Zustand — verwenden Sie `useState` oder Atome
|
||||
* Verwenden Sie Atomfamilien und Selektoren für Listen
|
||||
|
||||
### Avoid unnecessary re-renders
|
||||
### Vermeiden Sie unnötige Re-Renders
|
||||
|
||||
* Extract `useEffect` and data fetching into sibling sidecar components
|
||||
* Prefer event handlers (`handleClick`, `handleChange`) over `useEffect`
|
||||
* Don't use `React.memo()` — fix the root cause instead
|
||||
* Limit `useCallback` / `useMemo` usage
|
||||
* Lagern Sie `useEffect` und das Daten-Fetching in gleichrangige Sidecar-Komponenten aus
|
||||
* Bevorzugen Sie Event-Handler (`handleClick`, `handleChange`) gegenüber `useEffect`
|
||||
* Verwenden Sie `React.memo()` nicht — beheben Sie stattdessen die Grundursache
|
||||
* Beschränken Sie die Nutzung von `useCallback`/`useMemo`
|
||||
|
||||
```tsx
|
||||
// ❌ Bad — useEffect in the same component causes re-renders
|
||||
@@ -94,11 +94,11 @@ export const Page = () => {
|
||||
|
||||
## TypeScript
|
||||
|
||||
* **`type` over `interface`** — more flexible, easier to compose
|
||||
* **String literals over enums** — except for GraphQL codegen enums and internal library APIs
|
||||
* **No `any`** — strict TypeScript enforced
|
||||
* **No type imports** — use regular imports (enforced by Oxlint `typescript/consistent-type-imports`)
|
||||
* **Use [Zod](https://github.com/colinhacks/zod)** for runtime validation of untyped objects
|
||||
* **`type` statt `interface`** — flexibler, leichter zu kombinieren
|
||||
* **String-Literale statt Enums** — außer für GraphQL-Codegen-Enums und interne Bibliotheks-APIs
|
||||
* **Kein `any`** — striktes TypeScript wird durchgesetzt
|
||||
* **Keine Type-Imports** — verwenden Sie reguläre Imports (erzwungen durch Oxlint `typescript/consistent-type-imports`)
|
||||
* **Verwenden Sie [Zod](https://github.com/colinhacks/zod)** für die Laufzeitvalidierung ungetypter Objekte
|
||||
|
||||
## JavaScript
|
||||
|
||||
@@ -112,17 +112,17 @@ onClick?.();
|
||||
|
||||
## Namensgebung
|
||||
|
||||
* **Variables**: camelCase, descriptive (`email` not `value`, `fieldMetadata` not `fm`)
|
||||
* **Constants**: SCREAMING_SNAKE_CASE
|
||||
* **Types/Classes**: PascalCase
|
||||
* **Files/directories**: kebab-case (`.component.tsx`, `.service.ts`, `.entity.ts`)
|
||||
* **Event handlers**: `handleClick` (not `onClick` for the handler function)
|
||||
* **Component props**: prefix with component name (`ButtonProps`)
|
||||
* **Styled components**: prefix with `Styled` (`StyledTitle`)
|
||||
* **Variablen**: camelCase, aussagekräftig (`email` statt `value`, `fieldMetadata` statt `fm`)
|
||||
* **Konstanten**: SCREAMING_SNAKE_CASE
|
||||
* **Typen/Klassen**: PascalCase
|
||||
* **Dateien/Verzeichnisse**: kebab-case (`.component.tsx`, `.service.ts`, `.entity.ts`)
|
||||
* **Event-Handler**: `handleClick` (nicht `onClick` für die Handler-Funktion)
|
||||
* **Komponenten-Props**: mit dem Komponentennamen präfixieren (`ButtonProps`)
|
||||
* **Styled Components**: mit `Styled` präfixieren (`StyledTitle`)
|
||||
|
||||
## Styling
|
||||
|
||||
Use [Linaria](https://github.com/callstack/linaria) styled components. Use theme values — avoid hardcoded `px`, `rem`, or colors.
|
||||
Verwenden Sie [Linaria](https://github.com/callstack/linaria) Styled Components. Verwenden Sie Theme-Werte — vermeiden Sie hartkodierte `px`, `rem` oder Farben.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
@@ -142,7 +142,7 @@ const StyledButton = styled.button`
|
||||
|
||||
## Importe
|
||||
|
||||
Use aliases instead of relative paths:
|
||||
Verwenden Sie Aliase statt relativer Pfade:
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
@@ -153,7 +153,7 @@ import { Foo } from '~/testing/decorators/Foo';
|
||||
import { Bar } from '@/modules/bar/components/Bar';
|
||||
```
|
||||
|
||||
## Folder Structure
|
||||
## Ordnerstruktur
|
||||
|
||||
```
|
||||
front
|
||||
@@ -171,6 +171,6 @@ front
|
||||
└── ui/ # Reusable UI components (display, input, feedback, ...)
|
||||
```
|
||||
|
||||
* Modules can import from other modules, but `ui/` should stay dependency-free
|
||||
* Use `internal/` subfolders for module-private code
|
||||
* Components under 300 lines, services under 500 lines
|
||||
* Module können aus anderen Modulen importieren, aber `ui/` sollte abhängigkeitsfrei bleiben
|
||||
* Verwenden Sie `internal/`-Unterordner für modulinternen Code
|
||||
* Komponenten unter 300 Zeilen, Services unter 500 Zeilen
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
---
|
||||
title: APIs
|
||||
icon: plug
|
||||
description: REST and GraphQL APIs generated from your workspace schema.
|
||||
description: Vom Schema Ihres Arbeitsbereichs generierte REST- und GraphQL-APIs.
|
||||
---
|
||||
|
||||
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
|
||||
|
||||
## Schema-per-tenant APIs
|
||||
## Schema-pro-Mandant-APIs
|
||||
|
||||
There is no static API reference for Twenty. Each workspace has its own schema — when you add a custom object (say `Invoice`), it immediately gets REST and GraphQL endpoints identical to built-in objects like `Company` or `Person`. The API is generated from the schema, so endpoints use your object and field names directly — no opaque IDs.
|
||||
Es gibt keine statische API-Referenz für Twenty. Jeder Arbeitsbereich hat sein eigenes Schema — wenn Sie ein benutzerdefiniertes Objekt hinzufügen (z. B. `Invoice`), erhält es sofort REST- und GraphQL-Endpunkte, die mit den integrierten Objekten wie `Company` oder `Person` identisch sind. Die API wird aus dem Schema generiert, daher verwenden die Endpunkte Ihre Objekt- und Feldnamen direkt — keine undurchsichtigen IDs.
|
||||
|
||||
Your workspace-specific API documentation is available under **Settings → API & Webhooks** after creating an API key. It includes an interactive playground where you can execute real calls against your data.
|
||||
Ihre arbeitsbereichsspezifische API-Dokumentation ist nach dem Erstellen eines API-Schlüssels unter **Einstellungen → API & Webhooks** verfügbar. Sie umfasst einen interaktiven Playground, in dem Sie echte Aufrufe gegen Ihre Daten ausführen können.
|
||||
|
||||
## Two APIs
|
||||
## Zwei APIs
|
||||
|
||||
**Core API** — `/rest/` and `/graphql/`
|
||||
**Core-API** — `/rest/` und `/graphql/`
|
||||
|
||||
CRUD on records: People, Companies, Opportunities, your custom objects. Query, filter, traverse relations.
|
||||
CRUD für Datensätze: Personen, Unternehmen, Verkaufschancen, Ihre benutzerdefinierten Objekte. Abfragen, filtern, Beziehungen durchlaufen.
|
||||
|
||||
**Metadata API** — `/rest/metadata/` and `/metadata/`
|
||||
**Metadaten-API** — `/rest/metadata/` und `/metadata/`
|
||||
|
||||
Schema management: create/modify/delete objects, fields, and relations. This is how you programmatically change your data model.
|
||||
Schemaverwaltung: Objekte, Felder und Beziehungen erstellen/ändern/löschen. So ändern Sie Ihr Datenmodell programmatisch.
|
||||
|
||||
Both are available as REST and GraphQL. GraphQL adds batch upserts and the ability to traverse relations in a single query. Same underlying data either way.
|
||||
Beide sind als REST und GraphQL verfügbar. GraphQL bietet Batch-Upserts und die Möglichkeit, Beziehungen in einer einzigen Abfrage zu durchlaufen. Die zugrunde liegenden Daten sind in beiden Fällen gleich.
|
||||
|
||||
## Base URLs
|
||||
## Basis-URLs
|
||||
|
||||
| Umgebung | Basis-URL |
|
||||
| ----------- | ------------------------- |
|
||||
| Cloud | `https://api.twenty.com/` |
|
||||
| Self-Hosted | `https://{your-domain}/` |
|
||||
| Umgebung | Basis-URL |
|
||||
| ------------- | ------------------------- |
|
||||
| Cloud | `https://api.twenty.com/` |
|
||||
| Selbsthosting | `https://{your-domain}/` |
|
||||
|
||||
## Authentifizierung
|
||||
|
||||
@@ -37,19 +37,19 @@ Both are available as REST and GraphQL. GraphQL adds batch upserts and the abili
|
||||
Authorization: Bearer YOUR_API_KEY
|
||||
```
|
||||
|
||||
Create an API key in **Settings → API & Webhooks → + Create key**. Copy it immediately — it's shown once. Keys can be scoped to a specific role under **Settings → Roles → Assignment tab** to limit what they can access.
|
||||
Erstellen Sie einen API-Schlüssel unter **Settings > APIs & Webhooks > + Create key**. Kopieren Sie ihn sofort — er wird nur einmal angezeigt. Schlüssel können unter **Settings > Roles > Assignment tab** auf eine bestimmte Rolle beschränkt werden, um ihren Zugriff einzuschränken.
|
||||
|
||||
<VimeoEmbed videoId="928786722" title="API-Schlüssel erstellen" />
|
||||
|
||||
For OAuth-based access (external apps acting on behalf of users), see [OAuth](/l/de/developers/extend/oauth).
|
||||
Für OAuth-basierten Zugriff (externe Apps, die im Namen von Nutzern handeln), siehe [OAuth](/l/de/developers/extend/oauth).
|
||||
|
||||
## Batch operations
|
||||
## Batch-Vorgänge
|
||||
|
||||
Both REST and GraphQL support batching up to 60 records per request — create, update, or delete. GraphQL also supports batch upsert (create-or-update in one call) using plural names like `CreateCompanies`.
|
||||
Sowohl REST als auch GraphQL unterstützen Batching von bis zu 60 Datensätzen pro Anfrage — erstellen, aktualisieren oder löschen. GraphQL unterstützt außerdem Batch-Upsert (Erstellen-oder-Aktualisieren in einem Aufruf) mit Pluralnamen wie `CreateCompanies`.
|
||||
|
||||
## Rate limits
|
||||
## Rate Limits
|
||||
|
||||
| Limit | Wert |
|
||||
| ---------- | ------------------------ |
|
||||
| Requests | 100 per minute |
|
||||
| Batch size | 60 Datensätze pro Aufruf |
|
||||
| Limit | Wert |
|
||||
| ----------- | ------------------------ |
|
||||
| Anfragen | 100 Aufrufe pro Minute |
|
||||
| Batch-Größe | 60 Datensätze pro Aufruf |
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
title: Architektur
|
||||
description: How Twenty apps work — sandboxing, lifecycle, and the building blocks.
|
||||
description: Wie Twenty-Apps funktionieren — Sandboxing, Lebenszyklus und Bausteine.
|
||||
icon: sitemap
|
||||
---
|
||||
|
||||
Twenty apps are TypeScript packages that extend your workspace with custom objects, logic, UI components, and AI capabilities. They run on the Twenty platform with full sandboxing and permission controls.
|
||||
Twenty-Apps sind TypeScript-Pakete, die Ihren Arbeitsbereich mit benutzerdefinierten Objekten, Logik, UI-Komponenten und KI-Funktionen erweitern. Sie laufen auf der Twenty-Plattform mit vollständigem Sandboxing und Berechtigungsverwaltung.
|
||||
|
||||
## How apps work
|
||||
## Wie Apps funktionieren
|
||||
|
||||
An app is a collection of **entities** declared using `defineEntity()` functions from the `twenty-sdk` package. The SDK detects these declarations via AST analysis at build time and produces a **manifest** — a complete description of what your app adds to a workspace.
|
||||
Eine App ist eine Sammlung von **Entitäten**, die mithilfe von `defineEntity()`-Funktionen aus dem Paket `twenty-sdk` deklariert werden. Das SDK erkennt diese Deklarationen zur Build-Zeit per AST-Analyse und erzeugt ein **Manifest** — eine vollständige Beschreibung dessen, was Ihre App zu einem Arbeitsbereich hinzufügt.
|
||||
|
||||
```
|
||||
your-app/
|
||||
@@ -29,32 +29,32 @@ your-app/
|
||||
```
|
||||
|
||||
<Note>
|
||||
**File organization is up to you.** Entity detection is AST-based — the SDK finds `export default defineEntity(...)` calls regardless of where the file lives. The folder structure above is a convention, not a requirement.
|
||||
**Die Dateiorganisation liegt bei Ihnen.** Die Entitätserkennung ist AST-basiert — das SDK findet Aufrufe von `export default defineEntity(...)`, unabhängig davon, wo sich die Datei befindet. Die obige Ordnerstruktur ist eine Konvention, keine Anforderung.
|
||||
</Note>
|
||||
|
||||
## Entity types
|
||||
## Entitätstypen
|
||||
|
||||
| Entität | Zweck | Dokumentation |
|
||||
| ------------------------ | ----------------------------------------- | ------------------------------------------------------------ |
|
||||
| **Application** | App identity, permissions, variables | [Data Model](/l/de/developers/extend/apps/data-model) |
|
||||
| **Role** | Permission sets for objects and fields | [Data Model](/l/de/developers/extend/apps/data-model) |
|
||||
| **Object** | Custom data tables with fields | [Data Model](/l/de/developers/extend/apps/data-model) |
|
||||
| **Feld** | Extend existing objects, define relations | [Data Model](/l/de/developers/extend/apps/data-model) |
|
||||
| **Logic Function** | Server-side TypeScript with triggers | [Logikfunktionen](/l/de/developers/extend/apps/logic-functions) |
|
||||
| **Front Component** | Sandboxed React UI in Twenty's page | [Front Components](/l/de/developers/extend/apps/front-components) |
|
||||
| **Skill** | Reusable AI agent instructions | [Skills & Agents](/l/de/developers/extend/apps/skills-and-agents) |
|
||||
| **Agent** | AI assistants with custom prompts | [Skills & Agents](/l/de/developers/extend/apps/skills-and-agents) |
|
||||
| **View** | Pre-configured record list views | [Layout](/l/de/developers/extend/apps/layout) |
|
||||
| **Navigation Menu Item** | Custom sidebar entries | [Layout](/l/de/developers/extend/apps/layout) |
|
||||
| **Page Layout** | Custom record page tabs and widgets | [Layout](/l/de/developers/extend/apps/layout) |
|
||||
| Entität | Zweck | Dokumentation |
|
||||
| -------------------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------- |
|
||||
| **Anwendung** | App-Identität, Berechtigungen, Variablen | [Datenmodell](/l/de/developers/extend/apps/data-model) |
|
||||
| **Rolle** | Berechtigungssätze für Objekte und Felder | [Datenmodell](/l/de/developers/extend/apps/data-model) |
|
||||
| **Object** | Benutzerdefinierte Datentabellen mit Feldern | [Datenmodell](/l/de/developers/extend/apps/data-model) |
|
||||
| **Feld** | Bestehende Objekte erweitern, Relationen definieren | [Datenmodell](/l/de/developers/extend/apps/data-model) |
|
||||
| **Logikfunktion** | Serverseitiges TypeScript mit Triggern | [Logikfunktionen](/l/de/developers/extend/apps/logic-functions) |
|
||||
| **Frontend-Komponente** | Sandboxed React-UI auf der Twenty-Seite | [Frontend-Komponenten](/l/de/developers/extend/apps/front-components) |
|
||||
| **Skill** | Wiederverwendbare Anweisungen für KI-Agenten | [Skills & Agenten](/l/de/developers/extend/apps/skills-and-agents) |
|
||||
| **Agent** | KI-Assistenten mit benutzerdefinierten Prompts | [Skills & Agenten](/l/de/developers/extend/apps/skills-and-agents) |
|
||||
| **Ansicht** | Vorkonfigurierte Listenansichten für Datensätze | [Layout](/l/de/developers/extend/apps/layout) |
|
||||
| **Navigationsmenüeintrag** | Benutzerdefinierte Seitenleisten-Einträge | [Layout](/l/de/developers/extend/apps/layout) |
|
||||
| **Seitenlayout** | Benutzerdefinierte Registerkarten und Widgets auf Datensatzseiten | [Layout](/l/de/developers/extend/apps/layout) |
|
||||
|
||||
## Sandboxing
|
||||
|
||||
* **Logic functions** run in isolated Node.js processes on the server. They only access data through the typed API client, scoped to the app's role permissions.
|
||||
* **Front components** run in Web Workers using Remote DOM — sandboxed from the main page but rendering native DOM elements (not iframes). They communicate with Twenty via a message-passing host API.
|
||||
* **Permissions** are enforced at the API level. The runtime token (`TWENTY_APP_ACCESS_TOKEN`) is derived from the role defined in `defineApplication()`.
|
||||
* **Logikfunktionen** laufen in isolierten Node.js-Prozessen auf dem Server. Sie greifen nur über den typisierten API-Client auf Daten zu, begrenzt durch die Rollenberechtigungen der App.
|
||||
* **Frontend-Komponenten** laufen in Web Workers mit Remote DOM — von der Hauptseite isoliert, rendern aber native DOM-Elemente (keine iframes). Sie kommunizieren über eine Message-Passing-Host-API mit Twenty.
|
||||
* **Berechtigungen** werden auf API-Ebene durchgesetzt. Das Laufzeit-Token (`TWENTY_APP_ACCESS_TOKEN`) wird aus der in `defineApplication()` definierten Rolle abgeleitet.
|
||||
|
||||
## App lifecycle
|
||||
## App-Lebenszyklus
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
@@ -73,32 +73,32 @@ your-app/
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
* **`yarn twenty dev`** — watches your source files and live-syncs changes to a connected Twenty server. The typed API client is regenerated automatically when the schema changes.
|
||||
* **`yarn twenty build`** — compiles TypeScript, bundles logic functions and front components with esbuild, and produces a manifest.
|
||||
* **Pre/post-install hooks** — optional logic functions that run during installation. See [Logic Functions](/l/de/developers/extend/apps/logic-functions) for details.
|
||||
* **`yarn twenty dev`** — überwacht Ihre Quelldateien und synchronisiert Änderungen in Echtzeit mit einem verbundenen Twenty-Server. Der typisierte API-Client wird automatisch neu erzeugt, wenn sich das Schema ändert.
|
||||
* **`yarn twenty build`** — kompiliert TypeScript, bündelt Logikfunktionen und Frontend-Komponenten mit esbuild und erzeugt ein Manifest.
|
||||
* **Pre/Post-Install-Hooks** — optionale Logikfunktionen, die während der Installation ausgeführt werden. Details finden Sie unter [Logikfunktionen](/l/de/developers/extend/apps/logic-functions).
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Datenmodell" icon="database" href="/l/de/developers/extend/apps/data-model">
|
||||
Define objects, fields, roles, and relations.
|
||||
Objekte, Felder, Rollen und Relationen definieren.
|
||||
</Card>
|
||||
<Card title="Logikfunktionen" icon="bolt" href="/l/de/developers/extend/apps/logic-functions">
|
||||
Server-side functions with HTTP, cron, and event triggers.
|
||||
Serverseitige Funktionen mit HTTP-, cron- und Ereignis-Triggern.
|
||||
</Card>
|
||||
<Card title="Frontend-Komponenten" icon="window-maximize" href="/l/de/developers/extend/apps/front-components">
|
||||
Sandboxed React components inside Twenty's UI.
|
||||
Sandboxed React-Komponenten innerhalb der UI von Twenty.
|
||||
</Card>
|
||||
<Card title="Layout" icon="table-columns" href="/l/de/developers/extend/apps/layout">
|
||||
Views, navigation items, and record page layouts.
|
||||
Ansichten, Navigationseinträge und Layouts von Datensatzseiten.
|
||||
</Card>
|
||||
<Card title="Fähigkeiten & Agenten" icon="robot" href="/l/de/developers/extend/apps/skills-and-agents">
|
||||
AI skills and agents with custom prompts.
|
||||
KI-Skills und Agenten mit benutzerdefinierten Prompts.
|
||||
</Card>
|
||||
<Card title="CLI & Testing" icon="terminal" href="/l/de/developers/extend/apps/cli-and-testing">
|
||||
CLI commands, testing, assets, remotes, and CI.
|
||||
<Card title="CLI & Tests" icon="terminal" href="/l/de/developers/extend/apps/cli-and-testing">
|
||||
CLI-Befehle, Tests, Assets, Remotes und CI.
|
||||
</Card>
|
||||
<Card title="Veröffentlichen" icon="rocket" href="/l/de/developers/extend/apps/publishing">
|
||||
Deploy to a server or publish to the marketplace.
|
||||
Auf einem Server bereitstellen oder auf dem Marktplatz veröffentlichen.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
---
|
||||
title: Layout
|
||||
description: Define views, navigation menu items, and page layouts to shape how your app appears in Twenty.
|
||||
description: Definieren Sie Ansichten, Navigationsmenüeinträge und Seitenlayouts, um das Erscheinungsbild Ihrer App in Twenty zu gestalten.
|
||||
icon: table-columns
|
||||
---
|
||||
|
||||
Layout entities control how your app surfaces inside Twenty's UI — what lives in the sidebar, which saved views ship with the app, and how a record detail page is arranged.
|
||||
Layout-Entitäten steuern, wie Ihre App innerhalb der Benutzeroberfläche von Twenty dargestellt wird — was in der Seitenleiste angezeigt wird, welche gespeicherten Ansichten mit der App ausgeliefert werden und wie eine Detailseite eines Datensatzes angeordnet ist.
|
||||
|
||||
## Layout concepts
|
||||
## Layout-Konzepte
|
||||
|
||||
| Concept | What it controls | Entität |
|
||||
| ------------------------ | --------------------------------------------------------------------------------- | -------------------------- |
|
||||
| **View** | A saved list configuration for an object — visible fields, order, filters, groups | `defineView` |
|
||||
| **Navigation Menu Item** | An entry in the left sidebar that links to a view or an external URL | `defineNavigationMenuItem` |
|
||||
| **Page Layout** | The tabs and widgets that make up a record's detail page | `definePageLayout` |
|
||||
| Konzept | Was es steuert | Entität |
|
||||
| -------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------- |
|
||||
| **Ansicht** | Eine gespeicherte Listen-Konfiguration für ein Objekt — sichtbare Felder, Reihenfolge, Filter, Gruppen | `defineView` |
|
||||
| **Navigationsmenüeintrag** | Ein Eintrag in der linken Seitenleiste, der auf eine Ansicht oder eine externe URL verweist | `defineNavigationMenuItem` |
|
||||
| **Seitenlayout** | Die Tabs und Widgets, aus denen die Detailseite eines Datensatzes besteht | `definePageLayout` |
|
||||
|
||||
Views, navigation items, and page layouts reference each other by `universalIdentifier`:
|
||||
Ansichten, Navigationsmenüeinträge und Seitenlayouts verweisen über `universalIdentifier` aufeinander:
|
||||
|
||||
* A **navigation menu item** of type `VIEW` points at a `defineView` identifier, so the sidebar link opens that saved view.
|
||||
* A **page layout** of type `RECORD_PAGE` targets an object and can embed [front components](/l/de/developers/extend/apps/front-components) inside its tabs as widgets.
|
||||
* Ein **Navigationsmenüeintrag** vom Typ `VIEW` verweist auf einen `defineView`-Bezeichner, sodass der Seitenleistenlink diese gespeicherte Ansicht öffnet.
|
||||
* Ein **Seitenlayout** vom Typ `RECORD_PAGE` zielt auf ein Objekt ab und kann [Frontkomponenten](/l/de/developers/extend/apps/front-components) innerhalb seiner Tabs als Widgets einbetten.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineView" description="Gespeicherte Views für Objekte definieren">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Fähigkeiten & Agenten
|
||||
description: Define AI skills and agents for your app.
|
||||
description: Definieren Sie KI-Skills und Agenten für Ihre App.
|
||||
icon: robot
|
||||
---
|
||||
|
||||
@@ -8,7 +8,7 @@ icon: robot
|
||||
Skills and agents are currently in alpha. Die Funktion ist funktionsfähig, entwickelt sich jedoch noch weiter.
|
||||
</Warning>
|
||||
|
||||
Apps can define AI capabilities that live inside the workspace — reusable skill instructions and agents with custom system prompts.
|
||||
Apps können KI-Funktionen definieren, die im Arbeitsbereich verfügbar sind — wiederverwendbare Skill-Anweisungen und Agenten mit benutzerdefinierten System-Prompts.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineSkill" description="Skills für KI-Agenten definieren">
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
---
|
||||
title: OAuth
|
||||
icon: schlüssel
|
||||
description: Authorization code flow with PKCE and client credentials for server-to-server access.
|
||||
description: Autorisierungscode-Flow mit PKCE und Client-Anmeldedaten für Server-zu-Server-Zugriff.
|
||||
---
|
||||
|
||||
Twenty implements OAuth 2.0 with authorization code + PKCE for user-facing apps and client credentials for server-to-server access. Clients are registered dynamically via [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) — no manual setup in a dashboard.
|
||||
Twenty implementiert OAuth 2.0 mit Autorisierungscode + PKCE für benutzerorientierte Apps und Client-Anmeldedaten für Server-zu-Server-Zugriff. Clients werden dynamisch über [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) registriert — keine manuelle Einrichtung in einem Dashboard.
|
||||
|
||||
## When to Use OAuth
|
||||
## Wann Sie OAuth verwenden sollten
|
||||
|
||||
| Szenario | Auth Method |
|
||||
| --------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| Internal scripts, automation | [API Key](/l/de/developers/extend/api#authentication) |
|
||||
| External app acting on behalf of a user | **OAuth — Authorization Code** |
|
||||
| Server-to-server, no user context | **OAuth — Client Credentials** |
|
||||
| Twenty App with UI extensions | [Apps](/l/de/developers/extend/apps/getting-started) (OAuth is handled automatically) |
|
||||
| Szenario | Authentifizierungsmethode |
|
||||
| ------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| Interne Skripte, Automatisierung | [API-Schlüssel](/l/de/developers/extend/api#authentication) |
|
||||
| Externe App, die im Namen eines Benutzers handelt | **OAuth — Autorisierungscode** |
|
||||
| Server-zu-Server, kein Benutzerkontext | **OAuth — Client-Anmeldedaten** |
|
||||
| Twenty-App mit UI-Erweiterungen | [Apps](/l/de/developers/extend/apps/getting-started) (OAuth wird automatisch gehandhabt) |
|
||||
|
||||
## Register a Client
|
||||
## Einen Client registrieren
|
||||
|
||||
Twenty supports **dynamic client registration** per [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). No manual setup needed — register programmatically:
|
||||
Twenty unterstützt die **dynamische Client-Registrierung** gemäß [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). Keine manuelle Einrichtung erforderlich — registrieren Sie den Client programmgesteuert:
|
||||
|
||||
```bash
|
||||
POST /oauth/register
|
||||
@@ -31,7 +31,7 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**Antwort:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -43,23 +43,23 @@ Content-Type: application/json
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Store the `client_secret` securely — it cannot be retrieved later.
|
||||
Speichern Sie das `client_secret` sicher — es kann später nicht mehr abgerufen werden.
|
||||
</Warning>
|
||||
|
||||
## Geltungsbereiche
|
||||
|
||||
| Scope | Zugriff |
|
||||
| -------- | ---------------------------------------------------- |
|
||||
| `api` | Full read/write access to the Core and Metadata APIs |
|
||||
| `profil` | Read the authenticated user's profile information |
|
||||
| Geltungsbereich | Zugriff |
|
||||
| --------------- | ------------------------------------------------------------ |
|
||||
| `api` | Voller Lese-/Schreibzugriff auf die Core- und Metadaten-APIs |
|
||||
| `profile` | Profilinformationen des authentifizierten Benutzers lesen |
|
||||
|
||||
Request scopes as a space-separated string: `scope=api profile`
|
||||
Fordern Sie Geltungsbereiche als durch Leerzeichen getrennte Zeichenfolge an: `scope=api profile`
|
||||
|
||||
## Authorization Code Flow
|
||||
## Autorisierungscode-Flow
|
||||
|
||||
Use this flow when your app acts on behalf of a Twenty user.
|
||||
Verwenden Sie diesen Flow, wenn Ihre App im Namen eines Twenty-Benutzers handelt.
|
||||
|
||||
### 1. Redirect the user to authorize
|
||||
### 1. Leiten Sie den Benutzer zur Autorisierung weiter
|
||||
|
||||
```
|
||||
GET /oauth/authorize?
|
||||
@@ -72,29 +72,29 @@ GET /oauth/authorize?
|
||||
code_challenge_method=S256
|
||||
```
|
||||
|
||||
| Parameter | Erforderlich | Beschreibung |
|
||||
| ----------------------- | ------------ | ------------------------------------------------------------ |
|
||||
| `client_id` | Ja | Your registered client ID |
|
||||
| `response_type` | Ja | Must be `code` |
|
||||
| `redirect_uri` | Ja | Must match a registered redirect URI |
|
||||
| `scope` | Nein | Space-separated scopes (defaults to `api`) |
|
||||
| `zustand` | Empfohlen | Random string to prevent CSRF attacks |
|
||||
| `code_challenge` | Empfohlen | PKCE challenge (SHA-256 hash of verifier, base64url-encoded) |
|
||||
| `code_challenge_method` | Empfohlen | Must be `S256` when using PKCE |
|
||||
| Parameter | Erforderlich | Beschreibung |
|
||||
| ----------------------- | ------------ | -------------------------------------------------------------- |
|
||||
| `client_id` | Ja | Ihre registrierte Client-ID |
|
||||
| `response_type` | Ja | Muss `code` sein |
|
||||
| `redirect_uri` | Ja | Muss einer registrierten Redirect-URI entsprechen |
|
||||
| `scope` | Nein | Durch Leerzeichen getrennte Geltungsbereiche (Standard: `api`) |
|
||||
| `state` | Empfohlen | Zufällige Zeichenfolge zur Verhinderung von CSRF-Angriffen |
|
||||
| `code_challenge` | Empfohlen | PKCE-Challenge (SHA-256-Hash des Verifiers, base64url-codiert) |
|
||||
| `code_challenge_method` | Empfohlen | Muss bei Verwendung von PKCE `S256` sein |
|
||||
|
||||
The user sees a consent screen and approves or denies access.
|
||||
Der Benutzer sieht einen Zustimmungsbildschirm und stimmt dem Zugriff zu oder lehnt ihn ab.
|
||||
|
||||
### 2. Handle the callback
|
||||
### 2. Den Callback verarbeiten
|
||||
|
||||
After authorization, Twenty redirects back to your `redirect_uri`:
|
||||
Nach der Autorisierung leitet Twenty zurück zu Ihrer `redirect_uri` weiter:
|
||||
|
||||
```
|
||||
https://myapp.com/callback?code=AUTH_CODE&state=random_state_value
|
||||
```
|
||||
|
||||
Verify that `state` matches what you sent.
|
||||
Überprüfen Sie, dass `state` mit dem übereinstimmt, was Sie gesendet haben.
|
||||
|
||||
### 3. Exchange the code for tokens
|
||||
### 3. Tauschen Sie den Code gegen Token aus
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -108,7 +108,7 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
code_verifier=YOUR_PKCE_VERIFIER
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**Antwort:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -119,14 +119,14 @@ code_verifier=YOUR_PKCE_VERIFIER
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Use the access token
|
||||
### 4. Verwenden Sie das Zugriffstoken
|
||||
|
||||
```bash
|
||||
GET /rest/companies
|
||||
Authorization: Bearer ACCESS_TOKEN
|
||||
```
|
||||
|
||||
### 5. Refresh when expired
|
||||
### 5. Aktualisieren, wenn abgelaufen
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -138,9 +138,9 @@ client_id=YOUR_CLIENT_ID&
|
||||
client_secret=YOUR_CLIENT_SECRET
|
||||
```
|
||||
|
||||
## Client Credentials Flow
|
||||
## Client-Anmeldedaten-Flow
|
||||
|
||||
For server-to-server integrations with no user interaction:
|
||||
Für Server-zu-Server-Integrationen ohne Benutzerinteraktion:
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -152,38 +152,38 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
scope=api
|
||||
```
|
||||
|
||||
The returned token has workspace-level access, not tied to any specific user.
|
||||
Das zurückgegebene Token hat Zugriff auf Arbeitsbereichsebene und ist an keinen bestimmten Benutzer gebunden.
|
||||
|
||||
## Server Discovery
|
||||
## Server-Ermittlung
|
||||
|
||||
Twenty publishes its OAuth configuration at a standard discovery endpoint:
|
||||
Twenty veröffentlicht seine OAuth-Konfiguration an einem standardisierten Discovery-Endpunkt:
|
||||
|
||||
```
|
||||
GET /.well-known/oauth-authorization-server
|
||||
```
|
||||
|
||||
This returns all endpoints, supported grant types, scopes, and capabilities — useful for building generic OAuth clients.
|
||||
Dies liefert alle Endpunkte, unterstützte Grant-Typen, Geltungsbereiche und Fähigkeiten — nützlich, um generische OAuth-Clients zu erstellen.
|
||||
|
||||
## API Endpoints Summary
|
||||
## Zusammenfassung der API-Endpunkte
|
||||
|
||||
| Endpunkt | Zweck |
|
||||
| ----------------------------------------- | --------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Server metadata discovery |
|
||||
| `/oauth/register` | Dynamic client registration |
|
||||
| `/oauth/authorize` | User authorization |
|
||||
| `/oauth/token` | Token exchange and refresh |
|
||||
| Endpunkt | Zweck |
|
||||
| ----------------------------------------- | ----------------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Ermittlung von Servermetadaten |
|
||||
| `/oauth/register` | Dynamische Client-Registrierung |
|
||||
| `/oauth/authorize` | Benutzerautorisierung |
|
||||
| `/oauth/token` | Token-Austausch und -Aktualisierung |
|
||||
|
||||
| Umgebung | Basis-URL |
|
||||
| ----------------- | ------------------------ |
|
||||
| **Cloud** | `https://api.twenty.com` |
|
||||
| **Selbsthosting** | `https://{your-domain}` |
|
||||
|
||||
## OAuth vs API Keys
|
||||
## OAuth vs. API-Schlüssel
|
||||
|
||||
| | API-Schlüssel | OAuth |
|
||||
| -------------------------- | ----------------------- | -------------------------------------- |
|
||||
| **Einrichtung** | Generate in Settings | Register a client, implement flow |
|
||||
| **User context** | None (workspace-level) | Specific user's permissions |
|
||||
| **Am besten geeignet für** | Scripts, internal tools | External apps, multi-user integrations |
|
||||
| **Token rotation** | Manuell | Automatic via refresh tokens |
|
||||
| **Scoped access** | Full API access | Granular via scopes |
|
||||
| | API-Schlüssel | OAuth |
|
||||
| ------------------------------------- | ------------------------------- | ----------------------------------------- |
|
||||
| **Einrichtung** | In den Einstellungen generieren | Client registrieren, Flow implementieren |
|
||||
| **Benutzerkontext** | Keiner (Arbeitsbereichsebene) | Berechtigungen eines bestimmten Benutzers |
|
||||
| **Am besten geeignet für** | Skripte, interne Tools | Externe Apps, Multi-User-Integrationen |
|
||||
| **Token-Rotation** | Manuell | Automatisch über Refresh-Tokens |
|
||||
| **Geltungsbereichsbasierter Zugriff** | Voller API-Zugriff | Granular über Geltungsbereiche |
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Webhooks
|
||||
icon: satellite-dish
|
||||
description: Get notified when records change — HTTP POST to your endpoint on every create, update, or delete.
|
||||
description: Lassen Sie sich benachrichtigen, wenn sich Datensätze ändern — HTTP POST an Ihren Endpunkt bei jeder Erstellung, Aktualisierung oder Löschung.
|
||||
---
|
||||
|
||||
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
|
||||
|
||||
Twenty sends an HTTP POST to your URL whenever a record is created, updated, or deleted. All object types are covered, including custom objects.
|
||||
Twenty sendet einen HTTP POST an Ihre URL, wenn ein Datensatz erstellt, aktualisiert oder gelöscht wird. Alle Objekttypen sind abgedeckt, einschließlich benutzerdefinierter Objekte.
|
||||
|
||||
## Webhook erstellen
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Fehlerbehebung
|
||||
icon: wrench
|
||||
icon: Schraubenschlüssel
|
||||
---
|
||||
|
||||
## Fehlerbehebung
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: App-Tooltip
|
||||
icon: nachricht
|
||||
icon: Nachricht
|
||||
---
|
||||
|
||||
<Frame>
|
||||
|
||||
@@ -38,15 +38,15 @@ export const MyComponent = () => {
|
||||
<Tab title=""Eigenschaften"">
|
||||
|
||||
|
||||
| "Eigenschaften" | Typ | Beschreibung |
|
||||
| --------------- | ------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| linkToEntity | Zeichenkette | Der Link zur Entität |
|
||||
| entityId | Zeichenkette | Der eindeutige Identifikator für die Entität |
|
||||
| name | string | Der Name der Entität |
|
||||
| pictureUrl | Zeichenkette | s Bild", |
|
||||
| avatarType | Avatar-Typ | Der Typ des Avatars, den Sie anzeigen möchten. Hat zwei Optionen: `abgerundet` und `quadratisch` |
|
||||
| Variante | `EntityChipVariante` enum | Variante des Entity-Chips, die Sie anzeigen möchten. Hat zwei Optionen: `regelmäßig` und `transparent` |
|
||||
| LeftIcon | Icon-Komponente | Eine React-Komponente, die ein Symbol darstellt. Wird auf der linken Seite des Chips angezeigt |
|
||||
| Props | Typ | Beschreibung |
|
||||
| ------------ | ------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| linkToEntity | Zeichenkette | Der Link zur Entität |
|
||||
| entityId | Zeichenkette | Der eindeutige Identifikator für die Entität |
|
||||
| name | string | Der Name der Entität |
|
||||
| pictureUrl | Zeichenkette | s Bild", |
|
||||
| avatarType | Avatar-Typ | Der Typ des Avatars, den Sie anzeigen möchten. Hat zwei Optionen: `abgerundet` und `quadratisch` |
|
||||
| Variante | `EntityChipVariante` enum | Variante des Entity-Chips, die Sie anzeigen möchten. Hat zwei Optionen: `regelmäßig` und `transparent` |
|
||||
| LeftIcon | Icon-Komponente | Eine React-Komponente, die ein Symbol darstellt. Wird auf der linken Seite des Chips angezeigt |
|
||||
|
||||
|
||||
|
||||
@@ -137,15 +137,15 @@ export const MyComponent = () => {
|
||||
<Tab title="Eigenschaften">
|
||||
|
||||
|
||||
| Eigenschaften | Typ | Beschreibung |
|
||||
| ------------- | ------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| linkToEntity | string | Der Link zur Entität |
|
||||
| entityId | string | Der eindeutige Identifikator für die Entität |
|
||||
| name | string | Der Name der Entität |
|
||||
| pictureUrl | Zeichenfolge | s Bild", |
|
||||
| avatarType | Avatar-Typ | Der Typ des Avatars, den Sie anzeigen möchten. Hat zwei Optionen: `abgerundet` und `quadratisch` |
|
||||
| Variante | `EntityChipVariante` enum | Variante des Entity-Chips, die Sie anzeigen möchten. Hat zwei Optionen: `regelmäßig` und `transparent` |
|
||||
| LeftIcon | Icon-Komponente | Eine React-Komponente, die ein Symbol darstellt. Wird auf der linken Seite des Chips angezeigt |
|
||||
| Props | Typ | Beschreibung |
|
||||
| ------------ | ------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| linkToEntity | string | Der Link zur Entität |
|
||||
| entityId | string | Der eindeutige Identifikator für die Entität |
|
||||
| name | string | Der Name der Entität |
|
||||
| pictureUrl | Zeichenfolge | s Bild", |
|
||||
| avatarType | Avatar-Typ | Der Typ des Avatars, den Sie anzeigen möchten. Hat zwei Optionen: `abgerundet` und `quadratisch` |
|
||||
| Variante | `EntityChipVariante` enum | Variante des Entity-Chips, die Sie anzeigen möchten. Hat zwei Optionen: `regelmäßig` und `transparent` |
|
||||
| LeftIcon | Icon-Komponente | Eine React-Komponente, die ein Symbol darstellt. Wird auf der linken Seite des Chips angezeigt |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: '"Tag"'
|
||||
icon: '"tag"'
|
||||
icon: tag
|
||||
---
|
||||
|
||||
Komponente zur visuellen Kategorisierung oder Kennzeichnung von Inhalten.
|
||||
|
||||
@@ -26,9 +26,9 @@ export const MyComponent = () => {
|
||||
<Tab title=""Eigenschaften"">
|
||||
|
||||
|
||||
| "Eigenschaften" | Typ | Beschreibung |
|
||||
| --------------- | ----------------- | ------------------------------------------- |
|
||||
| Editor | `BlockNoteEditor` | Instanz oder Konfiguration des Blockeditors |
|
||||
| Props | Typ | Beschreibung |
|
||||
| ------ | ----------------- | ------------------------------------------- |
|
||||
| Editor | `BlockNoteEditor` | Instanz oder Konfiguration des Blockeditors |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ export const MyComponent = () => {
|
||||
<Tab title=""Eigenschaften"">
|
||||
|
||||
|
||||
| "Eigenschaften" | Typ | Beschreibung |
|
||||
| Props | Typ | Beschreibung |
|
||||
| --------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| deaktiviert | boolesch | Deaktiviert die Symbolauswahl, wenn auf `true` gesetzt ist. |
|
||||
| beiÄnderung | function | Die Rückruffunktion wird ausgelöst, wenn der Benutzer ein Symbol auswählt. Es erhält ein Objekt mit `iconKey` und `Icon` Eigenschaften |
|
||||
|
||||
@@ -23,15 +23,15 @@ export const MyComponent = () => {
|
||||
<Tab title=""Eigenschaften"">
|
||||
|
||||
|
||||
| "Eigenschaften" | Typ | Beschreibung |
|
||||
| --------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
|
||||
| bild | Zeichenkette | Die Bildquellen-URL |
|
||||
| onUpload | Funktion | Die Funktion, die aufgerufen wird, wenn ein Benutzer ein neues Bild hochlädt. Es erhält das `Datei` Objekt als Parameter |
|
||||
| onRemove | Funktion | Die Funktion wird aufgerufen, wenn der Benutzer auf die Entfernen-Schaltfläche klickt. |
|
||||
| onAbort | Funktion | Die Funktion wird aufgerufen, wenn der Benutzer während des Bilduploads auf die Abbrechen-Schaltfläche klickt. |
|
||||
| isUploading | boolesch | Gibt an, ob ein Bild derzeit hochgeladen wird |
|
||||
| Fehlermeldung | Zeichenkette | Eine optionale Fehlermeldung, die unterhalb des Bildeingangs angezeigt wird. |
|
||||
| deaktiviert | boolesch | Wenn `true`, ist die gesamte Eingabe deaktiviert und die Schaltflächen sind nicht anklickbar |
|
||||
| Props | Typ | Beschreibung |
|
||||
| ------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
|
||||
| bild | Zeichenkette | Die Bildquellen-URL |
|
||||
| onUpload | Funktion | Die Funktion, die aufgerufen wird, wenn ein Benutzer ein neues Bild hochlädt. Es erhält das `Datei` Objekt als Parameter |
|
||||
| onRemove | Funktion | Die Funktion wird aufgerufen, wenn der Benutzer auf die Entfernen-Schaltfläche klickt. |
|
||||
| onAbort | Funktion | Die Funktion wird aufgerufen, wenn der Benutzer während des Bilduploads auf die Abbrechen-Schaltfläche klickt. |
|
||||
| isUploading | boolesch | Gibt an, ob ein Bild derzeit hochgeladen wird |
|
||||
| Fehlermeldung | Zeichenkette | Eine optionale Fehlermeldung, die unterhalb des Bildeingangs angezeigt wird. |
|
||||
| deaktiviert | boolesch | Wenn `true`, ist die gesamte Eingabe deaktiviert und die Schaltflächen sind nicht anklickbar |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -38,14 +38,14 @@ export const MyComponent = () => {
|
||||
<Tab title=""Eigenschaften"">
|
||||
|
||||
|
||||
| "Eigenschaften" | Typ | Beschreibung |
|
||||
| --------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Klassenname | Zeichenkette | Optionale CSS-Klasse für zusätzliche Stilgebung |
|
||||
| deaktiviert | boolesch | Wenn auf `true` gesetzt, wird die Benutzerinteraktion mit der Komponente deaktiviert |
|
||||
| Beschriftung | string | Die Beschriftung, um den Zweck der `Select`-Komponente zu beschreiben |
|
||||
| onChange | Funktion | Die Funktion, die aufgerufen wird, wenn sich die ausgewählten Werte ändern |
|
||||
| optionen | Array | Repräsentiert die verfügbaren Optionen für die `Select`-Komponente. Es ist ein Array von Objekten, bei dem jedes Objekt ein `value` (die eindeutige Kennung), `label` (die eindeutige Kennung) und ein optionales `Icon` hat |
|
||||
| wert | Zeichenkette | Repräsentiert den aktuell ausgewählten Wert. Es sollte mit einem der `value`-Eigenschaften im `options`-Array übereinstimmen |
|
||||
| Props | Typ | Beschreibung |
|
||||
| ------------ | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Klassenname | Zeichenkette | Optionale CSS-Klasse für zusätzliche Stilgebung |
|
||||
| deaktiviert | boolesch | Wenn auf `true` gesetzt, wird die Benutzerinteraktion mit der Komponente deaktiviert |
|
||||
| Beschriftung | string | Die Beschriftung, um den Zweck der `Select`-Komponente zu beschreiben |
|
||||
| onChange | Funktion | Die Funktion, die aufgerufen wird, wenn sich die ausgewählten Werte ändern |
|
||||
| optionen | Array | Repräsentiert die verfügbaren Optionen für die `Select`-Komponente. Es ist ein Array von Objekten, bei dem jedes Objekt ein `value` (die eindeutige Kennung), `label` (die eindeutige Kennung) und ein optionales `Icon` hat |
|
||||
| wert | Zeichenkette | Repräsentiert den aktuell ausgewählten Wert. Es sollte mit einem der `value`-Eigenschaften im `options`-Array übereinstimmen |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ export const MyComponent = () => {
|
||||
<Tab title="Eigenschaften">
|
||||
|
||||
|
||||
| Eigenschaften | Typ | Beschreibung |
|
||||
| Props | Typ | Beschreibung |
|
||||
| -------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| className | Zeichenkette | Optionaler Name für zusätzliche Stile |
|
||||
| Beschriftung | Zeichenkette | Stellt die Beschriftung für das Eingabefeld dar |
|
||||
@@ -100,15 +100,15 @@ export const MyComponent = () => {
|
||||
<Tab title="Eigenschaften">
|
||||
|
||||
|
||||
| Eigenschaften | Typ | Beschreibung |
|
||||
| ------------- | ------------ | ---------------------------------------------------------------------------------------- |
|
||||
| onValidate | Funktion | Die Callback-Funktion, die Sie auslösen möchten, wenn der Benutzer die Eingabe validiert |
|
||||
| minRows | nummer | Die minimale Anzahl von Zeilen für den Textbereich |
|
||||
| Platzhalter | Zeichenkette | Der Platzhaltertext, den Sie anzeigen möchten, wenn der Textbereich leer ist |
|
||||
| onFocus | Funktion | Die Callback-Funktion, die Sie auslösen möchten, wenn der Textbereich den Fokus erlangt |
|
||||
| Variante | Zeichenkette | Die Variante der Eingabe. Optionen umfassen: `Standard`, `Ikone` und `Schaltfläche` |
|
||||
| buttonTitle | Zeichenkette | Der Titel für die Schaltfläche (nur für die Schaltflächenvariante anwendbar) |
|
||||
| wert | Zeichenkette | Der Initialwert für den Textbereich |
|
||||
| Props | Typ | Beschreibung |
|
||||
| ----------- | ------------ | ---------------------------------------------------------------------------------------- |
|
||||
| onValidate | Funktion | Die Callback-Funktion, die Sie auslösen möchten, wenn der Benutzer die Eingabe validiert |
|
||||
| minRows | nummer | Die minimale Anzahl von Zeilen für den Textbereich |
|
||||
| Platzhalter | Zeichenkette | Der Platzhaltertext, den Sie anzeigen möchten, wenn der Textbereich leer ist |
|
||||
| onFocus | Funktion | Die Callback-Funktion, die Sie auslösen möchten, wenn der Textbereich den Fokus erlangt |
|
||||
| Variante | Zeichenkette | Die Variante der Eingabe. Optionen umfassen: `Standard`, `Ikone` und `Schaltfläche` |
|
||||
| buttonTitle | Zeichenkette | Der Titel für die Schaltfläche (nur für die Schaltflächenvariante anwendbar) |
|
||||
| wert | Zeichenkette | Der Initialwert für den Textbereich |
|
||||
|
||||
|
||||
|
||||
@@ -146,13 +146,13 @@ export const MyComponent = () => {
|
||||
<Tab title="Eigenschaften">
|
||||
|
||||
|
||||
| Eigenschaften | Typ | Beschreibung |
|
||||
| ------------- | ------------ | ---------------------------------------------------------------------------- |
|
||||
| deaktiviert | boolesch | Gibt an, ob der Textbereich deaktiviert ist |
|
||||
| minRows | nummer | Minimale Anzahl sichtbarer Zeilen für den Textbereich. |
|
||||
| onChange | Funktion | Rückruffunktion wird ausgelöst, wenn sich der Inhalt des Textbereichs ändert |
|
||||
| Platzhalter | Zeichenkette | Platzhaltertext, der angezeigt wird, wenn der Textbereich leer ist |
|
||||
| wert | Zeichenkette | Der aktuelle Wert des Textbereichs |
|
||||
| Props | Typ | Beschreibung |
|
||||
| ----------- | ------------ | ---------------------------------------------------------------------------- |
|
||||
| deaktiviert | boolesch | Gibt an, ob der Textbereich deaktiviert ist |
|
||||
| minRows | nummer | Minimale Anzahl sichtbarer Zeilen für den Textbereich. |
|
||||
| onChange | Funktion | Rückruffunktion wird ausgelöst, wenn sich der Inhalt des Textbereichs ändert |
|
||||
| Platzhalter | Zeichenkette | Platzhaltertext, der angezeigt wird, wenn der Textbereich leer ist |
|
||||
| wert | Zeichenkette | Der aktuelle Wert des Textbereichs |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -35,10 +35,10 @@ export const MyComponent = () => {
|
||||
<Tab title=""Eigenschaften"">
|
||||
|
||||
|
||||
| "Eigenschaften" | Typ | Beschreibung |
|
||||
| --------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Klassenname | Zeichenkette | Optionaler Klassenname für zusätzliche Stilierung |
|
||||
| Links | array | Ein Array von Objekten, die jeweils einen Breadcrumb-Link darstellen. Jedes Objekt hat eine `children`-Eigenschaft (den textlichen Inhalt des Links) und eine optionale `href`-Eigenschaft (die URL, zu der navigiert wird, wenn der Link angeklickt wird) |
|
||||
| Props | Typ | Beschreibung |
|
||||
| ----------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Klassenname | Zeichenkette | Optionaler Klassenname für zusätzliche Stilierung |
|
||||
| Links | array | Ein Array von Objekten, die jeweils einen Breadcrumb-Link darstellen. Jedes Objekt hat eine `children`-Eigenschaft (den textlichen Inhalt des Links) und eine optionale `href`-Eigenschaft (die URL, zu der navigiert wird, wenn der Link angeklickt wird) |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ export const MyComponent = () => {
|
||||
<Tab title=""Eigenschaften"">
|
||||
|
||||
|
||||
| "Eigenschaften" | Typ | Beschreibung |
|
||||
| --------------- | ------ | --------------------------------------------------------------------------------------------------------- |
|
||||
| aktiverSchritt | nummer | Der Index des derzeit aktiven Schritts. Dies bestimmt, welcher Schritt visuell hervorgehoben werden soll. |
|
||||
| Props | Typ | Beschreibung |
|
||||
| -------------- | ------ | --------------------------------------------------------------------------------------------------------- |
|
||||
| aktiverSchritt | nummer | Der Index des derzeit aktiven Schritts. Dies bestimmt, welcher Schritt visuell hervorgehoben werden soll. |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Navigation
|
||||
description: Passen Sie die linke Seitenleiste an die Arbeitsweise Ihres Teams an.
|
||||
---
|
||||
|
||||
Die linke Seitenleiste ist Ihre wichtigste Möglichkeit, sich in Twenty zu bewegen. Sie ist vollständig anpassbar — Sie können sie neu organisieren, damit sie zu Ihrem Workflow passt, ohne eine Einstellungsseite zu öffnen.
|
||||
Die linke Seitenleiste ist Ihre wichtigste Möglichkeit, in Twenty zu navigieren. Sie ist vollständig anpassbar — Sie können sie neu organisieren, damit sie zu Ihrem Workflow passt, ohne eine Einstellungsseite zu öffnen.
|
||||
|
||||
## Einträge neu anordnen
|
||||
|
||||
@@ -21,7 +21,7 @@ Objekte, die Sie nicht verwenden, können aus der Seitenleiste ausgeblendet werd
|
||||
|
||||
## Favoriten
|
||||
|
||||
Heften Sie Ansichten, Datensätze oder Suchvorgänge im Bereich Favoriten oben in der Seitenleiste an, um mit einem Klick darauf zuzugreifen. Favoriten sind persönlich — jeder Nutzer verwaltet seine eigenen.
|
||||
Heften Sie Ansichten, Datensätze oder Suchvorgänge im Bereich Favoriten oben in der Seitenleiste an, um mit einem Klick darauf zuzugreifen. Favoriten sind persönlich — jeder Benutzer verwaltet seine eigenen.
|
||||
|
||||
## Benutzerdefinierte Links
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Comandi Backend
|
||||
icon: terminal
|
||||
icon: terminale
|
||||
---
|
||||
|
||||
## Comandi utili
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Commands
|
||||
icon: terminal
|
||||
description: Useful commands for developing Twenty.
|
||||
title: Comandi
|
||||
icon: terminale
|
||||
description: Comandi utili per sviluppare Twenty.
|
||||
---
|
||||
|
||||
Commands can be run from the repository root using `npx nx`. Use `npx nx run {project}:{command}` for explicit targeting.
|
||||
I comandi possono essere eseguiti dalla radice del repository usando `npx nx`. Usa `npx nx run {project}:{command}` per specificare esplicitamente il target.
|
||||
|
||||
## Starting the App
|
||||
## Avviare l'app
|
||||
|
||||
```bash
|
||||
npx nx start twenty-front # Frontend dev server (http://localhost:3001)
|
||||
@@ -30,7 +30,7 @@ npx nx lint:diff-with-main twenty-server
|
||||
npx nx lint twenty-front --configuration=fix # Auto-fix
|
||||
```
|
||||
|
||||
## Type Checking
|
||||
## Controllo dei tipi
|
||||
|
||||
```bash
|
||||
npx nx typecheck twenty-front
|
||||
@@ -68,7 +68,7 @@ npx nx run twenty-front:lingui:extract # Extract strings
|
||||
npx nx run twenty-front:lingui:compile # Compile translations
|
||||
```
|
||||
|
||||
## Build
|
||||
## Compilazione
|
||||
|
||||
```bash
|
||||
npx nx build twenty-shared # Must be built first
|
||||
|
||||
@@ -140,7 +140,7 @@ const StyledButton = styled.button`
|
||||
`;
|
||||
```
|
||||
|
||||
## Importa
|
||||
## Importazioni
|
||||
|
||||
Use aliases instead of relative paths:
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
title: Architettura
|
||||
description: How Twenty apps work — sandboxing, lifecycle, and the building blocks.
|
||||
description: Come funzionano le app di Twenty — sandboxing, ciclo di vita e componenti di base.
|
||||
icon: sitemap
|
||||
---
|
||||
|
||||
Twenty apps are TypeScript packages that extend your workspace with custom objects, logic, UI components, and AI capabilities. They run on the Twenty platform with full sandboxing and permission controls.
|
||||
Le app di Twenty sono pacchetti TypeScript che estendono il tuo spazio di lavoro con oggetti personalizzati, logica, componenti dell'interfaccia utente (UI) e funzionalità di IA. Vengono eseguite sulla piattaforma Twenty con sandboxing completo e controlli delle autorizzazioni.
|
||||
|
||||
## How apps work
|
||||
## Come funzionano le app
|
||||
|
||||
An app is a collection of **entities** declared using `defineEntity()` functions from the `twenty-sdk` package. The SDK detects these declarations via AST analysis at build time and produces a **manifest** — a complete description of what your app adds to a workspace.
|
||||
Un'app è una raccolta di **entità** dichiarate utilizzando le funzioni `defineEntity()` del pacchetto `twenty-sdk`. L'SDK rileva queste dichiarazioni tramite analisi dell'AST in fase di build e produce un **manifest** — una descrizione completa di ciò che la tua app aggiunge a uno spazio di lavoro.
|
||||
|
||||
```
|
||||
your-app/
|
||||
@@ -29,32 +29,32 @@ your-app/
|
||||
```
|
||||
|
||||
<Note>
|
||||
**File organization is up to you.** Entity detection is AST-based — the SDK finds `export default defineEntity(...)` calls regardless of where the file lives. The folder structure above is a convention, not a requirement.
|
||||
**L'organizzazione dei file dipende da te.** Il rilevamento delle entità è basato sull'AST — l'SDK trova le chiamate a `export default defineEntity(...)` indipendentemente da dove si trova il file. La struttura delle cartelle sopra è una convenzione, non un requisito.
|
||||
</Note>
|
||||
|
||||
## Entity types
|
||||
## Tipi di entità
|
||||
|
||||
| Entità | Scopo | Documentazione |
|
||||
| ------------------------ | ----------------------------------------- | ------------------------------------------------------------ |
|
||||
| **Application** | App identity, permissions, variables | [Data Model](/l/it/developers/extend/apps/data-model) |
|
||||
| **Role** | Permission sets for objects and fields | [Data Model](/l/it/developers/extend/apps/data-model) |
|
||||
| **Oggetto** | Custom data tables with fields | [Data Model](/l/it/developers/extend/apps/data-model) |
|
||||
| **Campo** | Extend existing objects, define relations | [Data Model](/l/it/developers/extend/apps/data-model) |
|
||||
| **Logic Function** | Server-side TypeScript with triggers | [Funzioni logiche](/l/it/developers/extend/apps/logic-functions) |
|
||||
| **Front Component** | Sandboxed React UI in Twenty's page | [Front Components](/l/it/developers/extend/apps/front-components) |
|
||||
| **Skill** | Reusable AI agent instructions | [Skills & Agents](/l/it/developers/extend/apps/skills-and-agents) |
|
||||
| **Agent** | AI assistants with custom prompts | [Skills & Agents](/l/it/developers/extend/apps/skills-and-agents) |
|
||||
| **View** | Pre-configured record list views | [Layout](/l/it/developers/extend/apps/layout) |
|
||||
| **Navigation Menu Item** | Custom sidebar entries | [Layout](/l/it/developers/extend/apps/layout) |
|
||||
| **Page Layout** | Custom record page tabs and widgets | [Layout](/l/it/developers/extend/apps/layout) |
|
||||
| Entità | Scopo | Documentazione |
|
||||
| -------------------------------- | ------------------------------------------------------ | ---------------------------------------------------------------- |
|
||||
| **Applicazione** | Identità dell'app, autorizzazioni, variabili | [Modello dati](/l/it/developers/extend/apps/data-model) |
|
||||
| **Ruolo** | Set di autorizzazioni per oggetti e campi | [Modello dati](/l/it/developers/extend/apps/data-model) |
|
||||
| **Oggetto** | Tabelle di dati personalizzate con campi | [Modello dati](/l/it/developers/extend/apps/data-model) |
|
||||
| **Campo** | Estendi gli oggetti esistenti, definisci le relazioni | [Modello dati](/l/it/developers/extend/apps/data-model) |
|
||||
| **Funzione logica** | TypeScript lato server con trigger | [Funzioni logiche](/l/it/developers/extend/apps/logic-functions) |
|
||||
| **Componente front-end** | UI React in sandbox nella pagina di Twenty | [Componenti front-end](/l/it/developers/extend/apps/front-components) |
|
||||
| **Abilità** | Istruzioni riutilizzabili per agenti IA | [Abilità e agenti](/l/it/developers/extend/apps/skills-and-agents) |
|
||||
| **Agente** | Assistenti IA con prompt personalizzati | [Abilità e agenti](/l/it/developers/extend/apps/skills-and-agents) |
|
||||
| **Vista** | Viste di elenco dei record preconfigurate | [Layout](/l/it/developers/extend/apps/layout) |
|
||||
| **Voce del menu di navigazione** | Voci della barra laterale personalizzate | [Layout](/l/it/developers/extend/apps/layout) |
|
||||
| **Layout di pagina** | Schede e widget personalizzati nelle pagine dei record | [Layout](/l/it/developers/extend/apps/layout) |
|
||||
|
||||
## Sandboxing
|
||||
|
||||
* **Logic functions** run in isolated Node.js processes on the server. They only access data through the typed API client, scoped to the app's role permissions.
|
||||
* **Front components** run in Web Workers using Remote DOM — sandboxed from the main page but rendering native DOM elements (not iframes). They communicate with Twenty via a message-passing host API.
|
||||
* **Permissions** are enforced at the API level. The runtime token (`TWENTY_APP_ACCESS_TOKEN`) is derived from the role defined in `defineApplication()`.
|
||||
* **Le funzioni logiche** vengono eseguite in processi Node.js isolati sul server. Accedono ai dati solo tramite il client API tipizzato, con ambito limitato alle autorizzazioni del ruolo dell'app.
|
||||
* **I componenti front-end** vengono eseguiti in Web Workers utilizzando il Remote DOM — isolati dalla pagina principale ma renderizzando elementi DOM nativi (non iframe). Comunicano con Twenty tramite un'API host basata sul passaggio di messaggi.
|
||||
* **Le autorizzazioni** vengono applicate a livello di API. Il token di runtime (`TWENTY_APP_ACCESS_TOKEN`) è derivato dal ruolo definito in `defineApplication()`.
|
||||
|
||||
## App lifecycle
|
||||
## Ciclo di vita dell'app
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
@@ -73,32 +73,32 @@ your-app/
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
* **`yarn twenty dev`** — watches your source files and live-syncs changes to a connected Twenty server. The typed API client is regenerated automatically when the schema changes.
|
||||
* **`yarn twenty build`** — compiles TypeScript, bundles logic functions and front components with esbuild, and produces a manifest.
|
||||
* **Pre/post-install hooks** — optional logic functions that run during installation. See [Logic Functions](/l/it/developers/extend/apps/logic-functions) for details.
|
||||
* **`yarn twenty dev`** — monitora i file sorgente e sincronizza in tempo reale le modifiche su un server Twenty connesso. Il client API tipizzato viene rigenerato automaticamente quando lo schema cambia.
|
||||
* **`yarn twenty build`** — compila TypeScript, crea i bundle delle funzioni logiche e dei componenti front-end con esbuild e produce un manifest.
|
||||
* **Hook di pre/post-installazione** — funzioni logiche opzionali che vengono eseguite durante l'installazione. Consulta [Funzioni logiche](/l/it/developers/extend/apps/logic-functions) per i dettagli.
|
||||
|
||||
## Prossimi passaggi
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Modello dati" icon="database" href="/l/it/developers/extend/apps/data-model">
|
||||
Define objects, fields, roles, and relations.
|
||||
Definisci oggetti, campi, ruoli e relazioni.
|
||||
</Card>
|
||||
<Card title="Funzioni logiche" icon="bolt" href="/l/it/developers/extend/apps/logic-functions">
|
||||
Server-side functions with HTTP, cron, and event triggers.
|
||||
Funzioni lato server con trigger HTTP, cron ed eventi.
|
||||
</Card>
|
||||
<Card title="Componenti front-end" icon="window-maximize" href="/l/it/developers/extend/apps/front-components">
|
||||
Sandboxed React components inside Twenty's UI.
|
||||
Componenti React in sandbox nell'UI di Twenty.
|
||||
</Card>
|
||||
<Card title="Disposizione" icon="table-columns" href="/l/it/developers/extend/apps/layout">
|
||||
Views, navigation items, and record page layouts.
|
||||
Viste, voci di navigazione e layout delle pagine dei record.
|
||||
</Card>
|
||||
<Card title="Skill e agenti" icon="robot" href="/l/it/developers/extend/apps/skills-and-agents">
|
||||
AI skills and agents with custom prompts.
|
||||
Abilità e agenti IA con prompt personalizzati.
|
||||
</Card>
|
||||
<Card title="CLI & Testing" icon="terminal" href="/l/it/developers/extend/apps/cli-and-testing">
|
||||
CLI commands, testing, assets, remotes, and CI.
|
||||
<Card title="CLI e test" icon="terminal" href="/l/it/developers/extend/apps/cli-and-testing">
|
||||
Comandi CLI, test, asset, remoti e CI.
|
||||
</Card>
|
||||
<Card title="Pubblicazione" icon="rocket" href="/l/it/developers/extend/apps/publishing">
|
||||
Deploy to a server or publish to the marketplace.
|
||||
Distribuisci su un server o pubblica sul marketplace.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Disposizione
|
||||
title: Layout
|
||||
description: Define views, navigation menu items, and page layouts to shape how your app appears in Twenty.
|
||||
icon: table-columns
|
||||
---
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Skill e agenti
|
||||
description: Define AI skills and agents for your app.
|
||||
description: Definisci skill e agenti di IA per la tua app.
|
||||
icon: robot
|
||||
---
|
||||
|
||||
@@ -8,7 +8,7 @@ icon: robot
|
||||
Skills and agents are currently in alpha. La funzionalità funziona ma è ancora in evoluzione.
|
||||
</Warning>
|
||||
|
||||
Apps can define AI capabilities that live inside the workspace — reusable skill instructions and agents with custom system prompts.
|
||||
Le app possono definire capacità di IA che risiedono all'interno dello spazio di lavoro — istruzioni di skill riutilizzabili e agenti con prompt di sistema personalizzati.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineSkill" description="Definisci le skill degli agenti IA">
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
---
|
||||
title: OAuth
|
||||
icon: chiave
|
||||
description: Authorization code flow with PKCE and client credentials for server-to-server access.
|
||||
description: Flusso del codice di autorizzazione con PKCE e credenziali client per l'accesso da server a server.
|
||||
---
|
||||
|
||||
Twenty implements OAuth 2.0 with authorization code + PKCE for user-facing apps and client credentials for server-to-server access. Clients are registered dynamically via [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) — no manual setup in a dashboard.
|
||||
Twenty implementa OAuth 2.0 con codice di autorizzazione + PKCE per le app rivolte agli utenti e credenziali client per l'accesso da server a server. I client vengono registrati dinamicamente tramite [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) — nessuna configurazione manuale in una dashboard.
|
||||
|
||||
## When to Use OAuth
|
||||
## Quando utilizzare OAuth
|
||||
|
||||
| Scenario | Auth Method |
|
||||
| --------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| Internal scripts, automation | [API Key](/l/it/developers/extend/api#authentication) |
|
||||
| External app acting on behalf of a user | **OAuth — Authorization Code** |
|
||||
| Server-to-server, no user context | **OAuth — Client Credentials** |
|
||||
| Twenty App with UI extensions | [Apps](/l/it/developers/extend/apps/getting-started) (OAuth is handled automatically) |
|
||||
| Scenario | Metodo di autenticazione |
|
||||
| ------------------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| Script interni, automazioni | [Chiave API](/l/it/developers/extend/api#authentication) |
|
||||
| App esterna che agisce per conto di un utente | **OAuth — Codice di autorizzazione** |
|
||||
| Da server a server, nessun contesto utente | **OAuth — Credenziali client** |
|
||||
| App Twenty con estensioni dell'interfaccia utente | [App](/l/it/developers/extend/apps/getting-started) (OAuth è gestito automaticamente) |
|
||||
|
||||
## Register a Client
|
||||
## Registrare un client
|
||||
|
||||
Twenty supports **dynamic client registration** per [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). No manual setup needed — register programmatically:
|
||||
Twenty supporta la **registrazione dinamica dei client** secondo [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). Non è necessaria alcuna configurazione manuale — registra a livello di codice:
|
||||
|
||||
```bash
|
||||
POST /oauth/register
|
||||
@@ -31,7 +31,7 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**Risposta:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -43,23 +43,23 @@ Content-Type: application/json
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Store the `client_secret` securely — it cannot be retrieved later.
|
||||
Conserva `client_secret` in modo sicuro — non potrà essere recuperato in seguito.
|
||||
</Warning>
|
||||
|
||||
## Ambiti
|
||||
|
||||
| Scope | Accesso |
|
||||
| --------- | ---------------------------------------------------- |
|
||||
| `api` | Full read/write access to the Core and Metadata APIs |
|
||||
| `profilo` | Read the authenticated user's profile information |
|
||||
| Ambito | Accesso |
|
||||
| --------- | -------------------------------------------------------------- |
|
||||
| `api` | Accesso completo in lettura/scrittura alle API Core e Metadata |
|
||||
| `profilo` | Legge le informazioni del profilo dell'utente autenticato |
|
||||
|
||||
Request scopes as a space-separated string: `scope=api profile`
|
||||
Richiedi gli ambiti come stringa separata da spazi: `scope=api profile`
|
||||
|
||||
## Authorization Code Flow
|
||||
## Flusso con codice di autorizzazione
|
||||
|
||||
Use this flow when your app acts on behalf of a Twenty user.
|
||||
Usa questo flusso quando la tua app agisce per conto di un utente Twenty.
|
||||
|
||||
### 1. Redirect the user to authorize
|
||||
### 1. Reindirizza l'utente per autorizzare
|
||||
|
||||
```
|
||||
GET /oauth/authorize?
|
||||
@@ -72,29 +72,29 @@ GET /oauth/authorize?
|
||||
code_challenge_method=S256
|
||||
```
|
||||
|
||||
| Parametro | Obbligatorio | Descrizione |
|
||||
| ----------------------- | ------------ | ------------------------------------------------------------ |
|
||||
| `client_id` | Sì | Your registered client ID |
|
||||
| `response_type` | Sì | Must be `code` |
|
||||
| `redirect_uri` | Sì | Must match a registered redirect URI |
|
||||
| `scope` | No | Space-separated scopes (defaults to `api`) |
|
||||
| `stato` | Consigliato | Random string to prevent CSRF attacks |
|
||||
| `code_challenge` | Consigliato | PKCE challenge (SHA-256 hash of verifier, base64url-encoded) |
|
||||
| `code_challenge_method` | Consigliato | Must be `S256` when using PKCE |
|
||||
| Parametro | Obbligatorio | Descrizione |
|
||||
| ----------------------- | ------------ | ------------------------------------------------------------------- |
|
||||
| `client_id` | Sì | ID client registrato |
|
||||
| `response_type` | Sì | Deve essere `code` |
|
||||
| `redirect_uri` | Sì | Deve corrispondere a un URI di reindirizzamento registrato |
|
||||
| `scope` | No | Ambiti separati da spazi (predefinito `api`) |
|
||||
| `stato` | Consigliato | Stringa casuale per prevenire attacchi CSRF |
|
||||
| `code_challenge` | Consigliato | Challenge PKCE (hash SHA-256 del verifier, codificato in base64url) |
|
||||
| `code_challenge_method` | Consigliato | Deve essere `S256` quando si usa PKCE |
|
||||
|
||||
The user sees a consent screen and approves or denies access.
|
||||
L'utente vede una schermata di consenso e approva o nega l'accesso.
|
||||
|
||||
### 2. Handle the callback
|
||||
### 2. Gestisci la callback
|
||||
|
||||
After authorization, Twenty redirects back to your `redirect_uri`:
|
||||
Dopo l'autorizzazione, Twenty reindirizza al tuo `redirect_uri`:
|
||||
|
||||
```
|
||||
https://myapp.com/callback?code=AUTH_CODE&state=random_state_value
|
||||
```
|
||||
|
||||
Verify that `state` matches what you sent.
|
||||
Verifica che `state` corrisponda a quanto inviato.
|
||||
|
||||
### 3. Exchange the code for tokens
|
||||
### 3. Scambia il codice con i token
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -108,7 +108,7 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
code_verifier=YOUR_PKCE_VERIFIER
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**Risposta:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -119,14 +119,14 @@ code_verifier=YOUR_PKCE_VERIFIER
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Use the access token
|
||||
### 4. Usa il token di accesso
|
||||
|
||||
```bash
|
||||
GET /rest/companies
|
||||
Authorization: Bearer ACCESS_TOKEN
|
||||
```
|
||||
|
||||
### 5. Refresh when expired
|
||||
### 5. Aggiorna alla scadenza
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -138,9 +138,9 @@ client_id=YOUR_CLIENT_ID&
|
||||
client_secret=YOUR_CLIENT_SECRET
|
||||
```
|
||||
|
||||
## Client Credentials Flow
|
||||
## Flusso delle credenziali del client
|
||||
|
||||
For server-to-server integrations with no user interaction:
|
||||
Per integrazioni da server a server senza interazione dell'utente:
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -152,38 +152,38 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
scope=api
|
||||
```
|
||||
|
||||
The returned token has workspace-level access, not tied to any specific user.
|
||||
Il token restituito ha accesso a livello di spazio di lavoro, non legato a un utente specifico.
|
||||
|
||||
## Server Discovery
|
||||
## Scoperta del server
|
||||
|
||||
Twenty publishes its OAuth configuration at a standard discovery endpoint:
|
||||
Twenty pubblica la propria configurazione OAuth in un endpoint di discovery standard:
|
||||
|
||||
```
|
||||
GET /.well-known/oauth-authorization-server
|
||||
```
|
||||
|
||||
This returns all endpoints, supported grant types, scopes, and capabilities — useful for building generic OAuth clients.
|
||||
Questo restituisce tutti gli endpoint, i tipi di grant supportati, gli ambiti e le funzionalità — utile per creare client OAuth generici.
|
||||
|
||||
## API Endpoints Summary
|
||||
## Riepilogo degli endpoint API
|
||||
|
||||
| Endpoint | Scopo |
|
||||
| ----------------------------------------- | --------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Server metadata discovery |
|
||||
| `/oauth/register` | Dynamic client registration |
|
||||
| `/oauth/authorize` | User authorization |
|
||||
| `/oauth/token` | Token exchange and refresh |
|
||||
| Endpoint | Scopo |
|
||||
| ----------------------------------------- | -------------------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Individuazione dei metadati del server |
|
||||
| `/oauth/register` | Registrazione dinamica dei client |
|
||||
| `/oauth/authorize` | Autorizzazione utente |
|
||||
| `/oauth/token` | Scambio e aggiornamento dei token |
|
||||
|
||||
| Ambiente | URL di base |
|
||||
| ----------------- | ------------------------ |
|
||||
| **Cloud** | `https://api.twenty.com` |
|
||||
| **Auto-ospitato** | `https://{your-domain}` |
|
||||
|
||||
## OAuth vs API Keys
|
||||
## OAuth vs Chiavi API
|
||||
|
||||
| | API Keys | OAuth |
|
||||
| ------------------ | ----------------------- | -------------------------------------- |
|
||||
| **Impostazione** | Generate in Settings | Register a client, implement flow |
|
||||
| **User context** | None (workspace-level) | Specific user's permissions |
|
||||
| **Ideale per** | Scripts, internal tools | External apps, multi-user integrations |
|
||||
| **Token rotation** | Manuale | Automatic via refresh tokens |
|
||||
| **Scoped access** | Full API access | Granular via scopes |
|
||||
| | API Keys | OAuth |
|
||||
| ----------------------- | --------------------------------------- | ---------------------------------------- |
|
||||
| **Impostazione** | Genera nelle Impostazioni | Registra un client, implementa il flusso |
|
||||
| **Contesto utente** | Nessuno (a livello di spazio di lavoro) | Autorizzazioni dell'utente specifico |
|
||||
| **Ideale per** | Script, strumenti interni | App esterne, integrazioni multiutente |
|
||||
| **Rotazione dei token** | Manuale | Automatica tramite token di refresh |
|
||||
| **Accesso con ambiti** | Accesso completo alle API | Granulare tramite ambiti |
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Webhooks
|
||||
icon: satellite-dish
|
||||
description: Get notified when records change — HTTP POST to your endpoint on every create, update, or delete.
|
||||
description: Ricevi una notifica quando i record cambiano — HTTP POST al tuo endpoint a ogni creazione, aggiornamento o eliminazione.
|
||||
---
|
||||
|
||||
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
|
||||
|
||||
Twenty sends an HTTP POST to your URL whenever a record is created, updated, or deleted. All object types are covered, including custom objects.
|
||||
Twenty invia un HTTP POST al tuo URL ogni volta che un record viene creato, aggiornato o eliminato. Tutti i tipi di oggetto sono supportati, inclusi gli oggetti personalizzati.
|
||||
|
||||
## Crea un Webhook
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ export const MyComponent = () => {
|
||||
<Tab title="Props">
|
||||
|
||||
|
||||
| Props | Tipo | Descrizione |
|
||||
| ------ | ----------------- | ---------------------------------------------------- |
|
||||
| editor | `BlockNoteEditor` | L'istanza o la configurazione dell'editor di blocchi |
|
||||
| Proprietà | Tipo | Descrizione |
|
||||
| --------- | ----------------- | ---------------------------------------------------- |
|
||||
| editor | `BlockNoteEditor` | L'istanza o la configurazione dell'editor di blocchi |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ export const MyComponent = () => {
|
||||
<Tab title="Props">
|
||||
|
||||
|
||||
| Props | Tipo | Descrizione |
|
||||
| Proprietà | Tipo | Descrizione |
|
||||
| ---------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------- |
|
||||
| disabilitato | booleano | Disabilita il selettore di icone se impostato su `true` |
|
||||
| onChange | funzione | La funzione di callback attivata quando l'utente seleziona un'icona. Riceve un oggetto con le proprietà `iconKey` e `Icon` |
|
||||
|
||||
@@ -48,7 +48,7 @@ export const MyComponent = () => {
|
||||
<Tab title="Proprietà">
|
||||
|
||||
|
||||
| Proprietà | Tipo | Descrizione |
|
||||
| Props | Tipo | Descrizione |
|
||||
| -------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| nomeClasse | stringa | Nome opzionale per lo stile aggiuntivo |
|
||||
| etichetta | stringa | Rappresenta l'etichetta per l'input |
|
||||
@@ -100,7 +100,7 @@ export const MyComponent = () => {
|
||||
<Tab title="Proprietà">
|
||||
|
||||
|
||||
| Proprietà | Tipo | Descrizione |
|
||||
| Props | Tipo | Descrizione |
|
||||
| -------------- | -------- | ------------------------------------------------------------------------------------- |
|
||||
| suValida | funzione | La funzione di callback che si vuole attivare quando l'utente valida l'input |
|
||||
| righeMinime | numero | Il numero minimo di righe per l'area di testo |
|
||||
@@ -146,7 +146,7 @@ export const MyComponent = () => {
|
||||
<Tab title="Proprietà">
|
||||
|
||||
|
||||
| Proprietà | Tipo | Descrizione |
|
||||
| Props | Tipo | Descrizione |
|
||||
| ------------- | -------- | --------------------------------------------------------------------------- |
|
||||
| disabilitato | booleano | Indica se l'area di testo è disabilitata |
|
||||
| righeMinime | numero | Numero minimo di righe visibili per l'area di testo. |
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Commands
|
||||
title: Comandos
|
||||
icon: terminal
|
||||
description: Useful commands for developing Twenty.
|
||||
description: Comandos úteis para desenvolver o Twenty.
|
||||
---
|
||||
|
||||
Commands can be run from the repository root using `npx nx`. Use `npx nx run {project}:{command}` for explicit targeting.
|
||||
Os comandos podem ser executados a partir da raiz do repositório usando `npx nx`. Use `npx nx run {project}:{command}` para direcionar explicitamente.
|
||||
|
||||
## Starting the App
|
||||
## Iniciando o aplicativo
|
||||
|
||||
```bash
|
||||
npx nx start twenty-front # Frontend dev server (http://localhost:3001)
|
||||
@@ -14,7 +14,7 @@ npx nx start twenty-server # Backend server (http://localhost:3000)
|
||||
npx nx run twenty-server:worker # Background worker
|
||||
```
|
||||
|
||||
## Database
|
||||
## Banco de Dados
|
||||
|
||||
```bash
|
||||
npx nx database:reset twenty-server # Reset and seed database
|
||||
@@ -30,7 +30,7 @@ npx nx lint:diff-with-main twenty-server
|
||||
npx nx lint twenty-front --configuration=fix # Auto-fix
|
||||
```
|
||||
|
||||
## Type Checking
|
||||
## Verificação de tipos
|
||||
|
||||
```bash
|
||||
npx nx typecheck twenty-front
|
||||
@@ -68,7 +68,7 @@ npx nx run twenty-front:lingui:extract # Extract strings
|
||||
npx nx run twenty-front:lingui:compile # Compile translations
|
||||
```
|
||||
|
||||
## Build
|
||||
## Compilação
|
||||
|
||||
```bash
|
||||
npx nx build twenty-shared # Must be built first
|
||||
|
||||
@@ -110,7 +110,7 @@ const value = process.env.MY_VALUE ?? 'default';
|
||||
onClick?.();
|
||||
```
|
||||
|
||||
## Nomeação
|
||||
## Nomenclatura
|
||||
|
||||
* **Variables**: camelCase, descriptive (`email` not `value`, `fieldMetadata` not `fm`)
|
||||
* **Constants**: SCREAMING_SNAKE_CASE
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
title: Arquitetura
|
||||
description: How Twenty apps work — sandboxing, lifecycle, and the building blocks.
|
||||
description: Como as aplicações Twenty funcionam — sandboxing, ciclo de vida e os blocos de construção.
|
||||
icon: sitemap
|
||||
---
|
||||
|
||||
Twenty apps are TypeScript packages that extend your workspace with custom objects, logic, UI components, and AI capabilities. They run on the Twenty platform with full sandboxing and permission controls.
|
||||
As aplicações Twenty são pacotes TypeScript que estendem seu espaço de trabalho com objetos personalizados, lógica, componentes de UI e recursos de IA. Elas são executadas na plataforma Twenty com sandboxing completo e controles de permissão.
|
||||
|
||||
## How apps work
|
||||
## Como as aplicações funcionam
|
||||
|
||||
An app is a collection of **entities** declared using `defineEntity()` functions from the `twenty-sdk` package. The SDK detects these declarations via AST analysis at build time and produces a **manifest** — a complete description of what your app adds to a workspace.
|
||||
Uma aplicação é uma coleção de **entidades** declaradas usando funções `defineEntity()` do pacote `twenty-sdk`. O SDK detecta essas declarações via análise de AST no momento da compilação e produz um **manifesto** — uma descrição completa do que seu aplicativo adiciona a um espaço de trabalho.
|
||||
|
||||
```
|
||||
your-app/
|
||||
@@ -29,32 +29,32 @@ your-app/
|
||||
```
|
||||
|
||||
<Note>
|
||||
**File organization is up to you.** Entity detection is AST-based — the SDK finds `export default defineEntity(...)` calls regardless of where the file lives. The folder structure above is a convention, not a requirement.
|
||||
**A organização de arquivos fica a seu critério.** A detecção de entidades é baseada em AST — o SDK encontra chamadas a `export default defineEntity(...)` independentemente de onde o arquivo esteja. A estrutura de pastas acima é uma convenção, não um requisito.
|
||||
</Note>
|
||||
|
||||
## Entity types
|
||||
## Tipos de entidade
|
||||
|
||||
| Entidade | Finalidade | Documentação |
|
||||
| ------------------------ | ----------------------------------------- | ------------------------------------------------------------ |
|
||||
| **Application** | App identity, permissions, variables | [Data Model](/l/pt/developers/extend/apps/data-model) |
|
||||
| **Role** | Permission sets for objects and fields | [Data Model](/l/pt/developers/extend/apps/data-model) |
|
||||
| **Objeto** | Custom data tables with fields | [Data Model](/l/pt/developers/extend/apps/data-model) |
|
||||
| **Campo** | Extend existing objects, define relations | [Data Model](/l/pt/developers/extend/apps/data-model) |
|
||||
| **Logic Function** | Server-side TypeScript with triggers | [Funções lógicas](/l/pt/developers/extend/apps/logic-functions) |
|
||||
| **Front Component** | Sandboxed React UI in Twenty's page | [Front Components](/l/pt/developers/extend/apps/front-components) |
|
||||
| **Skill** | Reusable AI agent instructions | [Skills & Agents](/l/pt/developers/extend/apps/skills-and-agents) |
|
||||
| **Agent** | AI assistants with custom prompts | [Skills & Agents](/l/pt/developers/extend/apps/skills-and-agents) |
|
||||
| **View** | Pre-configured record list views | [Layout](/l/pt/developers/extend/apps/layout) |
|
||||
| **Navigation Menu Item** | Custom sidebar entries | [Layout](/l/pt/developers/extend/apps/layout) |
|
||||
| **Page Layout** | Custom record page tabs and widgets | [Layout](/l/pt/developers/extend/apps/layout) |
|
||||
| Entidade | Finalidade | Documentação |
|
||||
| ----------------------------- | ----------------------------------------------------- | -------------------------------------------------------------------- |
|
||||
| **Aplicação** | Identidade da aplicação, permissões, variáveis | [Modelo de Dados](/l/pt/developers/extend/apps/data-model) |
|
||||
| **Papel** | Conjuntos de permissões para objetos e campos | [Modelo de Dados](/l/pt/developers/extend/apps/data-model) |
|
||||
| **Objeto** | Tabelas de dados personalizadas com campos | [Modelo de Dados](/l/pt/developers/extend/apps/data-model) |
|
||||
| **Campo** | Estender objetos existentes, definir relações | [Modelo de Dados](/l/pt/developers/extend/apps/data-model) |
|
||||
| **Função lógica** | TypeScript no lado do servidor com gatilhos | [Funções lógicas](/l/pt/developers/extend/apps/logic-functions) |
|
||||
| **Componente de front-end** | UI React em sandbox na página do Twenty | [Componentes de front-end](/l/pt/developers/extend/apps/front-components) |
|
||||
| **Habilidade** | Instruções reutilizáveis para agentes de IA | [Habilidades e Agentes](/l/pt/developers/extend/apps/skills-and-agents) |
|
||||
| **Agente** | Assistentes de IA com prompts personalizados | [Habilidades e Agentes](/l/pt/developers/extend/apps/skills-and-agents) |
|
||||
| **Vista** | Vistas de lista de registros pré-configuradas | [Layout](/l/pt/developers/extend/apps/layout) |
|
||||
| **Item do menu de navegação** | Entradas personalizadas na barra lateral | [Layout](/l/pt/developers/extend/apps/layout) |
|
||||
| **Layout da Página** | Abas e widgets personalizados nas páginas de registro | [Layout](/l/pt/developers/extend/apps/layout) |
|
||||
|
||||
## Sandboxing
|
||||
|
||||
* **Logic functions** run in isolated Node.js processes on the server. They only access data through the typed API client, scoped to the app's role permissions.
|
||||
* **Front components** run in Web Workers using Remote DOM — sandboxed from the main page but rendering native DOM elements (not iframes). They communicate with Twenty via a message-passing host API.
|
||||
* **Permissions** are enforced at the API level. The runtime token (`TWENTY_APP_ACCESS_TOKEN`) is derived from the role defined in `defineApplication()`.
|
||||
* **Funções lógicas** são executadas em processos Node.js isolados no servidor. Elas acessam dados apenas por meio do cliente de API tipado, restrito às permissões do papel do aplicativo.
|
||||
* **Componentes de front-end** executam em Web Workers usando Remote DOM — isolados da página principal, mas renderizando elementos DOM nativos (não iframes). Eles se comunicam com o Twenty por meio de uma API de host com passagem de mensagens.
|
||||
* **Permissões** são aplicadas no nível da API. O token de tempo de execução (`TWENTY_APP_ACCESS_TOKEN`) é derivado do papel definido em `defineApplication()`.
|
||||
|
||||
## App lifecycle
|
||||
## Ciclo de vida do aplicativo
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
@@ -73,32 +73,32 @@ your-app/
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
* **`yarn twenty dev`** — watches your source files and live-syncs changes to a connected Twenty server. The typed API client is regenerated automatically when the schema changes.
|
||||
* **`yarn twenty build`** — compiles TypeScript, bundles logic functions and front components with esbuild, and produces a manifest.
|
||||
* **Pre/post-install hooks** — optional logic functions that run during installation. See [Logic Functions](/l/pt/developers/extend/apps/logic-functions) for details.
|
||||
* **`yarn twenty dev`** — observa seus arquivos-fonte e sincroniza ao vivo as alterações com um servidor Twenty conectado. O cliente de API tipado é regenerado automaticamente quando o esquema muda.
|
||||
* **`yarn twenty build`** — compila TypeScript, empacota funções de lógica e componentes de front-end com o esbuild e produz um manifesto.
|
||||
* **Hooks de pré/pós-instalação** — funções de lógica opcionais que são executadas durante a instalação. Veja [Funções de Lógica](/l/pt/developers/extend/apps/logic-functions) para detalhes.
|
||||
|
||||
## Próximos passos
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Modelo de dados" icon="database" href="/l/pt/developers/extend/apps/data-model">
|
||||
Define objects, fields, roles, and relations.
|
||||
Defina objetos, campos, papéis e relações.
|
||||
</Card>
|
||||
<Card title="Funções lógicas" icon="bolt" href="/l/pt/developers/extend/apps/logic-functions">
|
||||
Server-side functions with HTTP, cron, and event triggers.
|
||||
Funções no lado do servidor com gatilhos HTTP, cron e de eventos.
|
||||
</Card>
|
||||
<Card title="Componentes de front-end" icon="window-maximize" href="/l/pt/developers/extend/apps/front-components">
|
||||
Sandboxed React components inside Twenty's UI.
|
||||
Componentes React em sandbox dentro da UI do Twenty.
|
||||
</Card>
|
||||
<Card title="Layout" icon="table-columns" href="/l/pt/developers/extend/apps/layout">
|
||||
Views, navigation items, and record page layouts.
|
||||
Vistas, itens de navegação e layouts de página de registro.
|
||||
</Card>
|
||||
<Card title="Habilidades e agentes" icon="robot" href="/l/pt/developers/extend/apps/skills-and-agents">
|
||||
AI skills and agents with custom prompts.
|
||||
Habilidades e agentes de IA com prompts personalizados.
|
||||
</Card>
|
||||
<Card title="CLI & Testing" icon="terminal" href="/l/pt/developers/extend/apps/cli-and-testing">
|
||||
CLI commands, testing, assets, remotes, and CI.
|
||||
<Card title="CLI e Testes" icon="terminal" href="/l/pt/developers/extend/apps/cli-and-testing">
|
||||
Comandos de CLI, testes, assets, remotes e CI.
|
||||
</Card>
|
||||
<Card title="Publicação" icon="rocket" href="/l/pt/developers/extend/apps/publishing">
|
||||
Deploy to a server or publish to the marketplace.
|
||||
Implante em um servidor ou publique no marketplace.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -20,7 +20,7 @@ Views, navigation items, and page layouts reference each other by `universalIden
|
||||
* A **page layout** of type `RECORD_PAGE` targets an object and can embed [front components](/l/pt/developers/extend/apps/front-components) inside its tabs as widgets.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineView" description="Define visualizações salvas para objetos">
|
||||
<Accordion title="defineView" description="Defina visualizações salvas para objetos">
|
||||
|
||||
As visualizações são configurações salvas de como os registros de um objeto são exibidos — incluindo quais campos são visíveis, sua ordem e quaisquer filtros ou grupos aplicados. Use `defineView()` para enviar visualizações pré-configuradas com seu app:
|
||||
|
||||
@@ -56,7 +56,7 @@ Pontos-chave:
|
||||
* `position` controla a ordenação quando existem várias visualizações para o mesmo objeto.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineNavigationMenuItem" description="Define links de navegação da barra lateral">
|
||||
<Accordion title="defineNavigationMenuItem" description="Defina links de navegação da barra lateral">
|
||||
|
||||
Os itens do menu de navegação adicionam entradas personalizadas à barra lateral do espaço de trabalho. Use `defineNavigationMenuItem()` para vincular a visualizações, URLs externas ou objetos:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Habilidades e agentes
|
||||
description: Define AI skills and agents for your app.
|
||||
description: Defina habilidades e agentes de IA para o seu aplicativo.
|
||||
icon: robot
|
||||
---
|
||||
|
||||
@@ -8,7 +8,7 @@ icon: robot
|
||||
Skills and agents are currently in alpha. O recurso é funcional, mas ainda está evoluindo.
|
||||
</Warning>
|
||||
|
||||
Apps can define AI capabilities that live inside the workspace — reusable skill instructions and agents with custom system prompts.
|
||||
Os aplicativos podem definir capacidades de IA que residem dentro do espaço de trabalho — instruções de habilidades reutilizáveis e agentes com prompts de sistema personalizados.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineSkill" description="Defina habilidades de agentes de IA">
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
---
|
||||
title: OAuth
|
||||
icon: chave
|
||||
description: Authorization code flow with PKCE and client credentials for server-to-server access.
|
||||
description: Fluxo de código de autorização com PKCE e credenciais de cliente para acesso servidor a servidor.
|
||||
---
|
||||
|
||||
Twenty implements OAuth 2.0 with authorization code + PKCE for user-facing apps and client credentials for server-to-server access. Clients are registered dynamically via [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) — no manual setup in a dashboard.
|
||||
A Twenty implementa OAuth 2.0 com código de autorização + PKCE para aplicações voltadas ao utilizador e credenciais de cliente para acesso servidor a servidor. Os clientes são registados dinamicamente via [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) — sem configuração manual num painel.
|
||||
|
||||
## When to Use OAuth
|
||||
## Quando usar OAuth
|
||||
|
||||
| Cenário | Auth Method |
|
||||
| --------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| Internal scripts, automation | [API Key](/l/pt/developers/extend/api#authentication) |
|
||||
| External app acting on behalf of a user | **OAuth — Authorization Code** |
|
||||
| Server-to-server, no user context | **OAuth — Client Credentials** |
|
||||
| Twenty App with UI extensions | [Apps](/l/pt/developers/extend/apps/getting-started) (OAuth is handled automatically) |
|
||||
| Cenário | Método de autenticação |
|
||||
| -------------------------------------------------- | --------------------------------------------------------------------------------------- |
|
||||
| Scripts internos, automatização | [Chave de API](/l/pt/developers/extend/api#authentication) |
|
||||
| Aplicação externa atuando em nome de um utilizador | **OAuth — Código de Autorização** |
|
||||
| Servidor a servidor, sem contexto de utilizador | **OAuth — Credenciais do Cliente** |
|
||||
| Aplicação Twenty com extensões de UI | [Aplicações](/l/pt/developers/extend/apps/getting-started) (OAuth é tratado automaticamente) |
|
||||
|
||||
## Register a Client
|
||||
## Registar um cliente
|
||||
|
||||
Twenty supports **dynamic client registration** per [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). No manual setup needed — register programmatically:
|
||||
A Twenty suporta **registo dinâmico de clientes** conforme [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). Sem necessidade de configuração manual — registe programaticamente:
|
||||
|
||||
```bash
|
||||
POST /oauth/register
|
||||
@@ -31,7 +31,7 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**Resposta:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -43,23 +43,23 @@ Content-Type: application/json
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Store the `client_secret` securely — it cannot be retrieved later.
|
||||
Guarde o `client_secret` com segurança — não poderá ser recuperado mais tarde.
|
||||
</Warning>
|
||||
|
||||
## Escopos
|
||||
|
||||
| Scope | Acesso |
|
||||
| -------- | ---------------------------------------------------- |
|
||||
| `api` | Full read/write access to the Core and Metadata APIs |
|
||||
| `perfil` | Read the authenticated user's profile information |
|
||||
| Escopo | Acesso |
|
||||
| -------- | ------------------------------------------------------- |
|
||||
| `api` | Acesso total de leitura/escrita às APIs Core e Metadata |
|
||||
| `perfil` | Leia as informações do perfil do utilizador autenticado |
|
||||
|
||||
Request scopes as a space-separated string: `scope=api profile`
|
||||
Solicite escopos como uma cadeia separada por espaços: `scope=api profile`
|
||||
|
||||
## Authorization Code Flow
|
||||
## Fluxo de Código de Autorização
|
||||
|
||||
Use this flow when your app acts on behalf of a Twenty user.
|
||||
Use este fluxo quando a sua aplicação atuar em nome de um utilizador da Twenty.
|
||||
|
||||
### 1. Redirect the user to authorize
|
||||
### 1. Redirecione o utilizador para autorizar
|
||||
|
||||
```
|
||||
GET /oauth/authorize?
|
||||
@@ -72,29 +72,29 @@ GET /oauth/authorize?
|
||||
code_challenge_method=S256
|
||||
```
|
||||
|
||||
| Parâmetro | Obrigatório | Descrição |
|
||||
| ----------------------- | ----------- | ------------------------------------------------------------ |
|
||||
| `client_id` | Sim | Your registered client ID |
|
||||
| `response_type` | Sim | Must be `code` |
|
||||
| `redirect_uri` | Sim | Must match a registered redirect URI |
|
||||
| `scope` | Não | Space-separated scopes (defaults to `api`) |
|
||||
| `estado` | Recomendado | Random string to prevent CSRF attacks |
|
||||
| `code_challenge` | Recomendado | PKCE challenge (SHA-256 hash of verifier, base64url-encoded) |
|
||||
| `code_challenge_method` | Recomendado | Must be `S256` when using PKCE |
|
||||
| Parâmetro | Obrigatório | Descrição |
|
||||
| ----------------------- | ----------- | ------------------------------------------------------------------- |
|
||||
| `client_id` | Sim | O seu ID de cliente registado |
|
||||
| `response_type` | Sim | Deve ser `code` |
|
||||
| `redirect_uri` | Sim | Deve corresponder a um URI de redirecionamento registado |
|
||||
| `scope` | Não | Escopos separados por espaços (predefinido para `api`) |
|
||||
| `estado` | Recomendado | Cadeia aleatória para prevenir ataques CSRF |
|
||||
| `code_challenge` | Recomendado | Desafio PKCE (hash SHA-256 do verificador, codificado em base64url) |
|
||||
| `code_challenge_method` | Recomendado | Deve ser `S256` ao usar PKCE |
|
||||
|
||||
The user sees a consent screen and approves or denies access.
|
||||
O utilizador vê um ecrã de consentimento e aprova ou nega o acesso.
|
||||
|
||||
### 2. Handle the callback
|
||||
### 2. Trate o callback
|
||||
|
||||
After authorization, Twenty redirects back to your `redirect_uri`:
|
||||
Após a autorização, a Twenty redireciona de volta para o seu `redirect_uri`:
|
||||
|
||||
```
|
||||
https://myapp.com/callback?code=AUTH_CODE&state=random_state_value
|
||||
```
|
||||
|
||||
Verify that `state` matches what you sent.
|
||||
Verifique se `state` corresponde ao que enviou.
|
||||
|
||||
### 3. Exchange the code for tokens
|
||||
### 3. Troque o código por tokens
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -108,7 +108,7 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
code_verifier=YOUR_PKCE_VERIFIER
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**Resposta:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -119,14 +119,14 @@ code_verifier=YOUR_PKCE_VERIFIER
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Use the access token
|
||||
### 4. Use o token de acesso
|
||||
|
||||
```bash
|
||||
GET /rest/companies
|
||||
Authorization: Bearer ACCESS_TOKEN
|
||||
```
|
||||
|
||||
### 5. Refresh when expired
|
||||
### 5. Atualize quando expirar
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -138,9 +138,9 @@ client_id=YOUR_CLIENT_ID&
|
||||
client_secret=YOUR_CLIENT_SECRET
|
||||
```
|
||||
|
||||
## Client Credentials Flow
|
||||
## Fluxo de Credenciais do Cliente
|
||||
|
||||
For server-to-server integrations with no user interaction:
|
||||
Para integrações servidor a servidor sem interação do utilizador:
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -152,38 +152,38 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
scope=api
|
||||
```
|
||||
|
||||
The returned token has workspace-level access, not tied to any specific user.
|
||||
O token retornado tem acesso ao nível do espaço de trabalho, não vinculado a nenhum utilizador específico.
|
||||
|
||||
## Server Discovery
|
||||
## Descoberta do servidor
|
||||
|
||||
Twenty publishes its OAuth configuration at a standard discovery endpoint:
|
||||
A Twenty publica a sua configuração OAuth num endpoint padrão de descoberta:
|
||||
|
||||
```
|
||||
GET /.well-known/oauth-authorization-server
|
||||
```
|
||||
|
||||
This returns all endpoints, supported grant types, scopes, and capabilities — useful for building generic OAuth clients.
|
||||
Isto retorna todos os endpoints, tipos de concessão suportados, escopos e capacidades — útil para criar clientes OAuth genéricos.
|
||||
|
||||
## API Endpoints Summary
|
||||
## Resumo de endpoints da API
|
||||
|
||||
| Endpoint | Finalidade |
|
||||
| ----------------------------------------- | --------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Server metadata discovery |
|
||||
| `/oauth/register` | Dynamic client registration |
|
||||
| `/oauth/authorize` | User authorization |
|
||||
| `/oauth/token` | Token exchange and refresh |
|
||||
| Endpoint | Finalidade |
|
||||
| ----------------------------------------- | ----------------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Descoberta de metadados do servidor |
|
||||
| `/oauth/register` | Registo dinâmico de cliente |
|
||||
| `/oauth/authorize` | Autorização do utilizador |
|
||||
| `/oauth/token` | Troca e atualização de tokens |
|
||||
|
||||
| Ambiente | URL base |
|
||||
| ------------------ | ------------------------ |
|
||||
| **Nuvem** | `https://api.twenty.com` |
|
||||
| **Auto-hospedado** | `https://{your-domain}` |
|
||||
|
||||
## OAuth vs API Keys
|
||||
## OAuth vs Chaves de API
|
||||
|
||||
| | Chaves API | OAuth |
|
||||
| ------------------ | ----------------------- | -------------------------------------- |
|
||||
| **Configuração** | Generate in Settings | Register a client, implement flow |
|
||||
| **User context** | None (workspace-level) | Specific user's permissions |
|
||||
| **Melhor para** | Scripts, internal tools | External apps, multi-user integrations |
|
||||
| **Token rotation** | Manual | Automatic via refresh tokens |
|
||||
| **Scoped access** | Full API access | Granular via scopes |
|
||||
| | Chaves API | OAuth |
|
||||
| ----------------------------- | ------------------------------------ | ------------------------------------------------ |
|
||||
| **Configuração** | Gerar em Configurações | Registar um cliente, implementar o fluxo |
|
||||
| **Contexto do utilizador** | Nenhum (nível de espaço de trabalho) | Permissões de um utilizador específico |
|
||||
| **Melhor para** | Scripts, ferramentas internas | Aplicações externas, integrações multiutilizador |
|
||||
| **Rotação de tokens** | Manual | Automática via tokens de atualização |
|
||||
| **Acesso baseado em escopos** | Acesso total à API | Granular por escopos |
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Webhooks
|
||||
icon: satellite-dish
|
||||
description: Get notified when records change — HTTP POST to your endpoint on every create, update, or delete.
|
||||
description: Receba notificações quando os registros mudarem — HTTP POST para o seu endpoint a cada criação, atualização ou exclusão.
|
||||
---
|
||||
|
||||
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
|
||||
|
||||
Twenty sends an HTTP POST to your URL whenever a record is created, updated, or deleted. All object types are covered, including custom objects.
|
||||
Twenty envia um HTTP POST para sua URL sempre que um registro é criado, atualizado ou excluído. Todos os tipos de objeto estão cobertos, incluindo objetos personalizados.
|
||||
|
||||
## Criar Webhook
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Commands
|
||||
title: Команды
|
||||
icon: terminal
|
||||
description: Useful commands for developing Twenty.
|
||||
description: Полезные команды для разработки Twenty.
|
||||
---
|
||||
|
||||
Commands can be run from the repository root using `npx nx`. Use `npx nx run {project}:{command}` for explicit targeting.
|
||||
Команды можно запускать из корня репозитория с помощью `npx nx`. Используйте `npx nx run {project}:{command}` для явного указания цели.
|
||||
|
||||
## Starting the App
|
||||
## Запуск приложения
|
||||
|
||||
```bash
|
||||
npx nx start twenty-front # Frontend dev server (http://localhost:3001)
|
||||
@@ -14,7 +14,7 @@ npx nx start twenty-server # Backend server (http://localhost:3000)
|
||||
npx nx run twenty-server:worker # Background worker
|
||||
```
|
||||
|
||||
## Database
|
||||
## База данных
|
||||
|
||||
```bash
|
||||
npx nx database:reset twenty-server # Reset and seed database
|
||||
@@ -22,7 +22,7 @@ npx nx run twenty-server:database:migrate:prod # Run migrations
|
||||
npx nx run twenty-server:database:migrate:generate --name <name> --type <fast|slow> # Generate a migration
|
||||
```
|
||||
|
||||
## Linting
|
||||
## Линтинг
|
||||
|
||||
```bash
|
||||
npx nx lint:diff-with-main twenty-front # Lint changed files (fastest)
|
||||
@@ -30,7 +30,7 @@ npx nx lint:diff-with-main twenty-server
|
||||
npx nx lint twenty-front --configuration=fix # Auto-fix
|
||||
```
|
||||
|
||||
## Type Checking
|
||||
## Проверка типов
|
||||
|
||||
```bash
|
||||
npx nx typecheck twenty-front
|
||||
@@ -68,7 +68,7 @@ npx nx run twenty-front:lingui:extract # Extract strings
|
||||
npx nx run twenty-front:lingui:compile # Compile translations
|
||||
```
|
||||
|
||||
## Build
|
||||
## Сборка
|
||||
|
||||
```bash
|
||||
npx nx build twenty-shared # Must be built first
|
||||
|
||||
@@ -110,7 +110,7 @@ const value = process.env.MY_VALUE ?? 'default';
|
||||
onClick?.();
|
||||
```
|
||||
|
||||
## Называние
|
||||
## Именование
|
||||
|
||||
* **Variables**: camelCase, descriptive (`email` not `value`, `fieldMetadata` not `fm`)
|
||||
* **Constants**: SCREAMING_SNAKE_CASE
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
title: Архитектура
|
||||
description: How Twenty apps work — sandboxing, lifecycle, and the building blocks.
|
||||
description: Как работают приложения Twenty — изоляция в песочнице, жизненный цикл и базовые элементы.
|
||||
icon: sitemap
|
||||
---
|
||||
|
||||
Twenty apps are TypeScript packages that extend your workspace with custom objects, logic, UI components, and AI capabilities. They run on the Twenty platform with full sandboxing and permission controls.
|
||||
Приложения Twenty — это пакеты TypeScript, которые расширяют ваше рабочее пространство пользовательскими объектами, логикой, компонентами интерфейса и возможностями ИИ. Они работают на платформе Twenty с полной изоляцией в песочнице и контролем прав доступа.
|
||||
|
||||
## How apps work
|
||||
## Как работают приложения
|
||||
|
||||
An app is a collection of **entities** declared using `defineEntity()` functions from the `twenty-sdk` package. The SDK detects these declarations via AST analysis at build time and produces a **manifest** — a complete description of what your app adds to a workspace.
|
||||
Приложение — это набор **сущностей**, объявленных с помощью функций `defineEntity()` из пакета `twenty-sdk`. SDK обнаруживает эти объявления посредством анализа AST на этапе сборки и формирует **манифест** — полное описание того, что ваше приложение добавляет в рабочее пространство.
|
||||
|
||||
```
|
||||
your-app/
|
||||
@@ -29,32 +29,32 @@ your-app/
|
||||
```
|
||||
|
||||
<Note>
|
||||
**File organization is up to you.** Entity detection is AST-based — the SDK finds `export default defineEntity(...)` calls regardless of where the file lives. The folder structure above is a convention, not a requirement.
|
||||
**Организация файлов — на ваше усмотрение.** Обнаружение сущностей основано на AST — SDK находит вызовы `export default defineEntity(...)` независимо от расположения файла. Структура папок выше — это соглашение, а не требование.
|
||||
</Note>
|
||||
|
||||
## Entity types
|
||||
## Типы сущностей
|
||||
|
||||
| Сущность | Назначение | Документация |
|
||||
| ------------------------ | ----------------------------------------- | ------------------------------------------------------------- |
|
||||
| **Application** | App identity, permissions, variables | [Data Model](/l/ru/developers/extend/apps/data-model) |
|
||||
| **Role** | Permission sets for objects and fields | [Data Model](/l/ru/developers/extend/apps/data-model) |
|
||||
| **Object** | Custom data tables with fields | [Data Model](/l/ru/developers/extend/apps/data-model) |
|
||||
| **Поле** | Extend existing objects, define relations | [Data Model](/l/ru/developers/extend/apps/data-model) |
|
||||
| **Logic Function** | Server-side TypeScript with triggers | [Логические функции](/l/ru/developers/extend/apps/logic-functions) |
|
||||
| **Front Component** | Sandboxed React UI in Twenty's page | [Front Components](/l/ru/developers/extend/apps/front-components) |
|
||||
| **Skill** | Reusable AI agent instructions | [Skills & Agents](/l/ru/developers/extend/apps/skills-and-agents) |
|
||||
| **Agent** | AI assistants with custom prompts | [Skills & Agents](/l/ru/developers/extend/apps/skills-and-agents) |
|
||||
| **View** | Pre-configured record list views | [Layout](/l/ru/developers/extend/apps/layout) |
|
||||
| **Navigation Menu Item** | Custom sidebar entries | [Layout](/l/ru/developers/extend/apps/layout) |
|
||||
| **Page Layout** | Custom record page tabs and widgets | [Layout](/l/ru/developers/extend/apps/layout) |
|
||||
| Сущность | Назначение | Документация |
|
||||
| ------------------------ | ------------------------------------------------------------ | ---------------------------------------------------------------- |
|
||||
| **Приложение** | Идентификация приложения, права доступа, переменные | [Модель данных](/l/ru/developers/extend/apps/data-model) |
|
||||
| **Роль** | Наборы прав для объектов и полей | [Модель данных](/l/ru/developers/extend/apps/data-model) |
|
||||
| **Object** | Пользовательские таблицы данных с полями | [Модель данных](/l/ru/developers/extend/apps/data-model) |
|
||||
| **Поле** | Расширение существующих объектов, определение связей | [Модель данных](/l/ru/developers/extend/apps/data-model) |
|
||||
| **Логическая функция** | Серверный TypeScript с триггерами | [Логические функции](/l/ru/developers/extend/apps/logic-functions) |
|
||||
| **Компонент фронтенда** | Изолированный в песочнице интерфейс React на странице Twenty | [Компоненты фронтенда](/l/ru/developers/extend/apps/front-components) |
|
||||
| **Навык** | Повторно используемые инструкции для ИИ-агента | [Навыки и агенты](/l/ru/developers/extend/apps/skills-and-agents) |
|
||||
| **Агент** | ИИ-агенты с пользовательскими промптами | [Навыки и агенты](/l/ru/developers/extend/apps/skills-and-agents) |
|
||||
| **Представление** | Преднастроенные представления списков записей | [Макет](/l/ru/developers/extend/apps/layout) |
|
||||
| **Пункт меню навигации** | Пользовательские элементы боковой панели | [Макет](/l/ru/developers/extend/apps/layout) |
|
||||
| **Макет страницы** | Пользовательские вкладки и виджеты страницы записи | [Макет](/l/ru/developers/extend/apps/layout) |
|
||||
|
||||
## Sandboxing
|
||||
## Изоляция в песочнице
|
||||
|
||||
* **Logic functions** run in isolated Node.js processes on the server. They only access data through the typed API client, scoped to the app's role permissions.
|
||||
* **Front components** run in Web Workers using Remote DOM — sandboxed from the main page but rendering native DOM elements (not iframes). They communicate with Twenty via a message-passing host API.
|
||||
* **Permissions** are enforced at the API level. The runtime token (`TWENTY_APP_ACCESS_TOKEN`) is derived from the role defined in `defineApplication()`.
|
||||
* **Логические функции** выполняются в изолированных процессах Node.js на сервере. Они получают доступ к данным только через типизированный клиент API, ограниченный правами роли приложения.
|
||||
* **Компоненты фронтенда** запускаются в Web Workers с использованием Remote DOM — изолированы от основной страницы, но при этом рендерят нативные элементы DOM (не iframes). Они взаимодействуют с Twenty через хостовый API обмена сообщениями.
|
||||
* **Права доступа** применяются на уровне API. Токен времени выполнения (`TWENTY_APP_ACCESS_TOKEN`) выводится из роли, определённой в `defineApplication()`.
|
||||
|
||||
## App lifecycle
|
||||
## Жизненный цикл приложения
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
@@ -73,32 +73,32 @@ your-app/
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
* **`yarn twenty dev`** — watches your source files and live-syncs changes to a connected Twenty server. The typed API client is regenerated automatically when the schema changes.
|
||||
* **`yarn twenty build`** — compiles TypeScript, bundles logic functions and front components with esbuild, and produces a manifest.
|
||||
* **Pre/post-install hooks** — optional logic functions that run during installation. See [Logic Functions](/l/ru/developers/extend/apps/logic-functions) for details.
|
||||
* **`yarn twenty dev`** — следит за исходными файлами и синхронизирует изменения в реальном времени с подключённым сервером Twenty. Типизированный клиент API автоматически пересоздаётся при изменении схемы.
|
||||
* **`yarn twenty build`** — компилирует TypeScript, упаковывает логические функции и фронтенд-компоненты с помощью esbuild и формирует манифест.
|
||||
* **Хуки до/после установки** — необязательные логические функции, которые выполняются во время установки. См. [Логические функции](/l/ru/developers/extend/apps/logic-functions) для подробностей.
|
||||
|
||||
## Следующие шаги
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Модель данных" icon="database" href="/l/ru/developers/extend/apps/data-model">
|
||||
Define objects, fields, roles, and relations.
|
||||
Определяйте объекты, поля, роли и связи.
|
||||
</Card>
|
||||
<Card title="Логические функции" icon="bolt" href="/l/ru/developers/extend/apps/logic-functions">
|
||||
Server-side functions with HTTP, cron, and event triggers.
|
||||
Серверные функции с HTTP-, cron- и событийными триггерами.
|
||||
</Card>
|
||||
<Card title="Компоненты фронтенда" icon="window-maximize" href="/l/ru/developers/extend/apps/front-components">
|
||||
Sandboxed React components inside Twenty's UI.
|
||||
Изолированные в песочнице компоненты React внутри интерфейса Twenty.
|
||||
</Card>
|
||||
<Card title="Макет" icon="table-columns" href="/l/ru/developers/extend/apps/layout">
|
||||
Views, navigation items, and record page layouts.
|
||||
Представления, пункты навигации и макеты страниц записей.
|
||||
</Card>
|
||||
<Card title="Навыки и агенты" icon="robot" href="/l/ru/developers/extend/apps/skills-and-agents">
|
||||
AI skills and agents with custom prompts.
|
||||
ИИ-навыки и агенты с пользовательскими промптами.
|
||||
</Card>
|
||||
<Card title="CLI & Testing" icon="terminal" href="/l/ru/developers/extend/apps/cli-and-testing">
|
||||
CLI commands, testing, assets, remotes, and CI.
|
||||
<Card title="CLI и тестирование" icon="terminal" href="/l/ru/developers/extend/apps/cli-and-testing">
|
||||
Команды CLI, тестирование, ассеты, удалённые модули и CI.
|
||||
</Card>
|
||||
<Card title="Публикация" icon="rocket" href="/l/ru/developers/extend/apps/publishing">
|
||||
Deploy to a server or publish to the marketplace.
|
||||
Разверните на сервере или опубликуйте в маркетплейсе.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: CLI & Testing
|
||||
description: CLI commands, testing setup, public assets, npm packages, remotes, and CI configuration.
|
||||
title: CLI и тестирование
|
||||
description: Команды CLI, настройка тестирования, публичные ресурсы, пакеты npm, удалённые репозитории и конфигурация CI.
|
||||
icon: terminal
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Навыки и агенты
|
||||
description: Define AI skills and agents for your app.
|
||||
description: Определите навыки и агентов ИИ для вашего приложения.
|
||||
icon: robot
|
||||
---
|
||||
|
||||
@@ -8,7 +8,7 @@ icon: robot
|
||||
Skills and agents are currently in alpha. Функция работает, но продолжает развиваться.
|
||||
</Warning>
|
||||
|
||||
Apps can define AI capabilities that live inside the workspace — reusable skill instructions and agents with custom system prompts.
|
||||
Приложения могут определять возможности ИИ, которые находятся внутри рабочего пространства — повторно используемые инструкции для навыков и агенты с настраиваемыми системными подсказками.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineSkill" description="Определяйте навыки ИИ-агентов">
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
---
|
||||
title: OAuth
|
||||
icon: ключ
|
||||
description: Authorization code flow with PKCE and client credentials for server-to-server access.
|
||||
description: Поток авторизационного кода с PKCE и учётными данными клиента для доступа между серверами.
|
||||
---
|
||||
|
||||
Twenty implements OAuth 2.0 with authorization code + PKCE for user-facing apps and client credentials for server-to-server access. Clients are registered dynamically via [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) — no manual setup in a dashboard.
|
||||
Twenty реализует OAuth 2.0 с потоком авторизационного кода + PKCE для пользовательских приложений и с учётными данными клиента для доступа между серверами. Клиенты регистрируются динамически по [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) — никакой ручной настройки в панели управления.
|
||||
|
||||
## When to Use OAuth
|
||||
## Когда использовать OAuth
|
||||
|
||||
| Сценарий | Auth Method |
|
||||
| --------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| Internal scripts, automation | [API Key](/l/ru/developers/extend/api#authentication) |
|
||||
| External app acting on behalf of a user | **OAuth — Authorization Code** |
|
||||
| Server-to-server, no user context | **OAuth — Client Credentials** |
|
||||
| Twenty App with UI extensions | [Apps](/l/ru/developers/extend/apps/getting-started) (OAuth is handled automatically) |
|
||||
| Сценарий | Метод аутентификации |
|
||||
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
|
||||
| Внутренние скрипты, автоматизация | [Ключ API](/l/ru/developers/extend/api#authentication) |
|
||||
| Внешнее приложение, действующее от имени пользователя | **OAuth — авторизационный код** |
|
||||
| Между серверами, без контекста пользователя | **OAuth — клиентские учётные данные** |
|
||||
| Приложение Twenty с расширениями пользовательского интерфейса (UI) | [Приложения](/l/ru/developers/extend/apps/getting-started) (OAuth обрабатывается автоматически) |
|
||||
|
||||
## Register a Client
|
||||
## Зарегистрировать клиента
|
||||
|
||||
Twenty supports **dynamic client registration** per [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). No manual setup needed — register programmatically:
|
||||
Twenty поддерживает **динамическую регистрацию клиентов** по [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). Ручная настройка не требуется — регистрируйте программно:
|
||||
|
||||
```bash
|
||||
POST /oauth/register
|
||||
@@ -31,7 +31,7 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**Ответ:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -43,23 +43,23 @@ Content-Type: application/json
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Store the `client_secret` securely — it cannot be retrieved later.
|
||||
Храните `client_secret` в надёжном месте — позже его нельзя будет получить.
|
||||
</Warning>
|
||||
|
||||
## Области действия
|
||||
|
||||
| Scope | Доступ |
|
||||
| --------- | ---------------------------------------------------- |
|
||||
| `api` | Full read/write access to the Core and Metadata APIs |
|
||||
| `профиль` | Read the authenticated user's profile information |
|
||||
| Область действия | Доступ |
|
||||
| ---------------- | ----------------------------------------------------------- |
|
||||
| `api` | Полный доступ на чтение/запись к Core и Metadata API |
|
||||
| `profile` | Чтение информации профиля аутентифицированного пользователя |
|
||||
|
||||
Request scopes as a space-separated string: `scope=api profile`
|
||||
Запрашивайте области действия как строку, разделённую пробелами: `scope=api profile`
|
||||
|
||||
## Authorization Code Flow
|
||||
## Поток авторизационного кода
|
||||
|
||||
Use this flow when your app acts on behalf of a Twenty user.
|
||||
Используйте этот поток, когда ваше приложение действует от имени пользователя Twenty.
|
||||
|
||||
### 1. Redirect the user to authorize
|
||||
### 1. Перенаправьте пользователя для авторизации
|
||||
|
||||
```
|
||||
GET /oauth/authorize?
|
||||
@@ -72,29 +72,29 @@ GET /oauth/authorize?
|
||||
code_challenge_method=S256
|
||||
```
|
||||
|
||||
| Параметр | Обязательно | Описание |
|
||||
| ----------------------- | ------------- | ------------------------------------------------------------ |
|
||||
| `client_id` | Да | Your registered client ID |
|
||||
| `response_type` | Да | Must be `code` |
|
||||
| `redirect_uri` | Да | Must match a registered redirect URI |
|
||||
| `scope` | Нет | Space-separated scopes (defaults to `api`) |
|
||||
| `состояние` | Рекомендуется | Random string to prevent CSRF attacks |
|
||||
| `code_challenge` | Рекомендуется | PKCE challenge (SHA-256 hash of verifier, base64url-encoded) |
|
||||
| `code_challenge_method` | Рекомендуется | Must be `S256` when using PKCE |
|
||||
| Параметр | Обязательно | Описание |
|
||||
| ----------------------- | ------------- | --------------------------------------------------------------- |
|
||||
| `client_id` | Да | Идентификатор вашего зарегистрированного клиента |
|
||||
| `response_type` | Да | Должно быть `code` |
|
||||
| `redirect_uri` | Да | Должен совпадать с зарегистрированным redirect URI |
|
||||
| `scope` | Нет | Области действия, разделённые пробелами (по умолчанию `api`) |
|
||||
| `state` | Рекомендуется | Случайная строка для предотвращения CSRF-атак |
|
||||
| `code_challenge` | Рекомендуется | Вызов PKCE (хэш SHA-256 от верификатора, в кодировке base64url) |
|
||||
| `code_challenge_method` | Рекомендуется | Должно быть `S256` при использовании PKCE |
|
||||
|
||||
The user sees a consent screen and approves or denies access.
|
||||
Пользователь видит экран согласия и подтверждает или отклоняет доступ.
|
||||
|
||||
### 2. Handle the callback
|
||||
### 2. Обработайте обратный вызов
|
||||
|
||||
After authorization, Twenty redirects back to your `redirect_uri`:
|
||||
После авторизации Twenty перенаправляет обратно на ваш `redirect_uri`:
|
||||
|
||||
```
|
||||
https://myapp.com/callback?code=AUTH_CODE&state=random_state_value
|
||||
```
|
||||
|
||||
Verify that `state` matches what you sent.
|
||||
Проверьте, что `state` совпадает с отправленным значением.
|
||||
|
||||
### 3. Exchange the code for tokens
|
||||
### 3. Обменяйте код на токены
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -108,7 +108,7 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
code_verifier=YOUR_PKCE_VERIFIER
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**Ответ:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -119,14 +119,14 @@ code_verifier=YOUR_PKCE_VERIFIER
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Use the access token
|
||||
### 4. Используйте токен доступа
|
||||
|
||||
```bash
|
||||
GET /rest/companies
|
||||
Authorization: Bearer ACCESS_TOKEN
|
||||
```
|
||||
|
||||
### 5. Refresh when expired
|
||||
### 5. Обновляйте при истечении срока действия
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -138,9 +138,9 @@ client_id=YOUR_CLIENT_ID&
|
||||
client_secret=YOUR_CLIENT_SECRET
|
||||
```
|
||||
|
||||
## Client Credentials Flow
|
||||
## Поток клиентских учётных данных
|
||||
|
||||
For server-to-server integrations with no user interaction:
|
||||
Для интеграций между серверами без участия пользователя:
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -152,38 +152,38 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
scope=api
|
||||
```
|
||||
|
||||
The returned token has workspace-level access, not tied to any specific user.
|
||||
Возвращаемый токен имеет доступ на уровне рабочей области и не привязан к конкретному пользователю.
|
||||
|
||||
## Server Discovery
|
||||
## Обнаружение сервера
|
||||
|
||||
Twenty publishes its OAuth configuration at a standard discovery endpoint:
|
||||
Twenty публикует свою конфигурацию OAuth на стандартной конечной точке обнаружения:
|
||||
|
||||
```
|
||||
GET /.well-known/oauth-authorization-server
|
||||
```
|
||||
|
||||
This returns all endpoints, supported grant types, scopes, and capabilities — useful for building generic OAuth clients.
|
||||
Это возвращает все конечные точки, поддерживаемые типы грантов, области действия и возможности — полезно для создания универсальных OAuth-клиентов.
|
||||
|
||||
## API Endpoints Summary
|
||||
## Сводка конечных точек API
|
||||
|
||||
| Конечная точка | Назначение |
|
||||
| ----------------------------------------- | --------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Server metadata discovery |
|
||||
| `/oauth/register` | Dynamic client registration |
|
||||
| `/oauth/authorize` | User authorization |
|
||||
| `/oauth/token` | Token exchange and refresh |
|
||||
| Конечная точка | Назначение |
|
||||
| ----------------------------------------- | --------------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Обнаружение метаданных сервера |
|
||||
| `/oauth/register` | Динамическая регистрация клиентов |
|
||||
| `/oauth/authorize` | Авторизация пользователя |
|
||||
| `/oauth/token` | Обмен и обновление токена |
|
||||
|
||||
| Среда | Базовый URL |
|
||||
| --------------------------- | ------------------------ |
|
||||
| **Облако** | `https://api.twenty.com` |
|
||||
| **Самостоятельный хостинг** | `https://{your-domain}` |
|
||||
|
||||
## OAuth vs API Keys
|
||||
## OAuth против ключей API
|
||||
|
||||
| | API ключи | OAuth |
|
||||
| ---------------------------- | ----------------------- | -------------------------------------- |
|
||||
| **Настройка** | Generate in Settings | Register a client, implement flow |
|
||||
| **User context** | None (workspace-level) | Specific user's permissions |
|
||||
| **Лучше всего подходит для** | Scripts, internal tools | External apps, multi-user integrations |
|
||||
| **Token rotation** | Вручную | Automatic via refresh tokens |
|
||||
| **Scoped access** | Full API access | Granular via scopes |
|
||||
| | API ключи | OAuth |
|
||||
| ------------------------------- | ------------------------------------- | ----------------------------------------------------- |
|
||||
| **Настройка** | Создаются в разделе «Настройки» | Зарегистрировать клиента, реализовать поток |
|
||||
| **Контекст пользователя** | Отсутствует (уровень рабочей области) | Права конкретного пользователя |
|
||||
| **Лучше всего подходит для** | Скрипты, внутренние инструменты | Внешние приложения, мультипользовательские интеграции |
|
||||
| **Ротация токенов** | Вручную | Автоматическая с помощью refresh-токенов |
|
||||
| **Доступ по областям действия** | Полный доступ к API | Детализированный через области действия |
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Вебхуки
|
||||
icon: satellite-dish
|
||||
description: Get notified when records change — HTTP POST to your endpoint on every create, update, or delete.
|
||||
description: Получайте уведомления при изменении записей — HTTP POST на вашу конечную точку при каждом создании, обновлении или удалении.
|
||||
---
|
||||
|
||||
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
|
||||
|
||||
Twenty sends an HTTP POST to your URL whenever a record is created, updated, or deleted. All object types are covered, including custom objects.
|
||||
Twenty отправляет запрос HTTP POST на ваш URL каждый раз, когда запись создаётся, обновляется или удаляется. Поддерживаются все типы объектов, включая пользовательские объекты.
|
||||
|
||||
## Создать вебхук
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Commands
|
||||
title: Komutlar
|
||||
icon: terminal
|
||||
description: Useful commands for developing Twenty.
|
||||
description: Twenty geliştirmek için yararlı komutlar.
|
||||
---
|
||||
|
||||
Commands can be run from the repository root using `npx nx`. Use `npx nx run {project}:{command}` for explicit targeting.
|
||||
Komutlar, deponun kök dizininden `npx nx` kullanılarak çalıştırılabilir. Açık hedefleme için `npx nx run {project}:{command}` kullanın.
|
||||
|
||||
## Starting the App
|
||||
## Uygulamayı Başlatma
|
||||
|
||||
```bash
|
||||
npx nx start twenty-front # Frontend dev server (http://localhost:3001)
|
||||
@@ -14,7 +14,7 @@ npx nx start twenty-server # Backend server (http://localhost:3000)
|
||||
npx nx run twenty-server:worker # Background worker
|
||||
```
|
||||
|
||||
## Database
|
||||
## Veritabanı
|
||||
|
||||
```bash
|
||||
npx nx database:reset twenty-server # Reset and seed database
|
||||
@@ -22,7 +22,7 @@ npx nx run twenty-server:database:migrate:prod # Run migrations
|
||||
npx nx run twenty-server:database:migrate:generate --name <name> --type <fast|slow> # Generate a migration
|
||||
```
|
||||
|
||||
## Linting
|
||||
## Lint denetimi
|
||||
|
||||
```bash
|
||||
npx nx lint:diff-with-main twenty-front # Lint changed files (fastest)
|
||||
@@ -30,7 +30,7 @@ npx nx lint:diff-with-main twenty-server
|
||||
npx nx lint twenty-front --configuration=fix # Auto-fix
|
||||
```
|
||||
|
||||
## Type Checking
|
||||
## Tip denetimi
|
||||
|
||||
```bash
|
||||
npx nx typecheck twenty-front
|
||||
@@ -68,7 +68,7 @@ npx nx run twenty-front:lingui:extract # Extract strings
|
||||
npx nx run twenty-front:lingui:compile # Compile translations
|
||||
```
|
||||
|
||||
## Build
|
||||
## Derleme
|
||||
|
||||
```bash
|
||||
npx nx build twenty-shared # Must be built first
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
title: Mimari
|
||||
description: How Twenty apps work — sandboxing, lifecycle, and the building blocks.
|
||||
description: Twenty uygulamaları nasıl çalışır — korumalı alan, yaşam döngüsü ve yapı taşları.
|
||||
icon: sitemap
|
||||
---
|
||||
|
||||
Twenty apps are TypeScript packages that extend your workspace with custom objects, logic, UI components, and AI capabilities. They run on the Twenty platform with full sandboxing and permission controls.
|
||||
Twenty uygulamaları, çalışma alanınızı özel nesneler, mantık, UI bileşenleri ve yapay zekâ yetenekleriyle genişleten TypeScript paketleridir. Tam korumalı alan ve izin kontrolleriyle Twenty platformunda çalışırlar.
|
||||
|
||||
## How apps work
|
||||
## Uygulamalar nasıl çalışır
|
||||
|
||||
An app is a collection of **entities** declared using `defineEntity()` functions from the `twenty-sdk` package. The SDK detects these declarations via AST analysis at build time and produces a **manifest** — a complete description of what your app adds to a workspace.
|
||||
Bir uygulama, `twenty-sdk` paketindeki `defineEntity()` işlevleri kullanılarak bildirilen **varlıklar** koleksiyonudur. SDK, bu bildirimleri derleme sırasında AST analiziyle algılar ve bir **manifest** üretir — uygulamanızın bir çalışma alanına neler eklediğinin eksiksiz bir açıklaması.
|
||||
|
||||
```
|
||||
your-app/
|
||||
@@ -29,32 +29,32 @@ your-app/
|
||||
```
|
||||
|
||||
<Note>
|
||||
**File organization is up to you.** Entity detection is AST-based — the SDK finds `export default defineEntity(...)` calls regardless of where the file lives. The folder structure above is a convention, not a requirement.
|
||||
**Dosya organizasyonu size kalmış.** Varlık algılama AST tabanlıdır — dosyanın nerede bulunduğundan bağımsız olarak SDK `export default defineEntity(...)` çağrılarını bulur. Yukarıdaki klasör yapısı bir gelenektir, zorunluluk değildir.
|
||||
</Note>
|
||||
|
||||
## Entity types
|
||||
## Varlık türleri
|
||||
|
||||
| Varlık | Amaç | Belgeler |
|
||||
| ------------------------ | ----------------------------------------- | ------------------------------------------------------------- |
|
||||
| **Application** | App identity, permissions, variables | [Data Model](/l/tr/developers/extend/apps/data-model) |
|
||||
| **Role** | Permission sets for objects and fields | [Data Model](/l/tr/developers/extend/apps/data-model) |
|
||||
| **Object** | Custom data tables with fields | [Data Model](/l/tr/developers/extend/apps/data-model) |
|
||||
| **Alan** | Extend existing objects, define relations | [Data Model](/l/tr/developers/extend/apps/data-model) |
|
||||
| **Logic Function** | Server-side TypeScript with triggers | [Mantıksal İşlevler](/l/tr/developers/extend/apps/logic-functions) |
|
||||
| **Front Component** | Sandboxed React UI in Twenty's page | [Front Components](/l/tr/developers/extend/apps/front-components) |
|
||||
| **Skill** | Reusable AI agent instructions | [Skills & Agents](/l/tr/developers/extend/apps/skills-and-agents) |
|
||||
| **Agent** | AI assistants with custom prompts | [Skills & Agents](/l/tr/developers/extend/apps/skills-and-agents) |
|
||||
| **View** | Pre-configured record list views | [Layout](/l/tr/developers/extend/apps/layout) |
|
||||
| **Navigation Menu Item** | Custom sidebar entries | [Layout](/l/tr/developers/extend/apps/layout) |
|
||||
| **Page Layout** | Custom record page tabs and widgets | [Layout](/l/tr/developers/extend/apps/layout) |
|
||||
| Varlık | Amaç | Belgeler |
|
||||
| ------------------------ | ------------------------------------------------------------- | --------------------------------------------------------------------- |
|
||||
| **Uygulama** | Uygulama kimliği, izinler, değişkenler | [Veri Modeli](/l/tr/developers/extend/apps/data-model) |
|
||||
| **Rol** | Nesneler ve alanlar için izin kümeleri | [Veri Modeli](/l/tr/developers/extend/apps/data-model) |
|
||||
| **Object** | Alanlara sahip özel veri tabloları | [Veri Modeli](/l/tr/developers/extend/apps/data-model) |
|
||||
| **Alan** | Mevcut nesneleri genişletme, ilişkileri tanımlama | [Veri Modeli](/l/tr/developers/extend/apps/data-model) |
|
||||
| **Mantık İşlevi** | Tetikleyicilerle sunucu tarafı TypeScript | [Mantıksal İşlevler](/l/tr/developers/extend/apps/logic-functions) |
|
||||
| **Ön Uç Bileşeni** | Twenty'nin sayfasında korumalı alanda React kullanıcı arayüzü | [Ön Uç Bileşenleri](/l/tr/developers/extend/apps/front-components) |
|
||||
| **Beceri** | Yeniden kullanılabilir yapay zekâ temsilcisi yönergeleri | [Beceriler ve Temsilciler](/l/tr/developers/extend/apps/skills-and-agents) |
|
||||
| **Temsilci** | Özel istemlere sahip yapay zekâ asistanları | [Beceriler ve Temsilciler](/l/tr/developers/extend/apps/skills-and-agents) |
|
||||
| **Görünüm** | Önceden yapılandırılmış kayıt listesi görünümleri | [Düzen](/l/tr/developers/extend/apps/layout) |
|
||||
| **Gezinme Menüsü Öğesi** | Özel kenar çubuğu öğeleri | [Düzen](/l/tr/developers/extend/apps/layout) |
|
||||
| **Sayfa Düzeni** | Özel kayıt sayfası sekmeleri ve widget'lar | [Düzen](/l/tr/developers/extend/apps/layout) |
|
||||
|
||||
## Sandboxing
|
||||
## Korumalı alan
|
||||
|
||||
* **Logic functions** run in isolated Node.js processes on the server. They only access data through the typed API client, scoped to the app's role permissions.
|
||||
* **Front components** run in Web Workers using Remote DOM — sandboxed from the main page but rendering native DOM elements (not iframes). They communicate with Twenty via a message-passing host API.
|
||||
* **Permissions** are enforced at the API level. The runtime token (`TWENTY_APP_ACCESS_TOKEN`) is derived from the role defined in `defineApplication()`.
|
||||
* **Mantık işlevleri** sunucuda yalıtılmış Node.js işlemlerinde çalışır. Verilere yalnızca, kapsamı uygulamanın rol izinleriyle sınırlandırılmış tipli API istemcisi üzerinden erişirler.
|
||||
* **Ön uç bileşenleri**, Remote DOM kullanan Web Worker'larda çalışır — ana sayfadan yalıtılmıştır ancak yerel DOM öğelerini (iframe'ler değil) oluşturur. Twenty ile mesaj iletimi yapan bir ana makine API'si aracılığıyla iletişim kurarlar.
|
||||
* **İzinler**, API düzeyinde uygulanır. Çalışma zamanı belirteci (`TWENTY_APP_ACCESS_TOKEN`), `defineApplication()` içinde tanımlanan rolden türetilir.
|
||||
|
||||
## App lifecycle
|
||||
## Uygulama yaşam döngüsü
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
@@ -73,32 +73,32 @@ your-app/
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
* **`yarn twenty dev`** — watches your source files and live-syncs changes to a connected Twenty server. The typed API client is regenerated automatically when the schema changes.
|
||||
* **`yarn twenty build`** — compiles TypeScript, bundles logic functions and front components with esbuild, and produces a manifest.
|
||||
* **Pre/post-install hooks** — optional logic functions that run during installation. See [Logic Functions](/l/tr/developers/extend/apps/logic-functions) for details.
|
||||
* **`yarn twenty dev`** — kaynak dosyalarınızı izler ve bağlı bir Twenty sunucusuna değişiklikleri canlı olarak senkronize eder. Şema değiştiğinde tipli API istemcisi otomatik olarak yeniden oluşturulur.
|
||||
* **`yarn twenty build`** — TypeScript'i derler, mantık işlevlerini ve ön uç bileşenlerini esbuild ile paketler ve bir manifest üretir.
|
||||
* **Kurulum öncesi/sonrası kancaları** — kurulum sırasında çalışan isteğe bağlı mantık işlevleri. Ayrıntılar için [Mantık İşlevleri](/l/tr/developers/extend/apps/logic-functions) bölümüne bakın.
|
||||
|
||||
## Sonraki adımlar
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Veri modeli" icon="database" href="/l/tr/developers/extend/apps/data-model">
|
||||
Define objects, fields, roles, and relations.
|
||||
Nesneleri, alanları, rolleri ve ilişkileri tanımlayın.
|
||||
</Card>
|
||||
<Card title="Mantıksal işlevler" icon="bolt" href="/l/tr/developers/extend/apps/logic-functions">
|
||||
Server-side functions with HTTP, cron, and event triggers.
|
||||
HTTP, cron ve olay tetikleyicilerine sahip sunucu tarafı işlevler.
|
||||
</Card>
|
||||
<Card title="Ön uç bileşenleri" icon="window-maximize" href="/l/tr/developers/extend/apps/front-components">
|
||||
Sandboxed React components inside Twenty's UI.
|
||||
Twenty'nin kullanıcı arayüzünde korumalı alanda React bileşenleri.
|
||||
</Card>
|
||||
<Card title="Düzen" icon="table-columns" href="/l/tr/developers/extend/apps/layout">
|
||||
Views, navigation items, and record page layouts.
|
||||
Görünümler, gezinme öğeleri ve kayıt sayfası düzenleri.
|
||||
</Card>
|
||||
<Card title="Beceriler ve Ajanlar" icon="robot" href="/l/tr/developers/extend/apps/skills-and-agents">
|
||||
AI skills and agents with custom prompts.
|
||||
Özel istemlere sahip yapay zekâ becerileri ve temsilciler.
|
||||
</Card>
|
||||
<Card title="CLI & Testing" icon="terminal" href="/l/tr/developers/extend/apps/cli-and-testing">
|
||||
CLI commands, testing, assets, remotes, and CI.
|
||||
<Card title="CLI ve Testler" icon="terminal" href="/l/tr/developers/extend/apps/cli-and-testing">
|
||||
CLI komutları, test, varlıklar, uzak depolar ve CI.
|
||||
</Card>
|
||||
<Card title="Yayımlama" icon="rocket" href="/l/tr/developers/extend/apps/publishing">
|
||||
Deploy to a server or publish to the marketplace.
|
||||
Bir sunucuya dağıtın veya pazaryerine yayınlayın.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: CLI & Testing
|
||||
description: CLI commands, testing setup, public assets, npm packages, remotes, and CI configuration.
|
||||
title: CLI ve Testler
|
||||
description: CLI komutları, test kurulumu, genel varlıklar, npm paketleri, uzaklar ve CI yapılandırması.
|
||||
icon: terminal
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Beceriler ve Ajanlar
|
||||
description: Define AI skills and agents for your app.
|
||||
description: Uygulamanız için yapay zekâ yetenekleri ve ajanları tanımlayın.
|
||||
icon: robot
|
||||
---
|
||||
|
||||
@@ -8,7 +8,7 @@ icon: robot
|
||||
Skills and agents are currently in alpha. Özellik işlevsel ancak hâlâ gelişmekte.
|
||||
</Warning>
|
||||
|
||||
Apps can define AI capabilities that live inside the workspace — reusable skill instructions and agents with custom system prompts.
|
||||
Uygulamalar, çalışma alanı içinde yer alan yapay zekâ yeteneklerini — yeniden kullanılabilir yetenek yönergeleri ve özel sistem istemlerine sahip ajanları — tanımlayabilir.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineSkill" description="Yapay zekâ ajanı yeteneklerini tanımlayın">
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
---
|
||||
title: OAuth
|
||||
icon: anahtar
|
||||
description: Authorization code flow with PKCE and client credentials for server-to-server access.
|
||||
description: PKCE'li yetkilendirme kodu akışı ve sunucudan sunucuya erişim için istemci kimlik bilgileri.
|
||||
---
|
||||
|
||||
Twenty implements OAuth 2.0 with authorization code + PKCE for user-facing apps and client credentials for server-to-server access. Clients are registered dynamically via [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) — no manual setup in a dashboard.
|
||||
Twenty, kullanıcıya dönük uygulamalar için yetkilendirme kodu + PKCE'yi ve sunucudan sunucuya erişim için istemci kimlik bilgilerini kullanarak OAuth 2.0'ı uygular. İstemciler [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) aracılığıyla dinamik olarak kaydedilir — bir kontrol panelinde manuel kurulum gerekmez.
|
||||
|
||||
## When to Use OAuth
|
||||
## OAuth Ne Zaman Kullanılır
|
||||
|
||||
| Senaryo | Auth Method |
|
||||
| --------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| Internal scripts, automation | [API Key](/l/tr/developers/extend/api#authentication) |
|
||||
| External app acting on behalf of a user | **OAuth — Authorization Code** |
|
||||
| Server-to-server, no user context | **OAuth — Client Credentials** |
|
||||
| Twenty App with UI extensions | [Apps](/l/tr/developers/extend/apps/getting-started) (OAuth is handled automatically) |
|
||||
| Senaryo | Kimlik Doğrulama Yöntemi |
|
||||
| --------------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
||||
| Dahili betikler, otomasyon | [API Anahtarı](/l/tr/developers/extend/api#authentication) |
|
||||
| Bir kullanıcının adına hareket eden harici uygulama | **OAuth — Yetkilendirme Kodu** |
|
||||
| Sunucudan sunucuya, kullanıcı bağlamı yok | **OAuth — İstemci Kimlik Bilgileri** |
|
||||
| UI uzantılarına sahip Twenty Uygulaması | [Uygulamalar](/l/tr/developers/extend/apps/getting-started) (OAuth otomatik olarak yönetilir) |
|
||||
|
||||
## Register a Client
|
||||
## Bir İstemci Kaydedin
|
||||
|
||||
Twenty supports **dynamic client registration** per [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). No manual setup needed — register programmatically:
|
||||
Twenty, [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) uyarınca **dinamik istemci kaydını** destekler. Manuel kurulum gerekmez — programatik olarak kaydedin:
|
||||
|
||||
```bash
|
||||
POST /oauth/register
|
||||
@@ -31,7 +31,7 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**Yanıt:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -43,23 +43,23 @@ Content-Type: application/json
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Store the `client_secret` securely — it cannot be retrieved later.
|
||||
`client_secret` değerini güvenli bir şekilde saklayın — daha sonra geri alınamaz.
|
||||
</Warning>
|
||||
|
||||
## Kapsamlar
|
||||
|
||||
| Scope | Erişim |
|
||||
| -------- | ---------------------------------------------------- |
|
||||
| `api` | Full read/write access to the Core and Metadata APIs |
|
||||
| `profil` | Read the authenticated user's profile information |
|
||||
| Kapsam | Erişim |
|
||||
| --------- | ---------------------------------------------------------- |
|
||||
| `api` | Core ve Metadata API'lerine tam okuma/yazma erişimi |
|
||||
| `profile` | Kimliği doğrulanmış kullanıcının profil bilgilerini okuyun |
|
||||
|
||||
Request scopes as a space-separated string: `scope=api profile`
|
||||
Kapsamları boşlukla ayrılmış bir dize olarak isteyin: `scope=api profile`
|
||||
|
||||
## Authorization Code Flow
|
||||
## Yetkilendirme Kodu Akışı
|
||||
|
||||
Use this flow when your app acts on behalf of a Twenty user.
|
||||
Uygulamanız bir Twenty kullanıcısı adına hareket ettiğinde bu akışı kullanın.
|
||||
|
||||
### 1. Redirect the user to authorize
|
||||
### 1. Kullanıcıyı yetkilendirmek için yönlendirin
|
||||
|
||||
```
|
||||
GET /oauth/authorize?
|
||||
@@ -72,29 +72,29 @@ GET /oauth/authorize?
|
||||
code_challenge_method=S256
|
||||
```
|
||||
|
||||
| Parametre | Zorunlu | Açıklama |
|
||||
| ----------------------- | -------- | ------------------------------------------------------------ |
|
||||
| `client_id` | Evet | Your registered client ID |
|
||||
| `response_type` | Evet | Must be `code` |
|
||||
| `redirect_uri` | Evet | Must match a registered redirect URI |
|
||||
| `scope` | Hayır | Space-separated scopes (defaults to `api`) |
|
||||
| `durum` | Önerilen | Random string to prevent CSRF attacks |
|
||||
| `code_challenge` | Önerilen | PKCE challenge (SHA-256 hash of verifier, base64url-encoded) |
|
||||
| `code_challenge_method` | Önerilen | Must be `S256` when using PKCE |
|
||||
| Parametre | Zorunlu | Açıklama |
|
||||
| ----------------------- | -------- | ------------------------------------------------------------------------ |
|
||||
| `client_id` | Evet | Kayıtlı istemci kimliğiniz |
|
||||
| `response_type` | Evet | `code` olmalıdır |
|
||||
| `redirect_uri` | Evet | Kayıtlı bir yönlendirme URI'siyle eşleşmelidir |
|
||||
| `scope` | Hayır | Boşlukla ayrılmış kapsamlar (varsayılan: `api`) |
|
||||
| `state` | Önerilen | CSRF saldırılarını önlemek için rastgele bir dize |
|
||||
| `code_challenge` | Önerilen | PKCE challenge (doğrulayıcının SHA-256 karması, base64url ile kodlanmış) |
|
||||
| `code_challenge_method` | Önerilen | PKCE kullanılırken `S256` olmalıdır |
|
||||
|
||||
The user sees a consent screen and approves or denies access.
|
||||
Kullanıcı bir onay ekranı görür ve erişimi onaylar veya reddeder.
|
||||
|
||||
### 2. Handle the callback
|
||||
### 2. Geri dönüşü işleyin
|
||||
|
||||
After authorization, Twenty redirects back to your `redirect_uri`:
|
||||
Yetkilendirmeden sonra, Twenty `redirect_uri` adresinize geri yönlendirir:
|
||||
|
||||
```
|
||||
https://myapp.com/callback?code=AUTH_CODE&state=random_state_value
|
||||
```
|
||||
|
||||
Verify that `state` matches what you sent.
|
||||
`state` değerinin gönderdiğinizle eşleştiğini doğrulayın.
|
||||
|
||||
### 3. Exchange the code for tokens
|
||||
### 3. Kodu belirteçlerle değiş tokuş edin
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -108,7 +108,7 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
code_verifier=YOUR_PKCE_VERIFIER
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**Yanıt:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -119,14 +119,14 @@ code_verifier=YOUR_PKCE_VERIFIER
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Use the access token
|
||||
### 4. Erişim belirtecini kullanın
|
||||
|
||||
```bash
|
||||
GET /rest/companies
|
||||
Authorization: Bearer ACCESS_TOKEN
|
||||
```
|
||||
|
||||
### 5. Refresh when expired
|
||||
### 5. Süresi dolduğunda yenileyin
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -138,9 +138,9 @@ client_id=YOUR_CLIENT_ID&
|
||||
client_secret=YOUR_CLIENT_SECRET
|
||||
```
|
||||
|
||||
## Client Credentials Flow
|
||||
## İstemci Kimlik Bilgileri Akışı
|
||||
|
||||
For server-to-server integrations with no user interaction:
|
||||
Sunucudan sunucuya, kullanıcı etkileşimi olmayan entegrasyonlar için:
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -152,38 +152,38 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
scope=api
|
||||
```
|
||||
|
||||
The returned token has workspace-level access, not tied to any specific user.
|
||||
Döndürülen belirteç, belirli bir kullanıcıya bağlı olmayan, çalışma alanı düzeyinde erişime sahiptir.
|
||||
|
||||
## Server Discovery
|
||||
## Sunucu Keşfi
|
||||
|
||||
Twenty publishes its OAuth configuration at a standard discovery endpoint:
|
||||
Twenty, OAuth yapılandırmasını standart bir keşif uç noktasında yayımlar:
|
||||
|
||||
```
|
||||
GET /.well-known/oauth-authorization-server
|
||||
```
|
||||
|
||||
This returns all endpoints, supported grant types, scopes, and capabilities — useful for building generic OAuth clients.
|
||||
Bu, tüm uç noktaları, desteklenen grant türlerini, kapsamları ve yetenekleri döndürür — genel OAuth istemcileri oluşturmak için kullanışlıdır.
|
||||
|
||||
## API Endpoints Summary
|
||||
## API Uç Noktaları Özeti
|
||||
|
||||
| Uç nokta | Amaç |
|
||||
| ----------------------------------------- | --------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Server metadata discovery |
|
||||
| `/oauth/register` | Dynamic client registration |
|
||||
| `/oauth/authorize` | User authorization |
|
||||
| `/oauth/token` | Token exchange and refresh |
|
||||
| Uç nokta | Amaç |
|
||||
| ----------------------------------------- | ----------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Sunucu üstverisi keşfi |
|
||||
| `/oauth/register` | Dinamik istemci kaydı |
|
||||
| `/oauth/authorize` | Kullanıcı yetkilendirmesi |
|
||||
| `/oauth/token` | Belirteç değişimi ve yenileme |
|
||||
|
||||
| Ortam | Temel URL |
|
||||
| ---------------------------- | ------------------------ |
|
||||
| **Bulut** | `https://api.twenty.com` |
|
||||
| **Kendi Kendine Barındırma** | `https://{your-domain}` |
|
||||
|
||||
## OAuth vs API Keys
|
||||
## OAuth ve API Anahtarları
|
||||
|
||||
| | API Anahtarları | OAuth |
|
||||
| ------------------ | ----------------------- | -------------------------------------- |
|
||||
| **Kurulum** | Generate in Settings | Register a client, implement flow |
|
||||
| **User context** | None (workspace-level) | Specific user's permissions |
|
||||
| **En uygun** | Scripts, internal tools | External apps, multi-user integrations |
|
||||
| **Token rotation** | Manuel | Automatic via refresh tokens |
|
||||
| **Scoped access** | Full API access | Granular via scopes |
|
||||
| | API Anahtarları | OAuth |
|
||||
| ------------------------- | -------------------------- | -------------------------------------------------- |
|
||||
| **Kurulum** | Ayarlar'da oluşturun | Bir istemci kaydedin, akışı uygulayın |
|
||||
| **Kullanıcı bağlamı** | Yok (çalışma alanı düzeyi) | Belirli bir kullanıcının izinleri |
|
||||
| **En uygun** | Betikler, dahili araçlar | Harici uygulamalar, çok kullanıcılı entegrasyonlar |
|
||||
| **Belirteç döndürme** | Manuel | Yenileme belirteçleri aracılığıyla otomatik olarak |
|
||||
| **Kapsama dayalı erişim** | Tam API erişimi | Kapsamlar aracılığıyla ayrıntılı |
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Webhook'lar
|
||||
icon: satellite-dish
|
||||
description: Get notified when records change — HTTP POST to your endpoint on every create, update, or delete.
|
||||
description: Kayıtlar değiştiğinde bildirim alın — her oluşturma, güncelleme veya silme işleminde uç noktanıza HTTP POST gönderilir.
|
||||
---
|
||||
|
||||
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
|
||||
|
||||
Twenty sends an HTTP POST to your URL whenever a record is created, updated, or deleted. All object types are covered, including custom objects.
|
||||
Bir kayıt oluşturulduğunda, güncellendiğinde veya silindiğinde Twenty URL'inize bir HTTP POST gönderir. Özel nesneler dahil tüm nesne türleri kapsanır.
|
||||
|
||||
## Webhook oluştur
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Sorun Giderme
|
||||
icon: wrench
|
||||
icon: anahtar
|
||||
---
|
||||
|
||||
## Sorun Giderme
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: İkonlar
|
||||
icon: i̇konlar
|
||||
icon: ikonlar
|
||||
---
|
||||
|
||||
<Frame>
|
||||
|
||||
@@ -9,13 +9,13 @@ Twenty'nin yerleşimi üç düzeyde özelleştirilebilir: uygulamada nasıl gezi
|
||||
|
||||
Sol kenar çubuğu tamamen özelleştirilebilir. Şunları yapabilirsiniz:
|
||||
|
||||
* **Öğeleri sürükleyip bırakarak yeniden sıralayın**
|
||||
* **Öğeleri yeniden sıralayın** sürükleyip bırakarak
|
||||
* **Klasörler oluşturun** ilgili nesneleri ve görünümleri gruplamak için
|
||||
* **Nesneleri gizleyin** — kullanmadıklarınızı
|
||||
* **Özel bağlantılar ekleyin** harici araçlara
|
||||
* **Favorileri sabitleyin** görünümlere, kayıtlara veya aramalara hızlı erişim için
|
||||
|
||||
[Gezinme başvurusu →](/l/tr/user-guide/layout/capabilities/navigation)
|
||||
[Gezinme referansı →](/l/tr/user-guide/layout/capabilities/navigation)
|
||||
|
||||
## Görünümler
|
||||
|
||||
@@ -42,4 +42,4 @@ Bir kaydı açtığınızda, ayrıntı sayfası yapılandırılabilir sekmeler v
|
||||
|
||||
Komut menüsünden yerleşim özelleştirme moduna girin (`Cmd+K` → "Kayıt sayfası yerleşimini düzenle").
|
||||
|
||||
[Kayıt sayfaları başvurusu →](/l/tr/user-guide/layout/capabilities/record-pages)
|
||||
[Kayıt sayfaları referansı →](/l/tr/user-guide/layout/capabilities/record-pages)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Commands
|
||||
title: 命令
|
||||
icon: terminal
|
||||
description: Useful commands for developing Twenty.
|
||||
description: 用于开发 Twenty 的实用命令。
|
||||
---
|
||||
|
||||
Commands can be run from the repository root using `npx nx`. Use `npx nx run {project}:{command}` for explicit targeting.
|
||||
可以在存储库根目录使用 `npx nx` 运行命令。 使用 `npx nx run {project}:{command}` 显式指定目标。
|
||||
|
||||
## Starting the App
|
||||
## 启动应用
|
||||
|
||||
```bash
|
||||
npx nx start twenty-front # Frontend dev server (http://localhost:3001)
|
||||
@@ -14,7 +14,7 @@ npx nx start twenty-server # Backend server (http://localhost:3000)
|
||||
npx nx run twenty-server:worker # Background worker
|
||||
```
|
||||
|
||||
## Database
|
||||
## 数据库
|
||||
|
||||
```bash
|
||||
npx nx database:reset twenty-server # Reset and seed database
|
||||
@@ -22,7 +22,7 @@ npx nx run twenty-server:database:migrate:prod # Run migrations
|
||||
npx nx run twenty-server:database:migrate:generate --name <name> --type <fast|slow> # Generate a migration
|
||||
```
|
||||
|
||||
## Linting
|
||||
## 代码检查
|
||||
|
||||
```bash
|
||||
npx nx lint:diff-with-main twenty-front # Lint changed files (fastest)
|
||||
@@ -30,7 +30,7 @@ npx nx lint:diff-with-main twenty-server
|
||||
npx nx lint twenty-front --configuration=fix # Auto-fix
|
||||
```
|
||||
|
||||
## Type Checking
|
||||
## 类型检查
|
||||
|
||||
```bash
|
||||
npx nx typecheck twenty-front
|
||||
@@ -68,7 +68,7 @@ npx nx run twenty-front:lingui:extract # Extract strings
|
||||
npx nx run twenty-front:lingui:compile # Compile translations
|
||||
```
|
||||
|
||||
## Build
|
||||
## 构建
|
||||
|
||||
```bash
|
||||
npx nx build twenty-shared # Must be built first
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
title: 架构
|
||||
description: How Twenty apps work — sandboxing, lifecycle, and the building blocks.
|
||||
description: Twenty 应用如何运作——沙盒化、生命周期与构建模块。
|
||||
icon: sitemap
|
||||
---
|
||||
|
||||
Twenty apps are TypeScript packages that extend your workspace with custom objects, logic, UI components, and AI capabilities. They run on the Twenty platform with full sandboxing and permission controls.
|
||||
Twenty 应用是 TypeScript 包,可通过自定义对象、逻辑、UI 组件和 AI 能力扩展你的工作区。 它们在 Twenty 平台上运行,具备完备的沙盒与权限控制。
|
||||
|
||||
## How apps work
|
||||
## 应用如何运作
|
||||
|
||||
An app is a collection of **entities** declared using `defineEntity()` functions from the `twenty-sdk` package. The SDK detects these declarations via AST analysis at build time and produces a **manifest** — a complete description of what your app adds to a workspace.
|
||||
应用是由 `twenty-sdk` 包中的 `defineEntity()` 函数声明的**实体**集合。 SDK 在构建时通过 AST 分析检测到这些声明,并生成一份**清单**——完整描述你的应用为工作区新增的内容。
|
||||
|
||||
```
|
||||
your-app/
|
||||
@@ -29,32 +29,32 @@ your-app/
|
||||
```
|
||||
|
||||
<Note>
|
||||
**File organization is up to you.** Entity detection is AST-based — the SDK finds `export default defineEntity(...)` calls regardless of where the file lives. The folder structure above is a convention, not a requirement.
|
||||
**文件组织由你决定。** 实体检测基于 AST——无论文件位于何处,SDK 都能找到 `export default defineEntity(...)` 的调用。 上述文件夹结构是一种约定,而非强制要求。
|
||||
</Note>
|
||||
|
||||
## Entity types
|
||||
## 实体类型
|
||||
|
||||
| 实体 | 目的 | 文档 |
|
||||
| ------------------------ | ----------------------------------------- | ------------------------------------------------------------ |
|
||||
| **Application** | App identity, permissions, variables | [Data Model](/l/zh/developers/extend/apps/data-model) |
|
||||
| **Role** | Permission sets for objects and fields | [Data Model](/l/zh/developers/extend/apps/data-model) |
|
||||
| **对象** | Custom data tables with fields | [Data Model](/l/zh/developers/extend/apps/data-model) |
|
||||
| **字段** | Extend existing objects, define relations | [Data Model](/l/zh/developers/extend/apps/data-model) |
|
||||
| **Logic Function** | Server-side TypeScript with triggers | [Logic Functions](/l/zh/developers/extend/apps/logic-functions) |
|
||||
| **Front Component** | Sandboxed React UI in Twenty's page | [Front Components](/l/zh/developers/extend/apps/front-components) |
|
||||
| **Skill** | Reusable AI agent instructions | [Skills & Agents](/l/zh/developers/extend/apps/skills-and-agents) |
|
||||
| **Agent** | AI assistants with custom prompts | [Skills & Agents](/l/zh/developers/extend/apps/skills-and-agents) |
|
||||
| **View** | Pre-configured record list views | [Layout](/l/zh/developers/extend/apps/layout) |
|
||||
| **Navigation Menu Item** | Custom sidebar entries | [Layout](/l/zh/developers/extend/apps/layout) |
|
||||
| **Page Layout** | Custom record page tabs and widgets | [Layout](/l/zh/developers/extend/apps/layout) |
|
||||
| 实体 | 目的 | 文档 |
|
||||
| --------- | ------------------------- | -------------------------------------------------- |
|
||||
| **应用程序** | 应用标识、权限、变量 | [数据模型](/l/zh/developers/extend/apps/data-model) |
|
||||
| **角色** | 对象和字段的权限集 | [数据模型](/l/zh/developers/extend/apps/data-model) |
|
||||
| **对象** | 带字段的自定义数据表 | [数据模型](/l/zh/developers/extend/apps/data-model) |
|
||||
| **字段** | 扩展现有对象,定义关系 | [数据模型](/l/zh/developers/extend/apps/data-model) |
|
||||
| **逻辑函数** | 带触发器的服务端 TypeScript | [逻辑函数](/l/zh/developers/extend/apps/logic-functions) |
|
||||
| **前端组件** | 在 Twenty 页面中的沙盒化 React UI | [前端组件](/l/zh/developers/extend/apps/front-components) |
|
||||
| **技能** | 可复用的 AI 代理指令 | [技能与代理](/l/zh/developers/extend/apps/skills-and-agents) |
|
||||
| **代理** | 具有自定义提示词的 AI 助手 | [技能与代理](/l/zh/developers/extend/apps/skills-and-agents) |
|
||||
| **视图** | 预配置的记录列表视图 | [布局](/l/zh/developers/extend/apps/layout) |
|
||||
| **导航菜单项** | 自定义侧边栏条目 | [布局](/l/zh/developers/extend/apps/layout) |
|
||||
| **页面布局** | 自定义记录页面的选项卡和小部件 | [布局](/l/zh/developers/extend/apps/layout) |
|
||||
|
||||
## Sandboxing
|
||||
## 沙盒化
|
||||
|
||||
* **Logic functions** run in isolated Node.js processes on the server. They only access data through the typed API client, scoped to the app's role permissions.
|
||||
* **Front components** run in Web Workers using Remote DOM — sandboxed from the main page but rendering native DOM elements (not iframes). They communicate with Twenty via a message-passing host API.
|
||||
* **Permissions** are enforced at the API level. The runtime token (`TWENTY_APP_ACCESS_TOKEN`) is derived from the role defined in `defineApplication()`.
|
||||
* **逻辑函数** 在服务器上的独立 Node.js 进程中运行。 它们只能通过类型化的 API 客户端访问数据,且范围受应用角色权限限制。
|
||||
* **前端组件** 在使用 Remote DOM 的 Web Worker 中运行——与主页面沙盒隔离,但渲染原生 DOM 元素(非 iframe)。 它们通过消息传递的宿主 API 与 Twenty 通信。
|
||||
* **权限** 在 API 层面强制执行。 运行时令牌(`TWENTY_APP_ACCESS_TOKEN`)源自 `defineApplication()` 中定义的角色。
|
||||
|
||||
## App lifecycle
|
||||
## 应用生命周期
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
@@ -73,32 +73,32 @@ your-app/
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
* **`yarn twenty dev`** — watches your source files and live-syncs changes to a connected Twenty server. The typed API client is regenerated automatically when the schema changes.
|
||||
* **`yarn twenty build`** — compiles TypeScript, bundles logic functions and front components with esbuild, and produces a manifest.
|
||||
* **Pre/post-install hooks** — optional logic functions that run during installation. See [Logic Functions](/l/zh/developers/extend/apps/logic-functions) for details.
|
||||
* **`yarn twenty dev`** — 监视你的源文件,并将更改实时同步到已连接的 Twenty 服务器。 当模式发生变化时,会自动重新生成类型化的 API 客户端。
|
||||
* **`yarn twenty build`** — 编译 TypeScript,使用 esbuild 打包逻辑函数和前端组件,并生成清单。
|
||||
* **预/后安装钩子** — 在安装过程中运行的可选逻辑函数。 详情请参见[逻辑函数](/l/zh/developers/extend/apps/logic-functions)。
|
||||
|
||||
## Next steps
|
||||
## 后续步骤
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="数据模型" icon="database" href="/l/zh/developers/extend/apps/data-model">
|
||||
Define objects, fields, roles, and relations.
|
||||
定义对象、字段、角色和关系。
|
||||
</Card>
|
||||
<Card title="逻辑函数" icon="bolt" href="/l/zh/developers/extend/apps/logic-functions">
|
||||
Server-side functions with HTTP, cron, and event triggers.
|
||||
具有 HTTP、cron 和事件触发器的服务端函数。
|
||||
</Card>
|
||||
<Card title="前端组件" icon="window-maximize" href="/l/zh/developers/extend/apps/front-components">
|
||||
Sandboxed React components inside Twenty's UI.
|
||||
Twenty 的 UI 中的沙盒化 React 组件。
|
||||
</Card>
|
||||
<Card title="布局" icon="table-columns" href="/l/zh/developers/extend/apps/layout">
|
||||
Views, navigation items, and record page layouts.
|
||||
视图、导航菜单项和记录页面布局。
|
||||
</Card>
|
||||
<Card title="技能与智能体" icon="robot" href="/l/zh/developers/extend/apps/skills-and-agents">
|
||||
AI skills and agents with custom prompts.
|
||||
具有自定义提示词的 AI 技能与代理。
|
||||
</Card>
|
||||
<Card title="CLI & Testing" icon="terminal" href="/l/zh/developers/extend/apps/cli-and-testing">
|
||||
CLI commands, testing, assets, remotes, and CI.
|
||||
<Card title="CLI 与测试" icon="terminal" href="/l/zh/developers/extend/apps/cli-and-testing">
|
||||
CLI 命令、测试、资源、远程和 CI。
|
||||
</Card>
|
||||
<Card title="发布" icon="rocket" href="/l/zh/developers/extend/apps/publishing">
|
||||
Deploy to a server or publish to the marketplace.
|
||||
部署到服务器或发布到应用市场。
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 技能与智能体
|
||||
description: Define AI skills and agents for your app.
|
||||
description: 为你的应用定义 AI 技能和智能体。
|
||||
icon: robot
|
||||
---
|
||||
|
||||
@@ -8,7 +8,7 @@ icon: robot
|
||||
Skills and agents are currently in alpha. 该功能可用,但仍在演进中。
|
||||
</Warning>
|
||||
|
||||
Apps can define AI capabilities that live inside the workspace — reusable skill instructions and agents with custom system prompts.
|
||||
应用可以定义存在于工作区内的 AI 能力——可复用的技能指令以及具有自定义系统提示词的智能体。
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineSkill" description="定义 AI 智能体技能">
|
||||
@@ -40,9 +40,9 @@ export default defineSkill({
|
||||
* `description`(可选)提供有关技能用途的更多上下文。
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineAgent" description="Define AI agents with custom prompts">
|
||||
<Accordion title="defineAgent" description="使用自定义提示词定义 AI 智能体">
|
||||
|
||||
Agents are AI assistants that live inside your workspace. Use `defineAgent()` to create agents with a custom system prompt:
|
||||
智能体是在你的工作区内驻留的 AI 助手。 使用 `defineAgent()` 来创建带有自定义系统提示词的智能体:
|
||||
|
||||
```ts src/agents/example-agent.ts
|
||||
import { defineAgent } from 'twenty-sdk/define';
|
||||
@@ -58,12 +58,12 @@ export default defineAgent({
|
||||
```
|
||||
|
||||
关键点:
|
||||
* `name` is the unique identifier string for the agent (kebab-case recommended).
|
||||
* `label` is the display name shown in the UI.
|
||||
* `prompt` is the system prompt that defines the agent's behavior.
|
||||
* `description` (optional) provides context about what the agent does.
|
||||
* `name` 是该智能体的唯一标识字符串(推荐使用 kebab-case)。
|
||||
* `label` 是在 UI 中显示的名称。
|
||||
* `prompt` 是定义智能体行为的系统提示词。
|
||||
* `description`(可选)提供有关智能体功能的上下文。
|
||||
* `icon`(可选)设置在 UI 中显示的图标。
|
||||
* `modelId` (optional) overrides the default AI model used by the agent.
|
||||
* `modelId`(可选)会覆盖该智能体使用的默认 AI 模型。
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
---
|
||||
title: OAuth
|
||||
icon: 键
|
||||
description: Authorization code flow with PKCE and client credentials for server-to-server access.
|
||||
description: 采用 PKCE 的授权码流程和用于服务器到服务器访问的客户端凭证。
|
||||
---
|
||||
|
||||
Twenty implements OAuth 2.0 with authorization code + PKCE for user-facing apps and client credentials for server-to-server access. Clients are registered dynamically via [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) — no manual setup in a dashboard.
|
||||
Twenty 对面向用户的应用采用授权码 + PKCE 实现 OAuth 2.0,对服务器到服务器访问采用客户端凭证。 客户端通过 [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) 动态注册——无需在仪表板中手动设置。
|
||||
|
||||
## When to Use OAuth
|
||||
## 何时使用 OAuth
|
||||
|
||||
| 场景 | Auth Method |
|
||||
| --------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| Internal scripts, automation | [API Key](/l/zh/developers/extend/api#authentication) |
|
||||
| External app acting on behalf of a user | **OAuth — Authorization Code** |
|
||||
| Server-to-server, no user context | **OAuth — Client Credentials** |
|
||||
| Twenty App with UI extensions | [Apps](/l/zh/developers/extend/apps/getting-started) (OAuth is handled automatically) |
|
||||
| 场景 | 认证方式 |
|
||||
| ------------------- | ----------------------------------------------------------- |
|
||||
| 内部脚本、自动化 | [API 密钥](/l/zh/developers/extend/api#authentication) |
|
||||
| 代表用户执行操作的外部应用 | **OAuth — 授权码** |
|
||||
| 服务器到服务器,无用户上下文 | **OAuth — 客户端凭证** |
|
||||
| 带有 UI 扩展的 Twenty 应用 | [应用](/l/zh/developers/extend/apps/getting-started) (OAuth 将自动处理) |
|
||||
|
||||
## Register a Client
|
||||
## 注册客户端
|
||||
|
||||
Twenty supports **dynamic client registration** per [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). No manual setup needed — register programmatically:
|
||||
根据 [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591),Twenty 支持**动态客户端注册**。 无需手动设置——以编程方式注册:
|
||||
|
||||
```bash
|
||||
POST /oauth/register
|
||||
@@ -31,7 +31,7 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -43,23 +43,23 @@ Content-Type: application/json
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Store the `client_secret` securely — it cannot be retrieved later.
|
||||
安全存储 `client_secret`——之后无法再检索。
|
||||
</Warning>
|
||||
|
||||
## 范围
|
||||
|
||||
| Scope | 访问 |
|
||||
| ------ | ---------------------------------------------------- |
|
||||
| `api` | Full read/write access to the Core and Metadata APIs |
|
||||
| `个人资料` | Read the authenticated user's profile information |
|
||||
| 范围 | 访问 |
|
||||
| ------ | ------------------------------ |
|
||||
| `api` | 对 Core 和 Metadata API 的完全读/写访问 |
|
||||
| `个人资料` | 读取已认证用户的个人资料信息 |
|
||||
|
||||
Request scopes as a space-separated string: `scope=api profile`
|
||||
以空格分隔的字符串请求范围:`scope=api profile`
|
||||
|
||||
## Authorization Code Flow
|
||||
## 授权码流程
|
||||
|
||||
Use this flow when your app acts on behalf of a Twenty user.
|
||||
当你的应用代表某个 Twenty 用户执行操作时,请使用此流程。
|
||||
|
||||
### 1. Redirect the user to authorize
|
||||
### 1. 重定向用户以进行授权
|
||||
|
||||
```
|
||||
GET /oauth/authorize?
|
||||
@@ -72,29 +72,29 @@ GET /oauth/authorize?
|
||||
code_challenge_method=S256
|
||||
```
|
||||
|
||||
| 参数 | 必填 | 描述 |
|
||||
| ----------------------- | -- | ------------------------------------------------------------ |
|
||||
| `client_id` | 是 | Your registered client ID |
|
||||
| `response_type` | 是 | Must be `code` |
|
||||
| `redirect_uri` | 是 | Must match a registered redirect URI |
|
||||
| `scope` | 否 | Space-separated scopes (defaults to `api`) |
|
||||
| `状态` | 推荐 | Random string to prevent CSRF attacks |
|
||||
| `code_challenge` | 推荐 | PKCE challenge (SHA-256 hash of verifier, base64url-encoded) |
|
||||
| `code_challenge_method` | 推荐 | Must be `S256` when using PKCE |
|
||||
| 参数 | 必填 | 描述 |
|
||||
| ----------------------- | -- | ------------------------------------- |
|
||||
| `client_id` | 是 | 你已注册的客户端 ID |
|
||||
| `response_type` | 是 | 必须为 `code` |
|
||||
| `redirect_uri` | 是 | 必须与已注册的重定向 URI 匹配 |
|
||||
| `scope` | 否 | 以空格分隔的范围(默认为 `api`) |
|
||||
| `状态` | 推荐 | 用于防止 CSRF 攻击的随机字符串 |
|
||||
| `code_challenge` | 推荐 | PKCE 质询(验证器的 SHA-256 哈希,base64url 编码) |
|
||||
| `code_challenge_method` | 推荐 | 使用 PKCE 时必须为 `S256` |
|
||||
|
||||
The user sees a consent screen and approves or denies access.
|
||||
用户将看到授权同意界面,并同意或拒绝访问。
|
||||
|
||||
### 2. Handle the callback
|
||||
### 2. 处理回调
|
||||
|
||||
After authorization, Twenty redirects back to your `redirect_uri`:
|
||||
授权后,Twenty 会重定向回你的 `redirect_uri`:
|
||||
|
||||
```
|
||||
https://myapp.com/callback?code=AUTH_CODE&state=random_state_value
|
||||
```
|
||||
|
||||
Verify that `state` matches what you sent.
|
||||
验证 `state` 与你发送的值一致。
|
||||
|
||||
### 3. Exchange the code for tokens
|
||||
### 3. 将授权码交换为令牌
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -108,7 +108,7 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
code_verifier=YOUR_PKCE_VERIFIER
|
||||
```
|
||||
|
||||
**Response:**
|
||||
**响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -119,14 +119,14 @@ code_verifier=YOUR_PKCE_VERIFIER
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Use the access token
|
||||
### 4. 使用访问令牌
|
||||
|
||||
```bash
|
||||
GET /rest/companies
|
||||
Authorization: Bearer ACCESS_TOKEN
|
||||
```
|
||||
|
||||
### 5. Refresh when expired
|
||||
### 5. 过期时刷新
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -138,9 +138,9 @@ client_id=YOUR_CLIENT_ID&
|
||||
client_secret=YOUR_CLIENT_SECRET
|
||||
```
|
||||
|
||||
## Client Credentials Flow
|
||||
## 客户端凭证流程
|
||||
|
||||
For server-to-server integrations with no user interaction:
|
||||
适用于无用户交互的服务器到服务器集成:
|
||||
|
||||
```bash
|
||||
POST /oauth/token
|
||||
@@ -152,38 +152,38 @@ client_secret=YOUR_CLIENT_SECRET&
|
||||
scope=api
|
||||
```
|
||||
|
||||
The returned token has workspace-level access, not tied to any specific user.
|
||||
返回的令牌具有工作区级访问权限,不绑定到任何特定用户。
|
||||
|
||||
## Server Discovery
|
||||
## 服务器发现
|
||||
|
||||
Twenty publishes its OAuth configuration at a standard discovery endpoint:
|
||||
Twenty 在标准发现端点发布其 OAuth 配置:
|
||||
|
||||
```
|
||||
GET /.well-known/oauth-authorization-server
|
||||
```
|
||||
|
||||
This returns all endpoints, supported grant types, scopes, and capabilities — useful for building generic OAuth clients.
|
||||
这将返回所有端点、支持的授权类型、范围和功能——有助于构建通用的 OAuth 客户端。
|
||||
|
||||
## API Endpoints Summary
|
||||
## API 端点概览
|
||||
|
||||
| 端点 | 目的 |
|
||||
| ----------------------------------------- | --------------------------- |
|
||||
| `/.well-known/oauth-authorization-server` | Server metadata discovery |
|
||||
| `/oauth/register` | Dynamic client registration |
|
||||
| `/oauth/authorize` | User authorization |
|
||||
| `/oauth/token` | Token exchange and refresh |
|
||||
| 端点 | 目的 |
|
||||
| ----------------------------------------- | -------- |
|
||||
| `/.well-known/oauth-authorization-server` | 服务器元数据发现 |
|
||||
| `/oauth/register` | 动态客户端注册 |
|
||||
| `/oauth/authorize` | 用户授权 |
|
||||
| `/oauth/token` | 令牌交换与刷新 |
|
||||
|
||||
| 环境 | 基础 URL |
|
||||
| ------- | ------------------------ |
|
||||
| **云端** | `https://api.twenty.com` |
|
||||
| **自托管** | `https://{your-domain}` |
|
||||
|
||||
## OAuth vs API Keys
|
||||
## OAuth 与 API 密钥对比
|
||||
|
||||
| | API 密钥 | OAuth |
|
||||
| ------------------ | ----------------------- | -------------------------------------- |
|
||||
| **Setup** | Generate in Settings | Register a client, implement flow |
|
||||
| **User context** | None (workspace-level) | Specific user's permissions |
|
||||
| **Best for** | Scripts, internal tools | External apps, multi-user integrations |
|
||||
| **Token rotation** | 手动 | Automatic via refresh tokens |
|
||||
| **Scoped access** | Full API access | Granular via scopes |
|
||||
| | API 密钥 | OAuth |
|
||||
| ----------- | ---------- | ----------- |
|
||||
| **设置** | 在设置中生成 | 注册客户端并实现流程 |
|
||||
| **用户上下文** | 无(工作区级) | 特定用户的权限 |
|
||||
| **最适合** | 脚本、内部工具 | 外部应用、多用户集成 |
|
||||
| **令牌轮换** | 手动 | 通过刷新令牌自动完成 |
|
||||
| **范围限定的访问** | 完整的 API 访问 | 通过范围实现细粒度控制 |
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Webhooks
|
||||
icon: satellite-dish
|
||||
description: Get notified when records change — HTTP POST to your endpoint on every create, update, or delete.
|
||||
description: 当记录更改时收到通知 — 在每次创建、更新或删除时向您的端点发送 HTTP POST。
|
||||
---
|
||||
|
||||
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
|
||||
|
||||
Twenty sends an HTTP POST to your URL whenever a record is created, updated, or deleted. All object types are covered, including custom objects.
|
||||
每当记录被创建、更新或删除时,Twenty 会向您的 URL 发送 HTTP POST。 涵盖所有对象类型,包括自定义对象。
|
||||
|
||||
## 创建 Webhook
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ const jestConfig = {
|
||||
extensionsToTreatAsEsm: ['.ts', '.tsx'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
statements: 48,
|
||||
statements: 47.9,
|
||||
lines: 46,
|
||||
functions: 39.5,
|
||||
},
|
||||
|
||||
+9
-3
@@ -1,4 +1,5 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { NavigationMenuItemType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -42,11 +43,13 @@ export const useNavigationMenuItemFolderOpenState = ({
|
||||
lastClickedNavigationMenuItemIdState,
|
||||
);
|
||||
|
||||
const [isManuallyClosed, setIsManuallyClosed] = useState(false);
|
||||
|
||||
const isExplicitlyOpen = openNavigationMenuItemFolderIds.includes(folderId);
|
||||
const hasActiveChild = folderChildrenNavigationMenuItems.some((item) =>
|
||||
activeNavigationMenuItemIds.includes(item.id),
|
||||
);
|
||||
const isOpen = isExplicitlyOpen || hasActiveChild;
|
||||
const isOpen = isExplicitlyOpen || (hasActiveChild && !isManuallyClosed);
|
||||
|
||||
const handleToggle = () => {
|
||||
if (isMobile) {
|
||||
@@ -55,10 +58,13 @@ export const useNavigationMenuItemFolderOpenState = ({
|
||||
);
|
||||
} else {
|
||||
setOpenNavigationMenuItemFolderIds((current) =>
|
||||
current.includes(folderId)
|
||||
isOpen
|
||||
? current.filter((id) => id !== folderId)
|
||||
: [...current, folderId],
|
||||
: current.includes(folderId)
|
||||
? current
|
||||
: [...current, folderId],
|
||||
);
|
||||
setIsManuallyClosed(isOpen);
|
||||
}
|
||||
|
||||
if (!isOpen) {
|
||||
|
||||
+3
-2
@@ -12,9 +12,7 @@ import { type SpreadsheetColumns } from '@/spreadsheet-import/types/SpreadsheetC
|
||||
import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType';
|
||||
import { addErrorsAndRunHooks } from '@/spreadsheet-import/utils/dataMutations';
|
||||
import { useDialogManager } from '@/ui/feedback/dialog-manager/hooks/useDialogManager';
|
||||
import { ModalContent } from 'twenty-ui/layout';
|
||||
import { styled } from '@linaria/react';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import {
|
||||
type Dispatch,
|
||||
@@ -23,6 +21,8 @@ import {
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { ModalContent } from 'twenty-ui/layout';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
// @ts-expect-error Todo: remove usage of react-data-grid`
|
||||
import { type RowsChangeData } from 'react-data-grid';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -80,6 +80,7 @@ const StyledScrollContainer = styled.div`
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
height: 0px;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
|
||||
+8
-1
@@ -1,11 +1,18 @@
|
||||
import { useStore } from 'jotai';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { isSelectableListGridFocusedState } from '@/ui/layout/selectable-list/states/isSelectableListGridFocusedState';
|
||||
|
||||
export const useInputFocusWithoutScrollOnMount = () => {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const store = useStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (isDefined(inputRef.current)) {
|
||||
if (
|
||||
isDefined(inputRef.current) &&
|
||||
!store.get(isSelectableListGridFocusedState.atom)
|
||||
) {
|
||||
inputRef.current.focus({ preventScroll: true });
|
||||
}
|
||||
});
|
||||
|
||||
+9
@@ -1,8 +1,10 @@
|
||||
import { useStore } from 'jotai';
|
||||
import { type ReactNode, useEffect } from 'react';
|
||||
|
||||
import { useSelectableListHotKeys } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListHotKeys';
|
||||
import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
|
||||
import { SelectableListContextProvider } from '@/ui/layout/selectable-list/states/contexts/SelectableListContext';
|
||||
import { isSelectableListGridFocusedState } from '@/ui/layout/selectable-list/states/isSelectableListGridFocusedState';
|
||||
import { selectableItemIdsComponentState } from '@/ui/layout/selectable-list/states/selectableItemIdsComponentState';
|
||||
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -27,6 +29,7 @@ export const SelectableList = ({
|
||||
}: SelectableListProps) => {
|
||||
useSelectableListHotKeys(selectableListInstanceId, focusId, onSelect);
|
||||
|
||||
const store = useStore();
|
||||
const setSelectableItemIds = useSetAtomComponentState(
|
||||
selectableItemIdsComponentState,
|
||||
selectableListInstanceId,
|
||||
@@ -48,6 +51,12 @@ export const SelectableList = ({
|
||||
}
|
||||
}, [selectableItemIdArray, selectableItemIdMatrix, setSelectableItemIds]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
store.set(isSelectableListGridFocusedState.atom, false);
|
||||
};
|
||||
}, [store]);
|
||||
|
||||
return (
|
||||
<SelectableListComponentInstanceContext.Provider
|
||||
value={{
|
||||
|
||||
+86
-8
@@ -1,11 +1,12 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useCallback } from 'react';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { isSelectableListGridFocusedState } from '@/ui/layout/selectable-list/states/isSelectableListGridFocusedState';
|
||||
import { isSelectedItemIdComponentFamilyState } from '@/ui/layout/selectable-list/states/isSelectedItemIdComponentFamilyState';
|
||||
import { selectableItemIdsComponentState } from '@/ui/layout/selectable-list/states/selectableItemIdsComponentState';
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
import { isSelectedItemIdComponentFamilyState } from '@/ui/layout/selectable-list/states/isSelectedItemIdComponentFamilyState';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
|
||||
type Direction = 'up' | 'down' | 'left' | 'right';
|
||||
@@ -15,6 +16,41 @@ export const useSelectableListHotKeys = (
|
||||
focusId: string,
|
||||
onSelect?: (itemId: string) => void,
|
||||
) => {
|
||||
// oxlint-disable-next-line twenty/no-state-useref
|
||||
const lastBlurredInputRef = useRef<HTMLInputElement | null>(null);
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const blurActiveInputIfNeeded = () => {
|
||||
if (document.activeElement instanceof HTMLInputElement) {
|
||||
lastBlurredInputRef.current = document.activeElement;
|
||||
store.set(isSelectableListGridFocusedState.atom, true);
|
||||
document.activeElement.blur();
|
||||
}
|
||||
};
|
||||
|
||||
const refocusBlurredInput = () => {
|
||||
if (!lastBlurredInputRef.current) {
|
||||
return;
|
||||
}
|
||||
store.set(isSelectableListGridFocusedState.atom, false);
|
||||
lastBlurredInputRef.current.focus();
|
||||
lastBlurredInputRef.current = null;
|
||||
};
|
||||
|
||||
const clearSelection = (selectedItemId: string | null) => {
|
||||
if (isNonEmptyString(selectedItemId)) {
|
||||
store.set(selectedItemIdComponentState.atomFamily({ instanceId }), null);
|
||||
store.set(
|
||||
isSelectedItemIdComponentFamilyState.atomFamily({
|
||||
instanceId,
|
||||
familyKey: selectedItemId,
|
||||
}),
|
||||
false,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const findPosition = (
|
||||
selectableItemIds: string[][],
|
||||
selectedItemId?: string | null,
|
||||
@@ -31,8 +67,6 @@ export const useSelectableListHotKeys = (
|
||||
}
|
||||
};
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const handleSelect = useCallback(
|
||||
(direction: Direction) => {
|
||||
const selectedItemId = store.get(
|
||||
@@ -138,16 +172,58 @@ export const useSelectableListHotKeys = (
|
||||
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: Key.ArrowUp,
|
||||
callback: () => handleSelect('up'),
|
||||
callback: () => {
|
||||
blurActiveInputIfNeeded();
|
||||
|
||||
const selectedItemId = store.get(
|
||||
selectedItemIdComponentState.atomFamily({ instanceId }),
|
||||
);
|
||||
const selectableItemIds = store.get(
|
||||
selectableItemIdsComponentState.atomFamily({ instanceId }),
|
||||
);
|
||||
const position = findPosition(selectableItemIds, selectedItemId);
|
||||
const isAtTop = position !== undefined && position.row === 0;
|
||||
|
||||
if (!isAtTop || !lastBlurredInputRef.current) {
|
||||
handleSelect('up');
|
||||
return;
|
||||
}
|
||||
|
||||
clearSelection(selectedItemId);
|
||||
refocusBlurredInput();
|
||||
},
|
||||
focusId,
|
||||
dependencies: [handleSelect, store, instanceId],
|
||||
});
|
||||
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: Key.ArrowDown,
|
||||
callback: () => {
|
||||
blurActiveInputIfNeeded();
|
||||
handleSelect('down');
|
||||
},
|
||||
focusId,
|
||||
dependencies: [handleSelect],
|
||||
});
|
||||
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: Key.ArrowDown,
|
||||
callback: () => handleSelect('down'),
|
||||
keys: '*',
|
||||
callback: (keyboardEvent) => {
|
||||
if (keyboardEvent.key.length !== 1) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
keyboardEvent.metaKey ||
|
||||
keyboardEvent.ctrlKey ||
|
||||
keyboardEvent.altKey
|
||||
) {
|
||||
return;
|
||||
}
|
||||
refocusBlurredInput();
|
||||
},
|
||||
focusId,
|
||||
dependencies: [handleSelect],
|
||||
dependencies: [],
|
||||
options: { enableOnFormTags: false, preventDefault: false },
|
||||
});
|
||||
|
||||
useHotkeysOnFocusedElement({
|
||||
@@ -155,6 +231,7 @@ export const useSelectableListHotKeys = (
|
||||
callback: () => handleSelect('left'),
|
||||
focusId,
|
||||
dependencies: [handleSelect],
|
||||
options: { enableOnFormTags: false },
|
||||
});
|
||||
|
||||
useHotkeysOnFocusedElement({
|
||||
@@ -162,5 +239,6 @@ export const useSelectableListHotKeys = (
|
||||
callback: () => handleSelect('right'),
|
||||
focusId,
|
||||
dependencies: [handleSelect],
|
||||
options: { enableOnFormTags: false },
|
||||
});
|
||||
};
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
|
||||
|
||||
export const isSelectableListGridFocusedState = createAtomState<boolean>({
|
||||
key: 'isSelectableListGridFocusedState',
|
||||
defaultValue: false,
|
||||
});
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { getDefaultObjectFields } from '@/cli/utilities/build/manifest/utils/get-default-object-fields';
|
||||
import { generateDefaultFieldUniversalIdentifier } from '@/cli/utilities/build/manifest/utils/generate-default-field-universal-identifier';
|
||||
import { generateDefaultFieldUniversalIdentifier } from '@/sdk/define/objects/generate-default-field-universal-identifier';
|
||||
import type { ObjectConfig } from '@/sdk/define/objects/object-config';
|
||||
|
||||
const mockObjectConfig: ObjectConfig = {
|
||||
@@ -14,7 +14,7 @@ const mockObjectConfig: ObjectConfig = {
|
||||
|
||||
const expectedUniversalId = (fieldName: string) =>
|
||||
generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig: mockObjectConfig,
|
||||
objectUniversalIdentifier: mockObjectConfig.universalIdentifier,
|
||||
fieldName,
|
||||
});
|
||||
|
||||
|
||||
+12
-10
@@ -1,11 +1,13 @@
|
||||
import type { ObjectConfig } from '@/sdk/define/objects/object-config';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { generateDefaultFieldUniversalIdentifier } from '@/cli/utilities/build/manifest/utils/generate-default-field-universal-identifier';
|
||||
import { generateDefaultFieldUniversalIdentifier } from '@/sdk/define/objects/generate-default-field-universal-identifier';
|
||||
import { type ObjectFieldManifest } from 'twenty-shared/application';
|
||||
|
||||
export const getDefaultObjectFields = (
|
||||
objectConfig: ObjectConfig,
|
||||
): ObjectFieldManifest[] => {
|
||||
const objectUniversalIdentifier = objectConfig.universalIdentifier;
|
||||
|
||||
const idField: ObjectFieldManifest = {
|
||||
name: 'id',
|
||||
label: 'Id',
|
||||
@@ -15,7 +17,7 @@ export const getDefaultObjectFields = (
|
||||
defaultValue: 'uuid',
|
||||
type: FieldMetadataType.UUID as const,
|
||||
universalIdentifier: generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier,
|
||||
fieldName: 'id',
|
||||
}),
|
||||
};
|
||||
@@ -29,7 +31,7 @@ export const getDefaultObjectFields = (
|
||||
defaultValue: null,
|
||||
type: FieldMetadataType.TEXT as const,
|
||||
universalIdentifier: generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier,
|
||||
fieldName: 'name',
|
||||
}),
|
||||
};
|
||||
@@ -43,7 +45,7 @@ export const getDefaultObjectFields = (
|
||||
defaultValue: 'now',
|
||||
type: FieldMetadataType.DATE_TIME as const,
|
||||
universalIdentifier: generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier,
|
||||
fieldName: 'createdAt',
|
||||
}),
|
||||
};
|
||||
@@ -57,7 +59,7 @@ export const getDefaultObjectFields = (
|
||||
defaultValue: 'now',
|
||||
type: FieldMetadataType.DATE_TIME as const,
|
||||
universalIdentifier: generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier,
|
||||
fieldName: 'updatedAt',
|
||||
}),
|
||||
};
|
||||
@@ -71,7 +73,7 @@ export const getDefaultObjectFields = (
|
||||
defaultValue: null,
|
||||
type: FieldMetadataType.DATE_TIME as const,
|
||||
universalIdentifier: generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier,
|
||||
fieldName: 'deletedAt',
|
||||
}),
|
||||
};
|
||||
@@ -85,7 +87,7 @@ export const getDefaultObjectFields = (
|
||||
defaultValue: { name: "''", source: "'MANUAL'" },
|
||||
type: FieldMetadataType.ACTOR as const,
|
||||
universalIdentifier: generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier,
|
||||
fieldName: 'createdBy',
|
||||
}),
|
||||
};
|
||||
@@ -99,7 +101,7 @@ export const getDefaultObjectFields = (
|
||||
defaultValue: { name: "''", source: "'MANUAL'" },
|
||||
type: FieldMetadataType.ACTOR as const,
|
||||
universalIdentifier: generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier,
|
||||
fieldName: 'updatedBy',
|
||||
}),
|
||||
};
|
||||
@@ -113,7 +115,7 @@ export const getDefaultObjectFields = (
|
||||
defaultValue: 0,
|
||||
type: FieldMetadataType.POSITION,
|
||||
universalIdentifier: generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier,
|
||||
fieldName: 'position',
|
||||
}),
|
||||
};
|
||||
@@ -127,7 +129,7 @@ export const getDefaultObjectFields = (
|
||||
defaultValue: null,
|
||||
type: FieldMetadataType.TS_VECTOR,
|
||||
universalIdentifier: generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier,
|
||||
fieldName: 'searchVector',
|
||||
}),
|
||||
};
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
import { generateDefaultFieldUniversalIdentifier } from '@/cli/utilities/build/manifest/utils/generate-default-field-universal-identifier';
|
||||
import { generateDefaultFieldUniversalIdentifier } from '@/sdk/define/objects/generate-default-field-universal-identifier';
|
||||
import { RelationType } from '@/sdk/define';
|
||||
import type { ObjectConfig } from '@/sdk/define/objects/object-config';
|
||||
import {
|
||||
@@ -130,13 +130,13 @@ export const getDefaultRelationObjectFields = (
|
||||
|
||||
const forwardFieldUniversalIdentifier =
|
||||
generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier: objectConfig.universalIdentifier,
|
||||
fieldName: config.fieldName,
|
||||
});
|
||||
|
||||
const reverseFieldUniversalIdentifier =
|
||||
generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier: objectConfig.universalIdentifier,
|
||||
fieldName: `${config.fieldName}Inverse`,
|
||||
});
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ export type { InputJsonSchema } from 'twenty-shared/logic-function';
|
||||
export { defineNavigationMenuItem } from '@/sdk/define/navigation-menu-items/define-navigation-menu-item';
|
||||
|
||||
export { defineObject } from '@/sdk/define/objects/define-object';
|
||||
export { generateDefaultFieldUniversalIdentifier } from '@/sdk/define/objects/generate-default-field-universal-identifier';
|
||||
export {
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS as STANDARD_OBJECT,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
|
||||
+5
-8
@@ -1,23 +1,20 @@
|
||||
import { generateDefaultFieldUniversalIdentifier } from '@/cli/utilities/build/manifest/utils/generate-default-field-universal-identifier';
|
||||
import { type ObjectConfig } from '@/sdk/define/objects/object-config';
|
||||
import { generateDefaultFieldUniversalIdentifier } from '@/sdk/define/objects/generate-default-field-universal-identifier';
|
||||
|
||||
describe('generateDefaultFieldUniversalIdentifier', () => {
|
||||
it('should generate a unique universal identifier', () => {
|
||||
const objectConfig = {
|
||||
universalIdentifier: '55b79f88-4094-4b3f-a0ac-1a91a55714f2',
|
||||
} as ObjectConfig;
|
||||
const objectUniversalIdentifier = '55b79f88-4094-4b3f-a0ac-1a91a55714f2';
|
||||
|
||||
const uId1 = generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier,
|
||||
fieldName: 'id',
|
||||
});
|
||||
const uId2 = generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier,
|
||||
fieldName: 'id',
|
||||
});
|
||||
|
||||
const anotherUId = generateDefaultFieldUniversalIdentifier({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier,
|
||||
fieldName: 'name',
|
||||
});
|
||||
|
||||
+3
-4
@@ -1,16 +1,15 @@
|
||||
import type { ObjectConfig } from '@/sdk/define/objects/object-config';
|
||||
import { v5 } from 'uuid';
|
||||
|
||||
const UNIVERSAL_IDENTIFIER_NAMESPACE = '142046f0-4d80-48b5-ad56-26ad410e895c';
|
||||
|
||||
export const generateDefaultFieldUniversalIdentifier = ({
|
||||
objectConfig,
|
||||
objectUniversalIdentifier,
|
||||
fieldName,
|
||||
}: {
|
||||
objectConfig: ObjectConfig;
|
||||
objectUniversalIdentifier: string;
|
||||
fieldName: string;
|
||||
}) => {
|
||||
const seed = `${objectConfig.universalIdentifier}-${fieldName}`;
|
||||
const seed = `${objectUniversalIdentifier}-${fieldName}`;
|
||||
|
||||
return v5(seed, UNIVERSAL_IDENTIFIER_NAMESPACE);
|
||||
};
|
||||
@@ -16,6 +16,10 @@ import { GenerateApiKeyCommand } from 'src/engine/core-modules/api-key/commands/
|
||||
import { MarketplaceModule } from 'src/engine/core-modules/application/application-marketplace/marketplace.module';
|
||||
import { StaleRegistrationCleanupModule } from 'src/engine/core-modules/application/application-oauth/stale-registration-cleanup/stale-registration-cleanup.module';
|
||||
import { ApplicationUpgradeModule } from 'src/engine/core-modules/application/application-upgrade/application-upgrade.module';
|
||||
import { RebuildApplicationDefaultDepsCommand } from 'src/database/commands/rebuild-application-default-deps.command';
|
||||
import { WorkspaceIteratorModule } from 'src/database/commands/command-runners/workspace-iterator.module';
|
||||
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
import { EnforceUsageCapCronCommand } from 'src/engine/core-modules/billing/crons/commands/enforce-usage-cap.cron.command';
|
||||
import { EnterpriseKeyValidationCronCommand } from 'src/engine/core-modules/enterprise/cron/command/enterprise-key-validation.cron.command';
|
||||
import { EnterpriseModule } from 'src/engine/core-modules/enterprise/enterprise.module';
|
||||
@@ -73,6 +77,9 @@ import { AutomatedTriggerModule } from 'src/modules/workflow/workflow-trigger/au
|
||||
MarketplaceModule,
|
||||
ApplicationUpgradeModule,
|
||||
StaleRegistrationCleanupModule,
|
||||
WorkspaceIteratorModule,
|
||||
ApplicationModule,
|
||||
WorkspaceCacheModule,
|
||||
WorkspaceVersionModule,
|
||||
UpgradeModule,
|
||||
],
|
||||
@@ -88,6 +95,7 @@ import { AutomatedTriggerModule } from 'src/modules/workflow/workflow-trigger/au
|
||||
GenerateApiKeyCommand,
|
||||
EnforceUsageCapCronCommand,
|
||||
UpgradeStatusCommand,
|
||||
RebuildApplicationDefaultDepsCommand,
|
||||
],
|
||||
})
|
||||
export class DatabaseCommandModule {}
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
import chalk from 'chalk';
|
||||
import { Command, CommandRunner, Option } from 'nest-commander';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
|
||||
import { CommandLogger } from 'src/database/commands/logger';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
|
||||
type RebuildDefaultPackageFilesCommandOptions = {
|
||||
workspaceId?: Set<string>;
|
||||
};
|
||||
|
||||
@Command({
|
||||
name: 'application:rebuild-default-deps',
|
||||
description:
|
||||
'Re-upload default package.json and yarn.lock to file storage for all applications in the workspace',
|
||||
})
|
||||
export class RebuildApplicationDefaultDepsCommand extends CommandRunner {
|
||||
protected logger: CommandLogger;
|
||||
|
||||
constructor(
|
||||
private readonly workspaceIteratorService: WorkspaceIteratorService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
) {
|
||||
super();
|
||||
this.logger = new CommandLogger({
|
||||
verbose: false,
|
||||
constructorName: this.constructor.name,
|
||||
});
|
||||
}
|
||||
|
||||
@Option({
|
||||
flags: '-w, --workspace-id [workspace_id]',
|
||||
description:
|
||||
'workspace id. Command runs on all active/suspended workspaces if not provided.',
|
||||
required: false,
|
||||
})
|
||||
parseWorkspaceId(val: string, previous?: Set<string>): Set<string> {
|
||||
const accumulator = previous ?? new Set<string>();
|
||||
|
||||
accumulator.add(val);
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
override async run(
|
||||
_passedParams: string[],
|
||||
options: RebuildDefaultPackageFilesCommandOptions,
|
||||
): Promise<void> {
|
||||
const workspaceIds = isDefined(options.workspaceId)
|
||||
? Array.from(options.workspaceId)
|
||||
: undefined;
|
||||
const report = await this.workspaceIteratorService.iterate({
|
||||
workspaceIds,
|
||||
callback: async ({ workspaceId }) => {
|
||||
const { flatApplicationMaps } =
|
||||
await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatApplicationMaps',
|
||||
]);
|
||||
|
||||
const applications = Object.values(flatApplicationMaps.byId).filter(
|
||||
(application): application is FlatApplication =>
|
||||
isDefined(application) && !isDefined(application.deletedAt),
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
`Found ${applications.length} application(s) in workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
for (const application of applications) {
|
||||
await this.applicationService.uploadDefaultPackageFilesAndSetFileIds({
|
||||
id: application.id,
|
||||
universalIdentifier: application.universalIdentifier,
|
||||
workspaceId,
|
||||
});
|
||||
this.logger.log(
|
||||
`Rebuilt default package files for application "${application.name}" (${application.id})`,
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
if (report.fail.length > 0) {
|
||||
throw new Error(
|
||||
`Command completed with ${report.fail.length} failure(s)`,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(chalk.blue('Command completed!'));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user