Prezentare generală
Dezvoltarea locală de aplicații se învârte în jurul sincronizării: CLI-ul reconstruiește manifestul și serverul aplică doar diferența dintre acesta și metadatele deja existente în spațiul tău de lucru. Această pagină explică ce comandă să folosești, cum să citești ce a modificat o sincronizare și ce să faci — în ordine — atunci când starea locală pare inconsistentă.Ce comandă și când
Pentru iterațiile locale de zi cu zi vei dori aproape întotdeauna
twenty app dev.
Publicarea și implementarea sunt pentru lansarea de versiuni, nu pentru bucla locală.Sincronizarea locală nu are nevoie de incrementarea versiunii
Regula deversion strict crescătoare (VERSION_ALREADY_EXISTS la deploy, APP_ALREADY_INSTALLED / CANNOT_DOWNGRADE_APPLICATION la instalare) se aplică pentru twenty app publish / twenty app install — calea de release. twenty app dev sincronizează manifestul pe loc și nu necesită niciodată schimbarea versiunii, astfel încât nu trebuie să atingi package.json pentru a itera. Dacă ajungi să crești versiunea ca să testezi o modificare locală, folosești calea de release atunci când ai nevoie de bucla de dezvoltare.
Citirea rezultatului sincronizării
Fiecare sincronizare afișează modificările de metadate pe care le-a aplicat (sau le-ar aplica, cuplan), în stil Terraform — un bloc per entitate cu atributele sale, apoi o linie de rezumat:
to destroy) sunt listate împreună cu ceea ce elimină (de ex. objectMetadata "auditNote" — drops the table and all its rows) și necesită confirmare interactivă sau --yes în scripturi.
O sincronizare șterge fiecare entitate deținută de aplicația ta pe care sursa ta nu o mai declară. Când un plan conține operațiuni de ștergere, acesta indică acest lucru și face referire la --no-prune (anterior --no-delete, care funcționează în continuare), ceea ce face sincronizarea aditivă: creările și actualizările sunt aplicate, nimic din ce lipsește din sursa dvs. nu este șters, iar componenta de setări și legăturile hookului de dezinstalare ale aplicației rămân așa cum sunt atunci când sursa dvs. nu le declară. Folosește-l atunci când sursa ta este intenționat parțială, de exemplu în timp ce preiei o aplicație creată în interfața cu utilizatorul. Aplicația Custom din spațiul de lucru este excepția: deoarece pull nu poate exporta încă tot ce deține, sincronizarea sa este aditivă, cu excepția cazului în care transmiteți --prune. Serverele lansate înainte de această modificare încă șterg în mod implicit, așa că transmiteți --no-prune atunci când aplicați aplicația Custom pe unul dintre acestea.
Când o sincronizare eșuează pe o singură entitate, eroarea numește entitatea problematică și universalIdentifier-ul acesteia, de exemplu:
Previzualizarea modificărilor (plan)
twenty app plan construiește manifestul, cere serverului planul de migrare și îl afișează — fără a aplica nimic. Este modalitatea sigură de a răspunde la întrebarea „ce ar schimba această sincronizare?” înainte de a te angaja la ea.
- Nu modifică spațiul de lucru, nu efectuează migrarea metadatelor, actualizarea înregistrărilor aplicației sau modificări ale rolului/filei implicite. Creează un instantaneu local, dar nu regenerează clientul API.
- Returnează același diff pe care l-ar aplica o sincronizare reală, astfel încât poți revizui dinainte entitățile create/actualizate/șterse.
- Este util înaintea unei modificări riscante, când revizuiești o modificare generată de AI sau într-un script care ar trebui să eșueze dacă o modificare neașteptată este pe cale să fie aplicată.
Un plan previzualizează doar modificările de metadate. Funcționează și pentru o aplicație care nu a fost
sincronizată niciodată: serverul evaluează manifestul comparativ cu o aplicație goală,
astfel încât planul listează tot ce ar crea sursa ta.
Extragerea unei aplicații instalate înapoi în sursă
twenty app pull este inversul comenzii apply: citește o aplicație din spațiul de lucru și îi restaurează fișierele define, traducerile și fișierele de dependențe stocate.
defineApplication() și preia aplicația respectivă. În afara unei aplicații, solicită un director și confirmare, creează un proiect local pentru aplicația particularizată a spațiului de lucru selectat, instalează dependențele cu Yarn, apoi preia definițiile. Noul proiect include fișiere de pachet și de configurare, fără entitățile demonstrative ale inițializatorului.
Utilizați --path pentru a selecta o aplicație existentă sau un director nou ori gol. Crearea neinteractivă necesită --path și --yes; pull refuză să suprascrie un director nevid fără legătură. Crearea unui proiect nu înregistrează o aplicație și nu modifică spațiul de lucru. Un proiect SDK existent fără o definiție a aplicației preia, de asemenea, aplicația personalizată. Nu există nicio opțiune --universal-identifier.
Dacă instalarea dependențelor eșuează pentru un proiect nou, scaffold-ul este păstrat. Rulați yarn install în interiorul acestuia, apoi reîncercați pull. Proiectele existente nu instalează automat dependențele. Dacă identificatorul aplicației lor nu poate fi citit, pull raportează acea eroare în loc să creeze o altă aplicație. Adaugă --verbose pentru a extinde secțiunile de acoperire ale raportului, care apoi denumesc până la 20 de identificatori per tip de metadate, în loc să afișeze doar totalurile.
Ce scrie:
- configurația aplicației;
- fișierele de dependențe
package.jsonșiyarn.lockstocate, în rădăcina proiectului; - obiecte, cu câmpurile lor incluse;
- câmpuri pe care aplicația ta le-a adăugat obiectelor pe care nu le deține;
- indici creați;
- indicatorii de permisiune pe care îi declară aplicația dvs., sub formă de fișiere
definePermissionFlag(); - roluri, cu permisiunile lor pentru obiecte, permisiunile pentru câmpuri, predicatele de permisiune la nivel de rând și grupurile, precum și indicatorii de permisiune inline. Rolul implicit al aplicației dvs. este scris cu
defineApplicationRole(). O permisiune pentru obiect sau câmp al cărei identificator este cel derivat de compilare este scrisă fără acesta. Când rolul implicit nu este unul dintre rolurile proprii ale aplicației dvs., ca în cazul aplicației Custom din spațiul de lucru, configurația aplicației păstrează în schimbdefaultRoleUniversalIdentifier; - vizualizări, cu câmpurile lor, grupurile de câmpuri, filtrele, grupurile de filtre, sortările și grupurile inline;
- câmpurile de vizualizare pe care aplicația dvs. le-a adăugat la vizualizări pe care nu le deține, ca fișiere
defineViewField()independente; - aspectele de pagină, cu filele și widgeturile acestora integrate;
- filele pe care aplicația dvs. le-a adăugat la aspecte de pagină pe care nu le deține, ca fișiere
definePageLayoutTab()independente; - elemente de meniu de navigare, inclusiv fișiere și foldere
defineNavigationMenuItem(); - widgeturile pe care aplicația dvs. le-a adăugat la filele pe care nu le deține, ca fișiere autonome
definePageLayoutWidget(); - fluxuri de lucru, ca fișiere
defineWorkflow(), cu sursa fiecărui pas Code în propriul fișier\<workflow-file-name>/\<step-name>.code.tsde lângă fluxul de lucru, atunci când versiunea lor stocată este cea scrisă de ultima sincronizare. Pentru aplicația Custom a spațiului de lucru, este versiunea activă, indiferent dacă a fost publicată de o sincronizare sau de constructorul de fluxuri de lucru, iar aplicarea publică o definiție modificată ca versiune nouă, după cum este descris în Workflows; - abilități, ca fișiere
defineSkill(); - agenți, ca fișiere
defineAgent(), cu declanșatoarele lor și rolul căruia aplicația dvs. îi face asocierea; - reguli de validare, ca fișiere
defineValidationRule()cu expresia lor sub formă de șir; - traduceri publicate, ca
locales/\<locale>.jsonpentru ca strings pull să poată citi înapoi din metadatele și sursa extrase șilocales/compiled/\<locale>.jsonpentru restul.
package.json sau yarn.lock stocat se modifică, pull înlocuiește fișierul local și raportează orice modificări locale suprascrise. Dacă fișierul la distanță nu s-a modificat de la pull-ul anterior, modificările locale sunt păstrate. Lipsa unui fișier la distanță nu șterge fișierul local corespunzător. Când pachetul exportat omite twenty-sdk, așa cum face aplicația Custom a spațiului de lucru, pull păstrează dependența SDK locală, astfel încât comenzile CLI să poată încărca în continuare proiectul. Fișierele de dependențe, metadatele și baza de referință sunt scrise împreună și sunt anulate împreună dacă o scriere eșuează.
Rulați yarn install după preluarea modificărilor dependențelor. Pull instalează dependențele doar la crearea unui proiect nou, înainte de restaurarea fișierelor la distanță; nu le reinstalează după înlocuirea package.json sau yarn.lock. Pull nu regenerează clientul tipizat. Rulează twenty app generate-client când ai nevoie de tipuri actualizate pentru spațiul de lucru.
Ce nu scrie:
- Neexportate încă — elemente de meniu pentru comenzi și elemente de meniu pentru setări, funcții de logică și componente front-end, furnizori de conexiuni, variabile ale aplicației, active publice, tipuri de activitate în cronologie și sursa stocată a funcțiilor dvs.
- Derivate de motor — câmpuri de sistem, relații implicite, vizualizări implicite și indecși de suport, precum și aspectele implicite ale paginilor pentru fiecare obiect. Serverul le reconstruiește la aplicare. Un obiect poate indica în continuare identificatorul etichetei sale către unul dintre acestea, așa cum fac obiectele de joncțiune create în interfața UI; referința este scrisă, iar compilarea o rezolvă fără a adăuga un câmp.
- Plasate într-o vizualizare implicită sau externă — filtrele, grupurile de filtre, sortările, grupurile și grupurile de câmpuri adăugate într-o vizualizare implicită a motorului sau într-o vizualizare deținută de o altă aplicație nu au încă un formular sursă și sunt raportate. Câmpurile de vizualizare adăugate acolo sunt scrise ca fișiere independente, deoarece identificatorul vizualizării este cunoscut.
- Plasate într-un aspect de pagină implicit sau extern — filele și widgeturile adăugate la un aspect de pagină implicit al motorului sau la unul deținut de altă aplicație sunt scrise ca fișiere autonome
definePageLayoutTab()șidefinePageLayoutWidget(), deoarece este cunoscut identificatorul la care se atașează. - Widgeturi pe care exportul nu le poate include încă — în orice aspect, inclusiv în al dvs., este raportat un widget de tip
VIEWdepreciat, un widget care afișează una dintre propriile componente front-end ale aplicației dvs. sau elemente din meniul de comenzi, ori un widget fără poziție pentru modul de aspect al filei sale, iar aspectul sau fila sunt scrise fără acesta. - Fluxuri de lucru pe care exportul nu le poate transporta încă — un flux de lucru modificat în generatorul de fluxuri de lucru de la ultima sincronizare, un flux de lucru de sistem sau privat, unul cu un pas Code creat înainte ca pașii să-și stocheze sursa și unul care apelează acțiunea de flux de lucru a altei aplicații sunt raportate și lăsate pe loc. Un flux de lucru lăsat pe loc își păstrează fișierele
.code.ts. Aplicația Custom a spațiului de lucru este excepția pentru primul și ultimul caz: constructorul publică și fluxurile sale de lucru, iar acestea pot apela acțiunile oricărei aplicații, deci sunt extrase. În schimb, unul dintre fluxurile sale de lucru este raportat atunci când nu are o versiune activă sau când versiunea sa activă utilizează setări pe care o definiție nu le poate exprima. Pașii de e-mail și calendar sunt preluați: un cont partajat cu spațiul de lucru este scris caconnectedAccountHandle, în timp ce contul privat și variabilele unui membru sunt păstrate ca atare. În schimb, fluxul de lucru este semnalat atunci când contul unui pas este arhivat, nu mai poate executa pasul sau își partajează adresa cu un cont mai vechi, deoarece aplicarea identificatorului ar selecta un alt cont. - Agenți pe care exportul nu îi poate prelua încă — un agent cu mai mult de un rol sau asociat cu un rol pe care extragerea nu îl scrie este raportat și lăsat pe loc.
- Reguli de validare pe care exportul nu le poate include încă — o regulă fără expresie sau mesaj, cum ar fi o ciornă nefinalizată din Setări sau una care citește un câmp șters din spațiul de lucru, este raportată și lăsată pe loc.
- Starea de rulare a spațiului de lucru, atașamentele înregistrărilor, atașamentele e-mailurilor, alocările de roluri pentru membri și chei API, webhookurile, navigarea per utilizator și elementele de navigare fixate la o înregistrare, toate excluse prin design, inclusiv pentru aplicația Custom a spațiului de lucru.
- Deținut de o altă aplicație — raportat, dar niciodată extras.
twenty app apply --no-prune până când sunt acoperite tipurile lipsă. Aplicația Custom din spațiul de lucru aplică deja acest comportament în mod implicit. O aplicare cu curățare (cea implicită pentru celelalte aplicații, --prune pentru aplicația Custom) le-ar șterge, iar twenty app plan enumeră exact care sunt acestea.
Stare locală spațiului de lucru. O entitate dezactivată în spațiul de lucru este scrisă ca definiție activă, iar suprascrierile pe care spațiul de lucru le-a efectuat asupra unei entități, cum ar fi o etichetă redenumită, nu sunt scrise. Raportul listează acele rânduri sub „Scrise fără starea lor locală spațiului de lucru”. Aplicarea arborelui înapoi în același spațiu de lucru lasă acea stare neatinsă; un alt spațiu de lucru primește entitatea activă și fără suprascrieri.
Fișierul de bază. Pull înregistrează ceea ce a preluat în .twenty/cli/pull-base.json, care este ignorat de git și specific fiecărei copii de lucru. Acest fișier este cel cu care compară o extragere ulterioară pentru a lăsa neatinse fișierele ale căror entități nu s-au schimbat și pentru a șterge fișierul unei entități care nu mai există în spațiul de lucru. Un checkout fără acesta scrie pur și simplu totul și nu șterge nimic.
Plan de recuperare în trepte
Când metadatele locale par greșite, escaladează în această ordine și oprește-te de îndată ce ești deblocat. Fiecare pas este mai disruptiv decât precedentul.- Resincronizează. Rulează din nou
twenty app apply. Sincronizările sunt idempotente — rularea din nou a unui manifest curat este sigură și rezolvă adesea o problemă temporară. - Previzualizează planul. Rulează
twenty app planpentru a vedea exact ce intenționează să schimbe următoarea sincronizare, fără a-l aplica. - Citește eroarea nominalizată. Dacă o sincronizare eșuează, notează tipul de metadate și
universalIdentifier-ul din mesaj (vezi mai sus) și localizează acea entitate în manifest. Un conflict indică de obicei un identificator duplicat sau reutilizat. - Dezinstalează și reinstalează.
twenty app uninstall, apoi sincronizează din nou (twenty app dev). Acest lucru reconstruiește metadatele aplicației de la zero, păstrând în același timp restul spațiului de lucru intact. - Resetare completă (ultimă soluție). Pentru un mediu local gestionat prin CLI, rulează
twenty local reset, apoitwenty local startși reconectează-te înainte de a sincroniza din nou. Pentru un checkout al sursei, resetează și reinițializează cu date baza de date de dezvoltare a acestuia.
Ai întâlnit o eroare de metadate? Te rugăm să deschizi o problemă și să incluzi
mesajul de migrare eșuată (cu tipul de metadate și
universalIdentifier),
rezultatul Metadata changes din sincronizare și comenzile pe care le-ai rulat.Evită sincronizările concurente pe același spațiu de lucru
Sincronizarea aplică migrațiile de metadate. Rularea mai multor operațiuni de sincronizare, deploy sau instalare împotriva aceluiași spațiu de lucru în același timp — de exemplu, mai multe terminale sau agenți AI care iterează în paralel — poate intercala acele migrații și poate lăsa metadatele într-o stare aplicată parțial. Serverul serializează sincronizările per spațiu de lucru pentru a preveni acest lucru, dar ar trebui totuși să treci operațiunile sensibile de metadate printr-un proces unic, în loc să le declanșezi concurent. Dacă orchestrezi dezvoltarea cu mai mulți agenți, rutează apelurile lor de sync/deploy/install printr-o singură coadă, astfel încât să ruleze doar unul la un moment dat.Deosebirea tipurilor de erori
Când ceva nu merge bine, diff-ul de metadate și erorile nominalizate îți permit să localizezi eșecul:- Eroare de construire a manifestului — CLI-ul eșuează înainte de sincronizare (
MANIFEST_BUILD_FAILED,TYPECHECK_FAILED); repară sursa aplicației. - Eroare de proprietate a înregistrării — sincronizarea este refuzată deoarece
universalIdentifieral aplicației aparține unui alt spațiu de lucru sau nu aparține deloc niciunui spațiu de lucru; consultați Proprietatea înregistrării. - Eroare de sincronizare / migrare — build-ul reușește, dar aplicarea diff-ului eșuează, menționând entitatea și
universalIdentifier-ul; repară metadatele care intră în conflict. - Eroare de dimensiune a dependențelor — sincronizarea sau instalarea eșuează deoarece
dependenciesde producție ale aplicației sunt prea mari pentru a fi instalate ca strat de rulare (LOGIC_FUNCTION_DEPENDENCIES_SIZE_EXCEEDED); mută pachetele pe care funcțiile tale logice nu le importă la rulare (biblioteci UI, unelte de dezvoltare) îndevDependencies. - Migrare amânată în desfășurare — sincronizarea este refuzată deoarece o migrare în fundal a modelului de date dintr-o sincronizare anterioară încă rulează (
DEFERRED_WORKSPACE_MIGRATION_ACTIONS_IN_PROGRESS); așteptați să se finalizeze, apoi sincronizați din nou. - Eroare de execuție în codul aplicației — sincronizarea reușește, dar funcțiile sau componentele tale logice se comportă incorect la execuție; verifică jurnalele funcțiilor.
- Stare locală a instanței — niciuna dintre cele de mai sus și spațiul de lucru tot arată greșit; coboară pe scara de recuperare.