Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s
125 lines
12 KiB
Plaintext
125 lines
12 KiB
Plaintext
---
|
||
title: تكوين التطبيق
|
||
description: عرّف هوية تطبيقك، والدور الافتراضي، والمتغيرات، وبيانات التعريف لسوق التطبيقات باستخدام defineApplication.
|
||
icon: rocket
|
||
---
|
||
|
||
يجب أن يحتوي كل تطبيق على استدعاء واحد فقط لـ `defineApplication`. يحدّد ما يلي:
|
||
|
||
* **الهوية** — المعرّف الشامل، واسم العرض، والوصف.
|
||
* **الأذونات** — الدور الذي تعمل بموجبه دوال المنطق والمكوّنات الأمامية الخاصة به.
|
||
* **المتغيرات** *(اختياري)* — أزواج مفتاح–قيمة تُتاح لكودك كمتغيرات بيئة.
|
||
* **خطافات ما قبل التثبيت/ما بعد التثبيت/إلغاء التثبيت** *(اختياري)* — راجع [Logic Functions](/l/ar/developers/extend/apps/logic/logic-functions).
|
||
|
||
```ts src/application-config.ts
|
||
import { defineApplication } from 'twenty-sdk/define';
|
||
|
||
export default defineApplication({
|
||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||
displayName: 'My Twenty App',
|
||
description: 'My first Twenty app',
|
||
applicationVariables: {
|
||
DEFAULT_RECIPIENT_NAME: {
|
||
universalIdentifier: '19e94e59-d4fe-4251-8981-b96d0a9f74de',
|
||
description: 'Default recipient name for postcards',
|
||
value: 'Jane Doe',
|
||
isSecret: false,
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
الملاحظات:
|
||
|
||
* حقول `universalIdentifier` هي معرّفات حتمية تملكها أنت. أنشِئها مرة واحدة واحتفظ بها ثابتة عبر عمليات المزامنة.
|
||
* `applicationVariables` تصبح متغيرات بيئة لوظائفك ومكوّناتك الأمامية. في وظائف المنطق (على جانب الخادم)، تكون متاحة على شكل `process.env.VARIABLE_NAME`. في المكوّنات الأمامية، استخدم `getApplicationVariable('VARIABLE_NAME')` من `twenty-sdk/front-component`. يتم حقن المتغيّرات المعلَّمة بـ `isSecret: true` في وظائف المنطق فقط. المكوّنات الأمامية تتلقّى المتغيّرات غير السرّية فقط.
|
||
* يتم اكتشاف الدور الافتراضي تلقائيًا من ملف الدور المميز بـ [`defineApplicationRole()`](/l/ar/developers/extend/apps/config/roles) — لست بحاجة إلى الإشارة إليه من `defineApplication()`.
|
||
* يتم اكتشاف دوال ما قبل التثبيت وما بعد التثبيت وإلغاء التثبيت تلقائيًا أثناء بناء البيان — لا حاجة للإشارة إليها في `defineApplication()`.
|
||
* لا يزال تمرير `defaultRoleUniversalIdentifier` بشكل صريح مدعومًا من أجل التوافق مع الإصدارات السابقة، ولكنه مُهمل لصالح `defineApplicationRole()`.
|
||
* `serverVariables` هي تكوينات وأسرار بنطاق المثيل (مثل مفاتيح واجهة برمجة التطبيقات). على عكس `applicationVariables`، فهي لا تصرح عن أي قيمة في ملف manifest — حيث يقوم مشغّل مساحة العمل بملئها من إعدادات التطبيق، ويتم حقنها في دوال المنطق فقط بعد تعيينها.
|
||
* كلا نوعي المتغير يقبلان `isDeprecated: true`. استخدم ذلك لإيقاف استخدام متغير بدلاً من حذفه: إبقاء المفتاح معلناً يحافظ على القيمة المخزنة (حذفه يدمّر القيمة التي أدخلها المشغّل)، ولا يزال يتم حقن المتغير، بحيث يمكن لشفرتك أن تعتمد عليه كخيار احتياطي — `process.env.NEW_API_KEY ?? process.env.API_KEY`. يختفي المتغير المهمل من إعدادات التطبيق عند عدم تحديد قيمة له، ولا يؤخذ في الحسبان ضمن فحص تهيئة التطبيق، لذا تكون `isDeprecated` أعلى أولوية من `isRequired`.
|
||
* لعرض واجهة مستخدم مخصّصة لإعدادات التكوين داخل علامة تبويب **Settings** في التطبيق (بدلًا من قسم تكوين المتغيّرات الافتراضي)، صرّح بمكوّن واجهة أمامية باستخدام [`defineSettingsFrontComponent()`](/l/ar/developers/extend/apps/layout/front-components#custom-settings-component) في ملفه الخاص. يُسمح بواحد فقط لكل تطبيق. الأقسام التي يديرها النظام (الترقية التلقائية، App URL، الاتصالات) تظل مرئية دائمًا.
|
||
|
||
## أنواع المتغيرات
|
||
|
||
كل من `applicationVariables` و`serverVariables` يقبلان حقل `type` اختياريًا (ولـ `SELECT` / `MULTI_SELECT`، قائمة `options`). الأنواع المدعومة: `TEXT` (افتراضي)، `BOOLEAN`، `NUMBER`، `NUMERIC`، `DATE`، `DATE_TIME`، `SELECT`، `MULTI_SELECT`، `ARRAY`، `RAW_JSON`، `RICH_TEXT`.
|
||
|
||
```ts src/application-config.ts
|
||
import { defineApplication, FieldType } from 'twenty-sdk/define';
|
||
|
||
export default defineApplication({
|
||
// ...identity, role...
|
||
applicationVariables: {
|
||
MAX_POSTCARDS: {
|
||
universalIdentifier: '5f4497e4-9030-4085-85eb-2c48b8d53713',
|
||
description: 'Maximum postcards per batch',
|
||
type: FieldType.NUMBER,
|
||
value: 10,
|
||
},
|
||
DEFAULT_REGION: {
|
||
universalIdentifier: '76c5c321-b6b6-46eb-b4fc-f9f04bb04227',
|
||
description: 'Default shipping region',
|
||
type: FieldType.SELECT,
|
||
options: [
|
||
{ label: 'Europe', value: 'eu' },
|
||
{ label: 'United States', value: 'us' },
|
||
],
|
||
value: 'eu',
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
إن `type` يؤثر فقط على **العرض والتحقق** — حيث يختار حقل الإدخال المطابق في واجهة إعدادات مساحة العمل (زر تبديل، حقل أرقام، قائمة منسدلة، منتقي تاريخ، محرر JSON، …) ويسمح لعملية البناء بالتحقق من صحة إعداداتك (على سبيل المثال، يجب أن يعلن `SELECT` / `MULTI_SELECT` عن `options` غير فارغة). وهو **لا** يغيّر كيفية وصول القيمة إلى الشيفرة الخاصة بك.
|
||
|
||
تُحَقَن القيم **دائمًا كسلاسل نصية** — فهذا جزء جوهري من متغيرات البيئة (`process.env.*` نصية فقط). عند تشغيل دالة المنطق الخاصة بك، يقوم المنفّذ بتسلسل كل قيمة وفقًا لـ `type` المعلن أثناء بناء `process.env`، بحيث يكون تنسيق السلسلة النصية متّسقًا بغض النظر عن كيفية تعيين القيمة (قيمة افتراضية في manifest، من واجهة الإعدادات، أو من إصدار سابق):
|
||
|
||
| النوع | سلسلة نصية في `process.env` |
|
||
| ------------------------------------- | -------------------------------------- |
|
||
| `TEXT`، `SELECT`، `DATE`، `DATE_TIME` | القيمة الخام (`"eu"`، `"2026-01-01"`) |
|
||
| `BOOLEAN` | `"true"` / `"false"` |
|
||
| `NUMBER`، `NUMERIC` | سلسلة عشرية (`"10"`، `"2.5"`) |
|
||
| `MULTI_SELECT`، `ARRAY` | مصفوفة JSON (`'["email","postcard"]'`) |
|
||
| `RAW_JSON`، `RICH_TEXT` | كائن JSON (`'{"retries":3}'`) |
|
||
|
||
حوّل السلسلة النصية مرة أخرى إلى النوع الذي تتوقعه:
|
||
|
||
```ts
|
||
const maxCards = Number(process.env.MAX_POSTCARDS); // "10" -> 10
|
||
const enabled = process.env.ENABLE_TRACKING === 'true'; // "true" -> true
|
||
const channels = JSON.parse(process.env.ENABLED_CHANNELS ?? '[]'); // '["email"]' -> ["email"]
|
||
const config = JSON.parse(process.env.PROVIDER_CONFIG ?? '{}'); // '{"retries":3}' -> { retries: 3 }
|
||
```
|
||
|
||
ينطبق الأمر نفسه على مكوّنات الواجهة الأمامية التي تقرأ القيم عبر `getApplicationVariable('VARIABLE_NAME')` — فالقيمة المعادة هي سلسلة نصية؛ قم بتحليلها حسب الحاجة.
|
||
|
||
## الدور الافتراضي للوظيفة
|
||
|
||
يتحكم الدور المعلن باستخدام [`defineApplicationRole()`](/l/ar/developers/extend/apps/config/roles) في ما يمكن لوظائف منطق التطبيق ومكوّنات الواجهة الوصول إليه:
|
||
|
||
* رموز وقت التشغيل المحقونة في دوال المنطق لديك مستمدة من هذا الدور. تُقيَّد المكالمة التي تتصرف كشخص بشكل أكبر بما يمكن لذلك الشخص القيام به، لذا لا يمكنها أبدًا تجاوز أيٍّ منهما. راجع [صلاحيات الوصول التي تستخدمها المكالمة](/l/ar/developers/extend/apps/logic/logic-functions#whose-access-a-call-uses).
|
||
* يكون عميل واجهة برمجة التطبيقات مضبوط الأنواع مقيّدًا بالأذونات الممنوحة لذلك الدور.
|
||
* اتبع مبدأ أقل امتياز: صرّح فقط عن الأذونات التي تحتاجها دوالك.
|
||
|
||
عند إنشاء هيكل لتطبيق جديد، ينشئ CLI ملف دور مبدئي في `src/roles/default-role.ts`. راجع [Roles & Permissions](/l/ar/developers/extend/apps/config/roles) للاطلاع على المرجع الكامل.
|
||
|
||
## بيانات التعريف لسوق التطبيقات
|
||
|
||
إذا كنت تخطط لـ [نشر تطبيقك](/l/ar/developers/extend/apps/operations/publishing)، فإن هذه الحقول الاختيارية تتحكّم في كيفية ظهوره في السوق:
|
||
|
||
| الحقل | الوصف |
|
||
| ------------------ | ------------------------------------------------------------------------------------------------------------ |
|
||
| `author` | اسم المؤلف أو الشركة |
|
||
| `category` | فئة التطبيق لتصفية سوق التطبيقات |
|
||
| `logo` | مسار شعار تطبيقك المضمَّن في `public/` (مثلًا، `public/logo.png`) |
|
||
| `galleryImages` | مصفوفة لمسارات صور المعرض المضمَّنة في `public/` (مثلًا، `public/screenshot-1.png`) |
|
||
| `aboutDescription` | وصف ماركداون أطول لعلامة التبويب "حول". إذا لم يتم تضمينه، يستخدم السوق ملف `README.md` الخاص بالحزمة من npm |
|
||
| `websiteUrl` | رابط إلى موقعك الإلكتروني |
|
||
| `termsUrl` | رابط إلى شروط الخدمة |
|
||
| `emailSupport` | عنوان البريد الإلكتروني للدعم |
|
||
| `issueReportUrl` | رابط إلى متتبّع المشاكل |
|
||
|
||
<Note>
|
||
القيمتان `logoUrl` و`screenshots` هما اسمَان مهملان بديلان لـ`logo` و`galleryImages`. عناوين URLs المطلقة الخارجية (`http://` أو `https://`) غير مدعومة لهذه الحقول: سيتم تجاهلها مع إظهار تحذير وقت البناء. بدلًا من ذلك، ضمِّن الصور في مجلد `public/` الخاص بتطبيقك.
|
||
</Note>
|