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
10 KiB
Plaintext
125 lines
10 KiB
Plaintext
---
|
||
title: Configurația aplicației
|
||
description: Declarați identitatea aplicației, rolul implicit, variabilele și metadatele din marketplace cu `defineApplication`.
|
||
icon: rocket
|
||
---
|
||
|
||
Fiecare aplicație trebuie să aibă exact un apel `defineApplication`. Acesta declară:
|
||
|
||
* **Identitate** — identificator universal, nume de afișare, descriere.
|
||
* **Permisiuni** — sub ce rol rulează funcțiile logice și componentele front-end ale acesteia.
|
||
* **Variabile** *(opțional)* — perechi cheie–valoare expuse codului dvs. ca variabile de mediu.
|
||
* **Hook-uri de pre-instalare / post-instalare / dezinstalare** *(opțional)* — vedeți [Funcții logice](/l/ro/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,
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
Notițe:
|
||
|
||
* Câmpurile `universalIdentifier` sunt ID-uri deterministe pe care le dețineți. Generați-le o singură dată și mențineți-le stabile între sincronizări.
|
||
* `applicationVariables` devin variabile de mediu pentru funcțiile și componentele front-end. În funcțiile de logică (server-side), acestea sunt disponibile ca `process.env.VARIABLE_NAME`. În componentele front-end, folosește `getApplicationVariable('VARIABLE_NAME')` din `twenty-sdk/front-component`. Variabilele marcate cu `isSecret: true` sunt injectate doar în funcțiile de logică. Componentele front-end primesc doar variabile non-secrete.
|
||
* Rolul implicit este detectat automat din fișierul de rol marcat cu [`defineApplicationRole()`](/l/ro/developers/extend/apps/config/roles) — nu este necesar să faci referire la el în `defineApplication()`.
|
||
* Funcțiile de pre-instalare, post-instalare și dezinstalare sunt detectate automat în timpul construirii manifestului — nu este nevoie să faceți referire la ele în `defineApplication()`.
|
||
* Transmiterea explicită a `defaultRoleUniversalIdentifier` este în continuare acceptată pentru compatibilitate retroactivă, dar este considerată învechită în favoarea `defineApplicationRole()`.
|
||
* `serverVariables` sunt configurări și secrete la nivel de instanță (de ex. chei API). Spre deosebire de `applicationVariables`, ele nu declară nicio valoare în manifest — operatorul spațiului de lucru le completează din setările aplicației și sunt injectate în funcțiile de logică doar după ce au fost setate.
|
||
* Ambele tipuri de variabile acceptă `isDeprecated: true`. Folosește-l pentru a retrage o variabilă în loc să o ștergi: păstrarea cheii declarate conservă valoarea stocată (ștergerea ei distruge valoarea introdusă de operator), iar variabila este în continuare injectată, astfel încât codul tău poate reveni la ea — `process.env.NEW_API_KEY ?? process.env.API_KEY`. O variabilă învechită dispare din setările aplicației odată ce nu mai are nicio valoare și nu este niciodată luată în calcul la verificarea configurației aplicației, astfel încât `isDeprecated` are prioritate față de `isRequired`.
|
||
* Pentru a afișa o interfață de configurare personalizată în fila **Settings** a aplicației (în locul secțiunii implicite de configurare a variabilelor), declară un front component cu [`defineSettingsFrontComponent()`](/l/ro/developers/extend/apps/layout/front-components#custom-settings-component) într-un fișier separat. Este permis doar unul per aplicație. Secțiunile gestionate de sistem (auto-upgrade, App URL, connections) rămân întotdeauna vizibile.
|
||
|
||
## Tipuri de variabile
|
||
|
||
Atât `applicationVariables`, cât și `serverVariables` acceptă un câmp opțional `type` (și, pentru `SELECT` / `MULTI_SELECT`, o listă `options`). Tipuri acceptate: `TEXT` (implicit), `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',
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
Proprietatea `type` afectează doar **prezentarea și validarea** — selectează câmpul de intrare corespunzător în interfața de setări a spațiului de lucru (un comutator, câmp numeric, listă derulantă, selector de dată, editor JSON, …) și permite build‑ului să valideze configurația (de exemplu, `SELECT` / `MULTI_SELECT` trebuie să declare o listă `options` negoală). Nu modifică **deloc** modul în care valoarea ajunge în codul tău.
|
||
|
||
Valorile sunt **întotdeauna injectate ca stringuri** — acest lucru este inerent pentru variabilele de mediu (`process.env.*` este doar string). Când rulează funcția ta de logică, executorul serializează fiecare valoare în funcție de `type`‑ul declarat în timp ce construiește `process.env`, astfel încât formatul stringului este consecvent indiferent de modul în care a fost setată valoarea (valoare implicită din manifest, interfața de setări sau o versiune anterioară):
|
||
|
||
| Tip | string `process.env` |
|
||
| ------------------------------------- | --------------------------------------- |
|
||
| `TEXT`, `SELECT`, `DATE`, `DATE_TIME` | valoarea brută (`"eu"`, `"2026-01-01"`) |
|
||
| `BOOLEAN` | `"true"` / `"false"` |
|
||
| `NUMBER`, `NUMERIC` | string zecimal (`"10"`, `"2.5"`) |
|
||
| `MULTI_SELECT`, `ARRAY` | array JSON (`'["email","postcard"]'`) |
|
||
| `RAW_JSON`, `RICH_TEXT` | obiect JSON (`'{"retries":3}'`) |
|
||
|
||
Parsează stringul înapoi în tipul pe care îl aștepți:
|
||
|
||
```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 }
|
||
```
|
||
|
||
Același lucru se aplică și componentelor de interfață care citesc valori prin `getApplicationVariable('VARIABLE_NAME')` — valoarea returnată este un string; parseaz-o după cum este necesar.
|
||
|
||
## Rol implicit pentru funcții
|
||
|
||
Rolul declarat cu [`defineApplicationRole()`](/l/ro/developers/extend/apps/config/roles) controlează la ce pot avea acces funcțiile logice și componentele de interfață ale aplicației:
|
||
|
||
* Tokenurile de runtime injectate în funcțiile dvs. de logică sunt derivate din acest rol. Un apel care acționează ca o persoană este restrâns suplimentar la ceea ce poate face acea persoană, astfel încât nu poate depăși niciodată niciuna dintre cele două limite. Consultați [Ce acces utilizează un apel](/l/ro/developers/extend/apps/logic/logic-functions#whose-access-a-call-uses).
|
||
* Clientul API tipizat este restricționat la permisiunile acordate acelui rol.
|
||
* Respectați principiul celui mai mic privilegiu: declarați doar permisiunile de care au nevoie funcțiile.
|
||
|
||
Când generați o aplicație nouă, CLI creează un fișier de rol de pornire la `src/roles/default-role.ts`. Consultați [Roluri și permisiuni](/l/ro/developers/extend/apps/config/roles) pentru referința completă.
|
||
|
||
## Metadate pentru marketplace
|
||
|
||
Dacă intenționați să [publicați aplicația](/l/ro/developers/extend/apps/operations/publishing), aceste câmpuri opționale controlează modul în care apare în marketplace:
|
||
|
||
| Câmp | Descriere |
|
||
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
|
||
| `author` | Numele autorului sau al companiei |
|
||
| `category` | Categoria aplicației pentru filtrarea în marketplace |
|
||
| `logo` | Calea către logo-ul aplicației tale inclus în `public/` (de ex., `public/logo.png`) |
|
||
| `galleryImages` | Array de căi către imaginile din galerie incluse în `public/` (de ex., `public/screenshot-1.png`) |
|
||
| `aboutDescription` | Descriere markdown mai lungă pentru fila "About". Dacă este omis, marketplace-ul folosește `README.md` al pachetului de pe npm |
|
||
| `websiteUrl` | Link către site-ul dvs. |
|
||
| `termsUrl` | Link către termenii de serviciu |
|
||
| `emailSupport` | Adresă de e-mail pentru suport |
|
||
| `issueReportUrl` | Link către sistemul de urmărire a problemelor |
|
||
|
||
<Note>
|
||
`logoUrl` și `screenshots` sunt aliasuri învechite pentru `logo` și `galleryImages`. URL-urile absolute externe (`http://` sau `https://`) nu sunt acceptate pentru aceste câmpuri: ele sunt eliminate cu un avertisment în timpul build-ului. În schimb, include imaginile în folderul `public/` al aplicației tale.
|
||
</Note>
|