Files
upstream-twenty/packages/twenty-docs/l/pt/developers/extend/apps/data/system-fields.mdx
upstream-mirror e7da97194a
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
snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
2026-09-17 23:28:13 +05:00

213 lines
11 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Referenciando metadados de sistema
description: Resolva os identificadores universais determinísticos dos metadados que o Twenty provisiona automaticamente em cada objeto, para que seu app possa referenciá-los sem hardcoding.
icon: gears
---
Todo objeto no Twenty vem com **metadados de sistema** que você nunca declara explicitamente, como um conjunto de campos e uma visualização principal de lista com suas colunas. O servidor cria tudo isso quando o objeto é provisionado, e o conjunto cresce conforme o Twenty cresce.
Como você não o declara, não existe nenhuma constante `universalIdentifier` para você importar. Em vez disso, o servidor **deriva** cada identificador de forma determinística, e o `twenty-sdk` expõe a mesma derivação para que seu manifesto possa resolver o valor exato que o servidor usa.
## Campos do sistema
Os campos escalares presentes em todo objeto, nenhum dos quais você declara com [`defineField()`](/l/pt/developers/extend/apps/data/extending-objects):
`id`, `createdAt`, `updatedAt`, `deletedAt`, `createdBy`, `updatedBy`, `position`, `searchVector`
Então, como você referencia `createdAt` como uma coluna em uma [visualização](/l/pt/developers/extend/apps/layout/views)?
### O Problema
Desde o Twenty 2.19, o identificador universal de um campo de sistema é **derivado deterministicamente** pelo servidor a partir de três entradas: o identificador universal do aplicativo, o identificador universal do objeto e o nome do campo. Inventar um id e deixá-lo hardcoded não funciona: ele não corresponde a nada no servidor, e a sincronização rejeita a referência pendente:
```
Dev sync failed: viewField: INVALID_VIEW_DATA: Field metadata not found
```
### A Solução
<Note>
`getFieldUniversalIdentifier` está disponível a partir do `twenty-sdk` 2.21.
</Note>
Use `getFieldUniversalIdentifier` para resolver exatamente o mesmo valor que o servidor usa. Ela recebe as três entradas e retorna o identificador universal do campo:
```ts
import { getFieldUniversalIdentifier } from 'twenty-sdk/define';
const createdAtFieldId = getFieldUniversalIdentifier({
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: MY_OBJECT_UNIVERSAL_IDENTIFIER,
name: 'createdAt',
});
```
* `applicationUniversalIdentifier` é o identificador do seu app, aquele que você passa para [`defineApplication()`](/l/pt/developers/extend/apps/config/application).
* `objectUniversalIdentifier` é o identificador do objeto ao qual o campo pertence.
* `name` é o nome do campo de sistema, um dos valores listados acima.
### Exemplo: uma coluna createdAt em uma visualização
O caso típico é adicionar uma coluna `createdAt` a uma visualização de um dos seus objetos personalizados. Resolva o id do campo e referencie-o como qualquer outro `fieldMetadataUniversalIdentifier`:
```ts src/views/example-view.ts
import {
defineView,
getFieldUniversalIdentifier,
} from 'twenty-sdk/define';
const APPLICATION_UNIVERSAL_IDENTIFIER =
'0b04e15c-27b2-4741-9046-b32e07469072';
const MY_OBJECT_UNIVERSAL_IDENTIFIER =
'c782b61c-70fd-4c88-9cd6-4e61ab8d7591';
export default defineView({
universalIdentifier: '70f10d44-144a-4da8-8c6f-3ec2422138c0',
name: 'All records',
objectUniversalIdentifier: MY_OBJECT_UNIVERSAL_IDENTIFIER,
icon: 'IconList',
position: 0,
fields: [
{
universalIdentifier: '75a90bc4-d901-4df4-85e0-af29db5e0104',
fieldMetadataUniversalIdentifier: getFieldUniversalIdentifier({
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: MY_OBJECT_UNIVERSAL_IDENTIFIER,
name: 'createdAt',
}),
position: 0,
isVisible: true,
size: 200,
},
],
});
```
O mesmo id resolvido funciona em qualquer lugar onde se espera um `fieldMetadataUniversalIdentifier`: campos de visualização, filtros, ordenações, agrupamentos e widgets de layout de página.
<Note>
Resolva o id, não o deixe hardcoded. Como o servidor deriva o valor a partir do
id do aplicativo, do id do objeto e do nome do campo, chamar
`getFieldUniversalIdentifier` mantém a sua referência correta mesmo que essas
entradas mudem, e evita divergências se a derivação evoluir no futuro.
</Note>
### Campos de relação do sistema
<Note>
`getSystemRelationFieldUniversalIdentifier` está disponível a partir da versão 2.23 do `twenty-sdk` e requer um servidor Twenty na versão 2.23 ou posterior.
</Note>
Além dos campos escalares de sistema acima, o servidor também provisiona quatro **campos de relação de sistema** em cada objeto: `timelineActivities`, `attachments`, `noteTargets` e `taskTargets`, cada um apontando para o objeto de relação padrão correspondente.
Dessa forma, esses campos não são resolvidos com `getFieldUniversalIdentifier`: seu identificador é derivado de forma **independente de nome**, a partir do objeto que hospeda o campo e do objeto para o qual o campo aponta. Dessa forma, renomear um objeto nunca altera os identificadores de seus campos de relação.
Use `getSystemRelationFieldUniversalIdentifier` para resolvê-los:
```ts
import {
getSystemRelationFieldUniversalIdentifier,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
// rocket.attachments — the relation field hosted on your custom object
const rocketAttachmentsFieldId = getSystemRelationFieldUniversalIdentifier({
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: ROCKET_OBJECT_UNIVERSAL_IDENTIFIER,
relationTargetObjectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment.universalIdentifier,
});
```
* `objectUniversalIdentifier` é o objeto que **hospeda** o campo.
* `relationTargetObjectUniversalIdentifier` é o objeto para o qual o campo **aponta**.
A direção é codificada pela ordem dos argumentos. Para resolver o lado inverso (por exemplo, `attachment.targetRocket`, o campo morph que o servidor cria no objeto de relação padrão), inverta os dois:
```ts
// attachment.targetRocket — the reverse morph field on Attachment
const attachmentTargetRocketFieldId =
getSystemRelationFieldUniversalIdentifier({
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment.universalIdentifier,
relationTargetObjectUniversalIdentifier: ROCKET_OBJECT_UNIVERSAL_IDENTIFIER,
});
```
Assim como acontece com campos de sistema escalares, o id resolvido funciona em qualquer lugar em que um `fieldMetadataUniversalIdentifier` é esperado.
## Visualizações de sistema
<Note>
`getSystemViewUniversalIdentifier` e `getSystemViewFieldUniversalIdentifier`
estão disponíveis a partir da versão 2.26 do `twenty-sdk` e requerem um servidor Twenty na versão 2.26 ou posterior.
</Note>
O servidor também provisiona uma **visualização de sistema** em cada objeto: a visualização principal de lista (`All {objectLabelPlural}`, com chave `ViewKey.INDEX` (derivada com `SYSTEM_VIEW_KEYS.INDEX`)), com uma coluna por campo exibível. Assim como os campos de relação de sistema, seus identificadores são derivados **sem usar nomes**, então renomear um objeto ou um campo nunca os altera.
Use `getSystemViewUniversalIdentifier` para resolvê‑la:
```ts
import {
getSystemViewUniversalIdentifier,
SYSTEM_VIEW_KEYS,
} from 'twenty-sdk/define';
const rocketIndexViewId = getSystemViewUniversalIdentifier({
objectMetadataApplicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: ROCKET_OBJECT_UNIVERSAL_IDENTIFIER,
viewKey: SYSTEM_VIEW_KEYS.INDEX,
});
```
* `objectMetadataApplicationUniversalIdentifier` é o aplicativo proprietário do **objeto**, que define o namespace da visualização.
* `objectUniversalIdentifier` é o objeto que a visualização lista.
* `viewKey` é o discriminador de visualização de sistema: `SYSTEM_VIEW_KEYS.INDEX` para a visualização principal de lista, `SYSTEM_VIEW_KEYS.FIELDS_WIDGET` para a visualização do widget de campos da página de registro. Ele é a chave da derivação; apenas `INDEX` também é armazenado na linha da visualização.
O id resolvido funciona em qualquer lugar em que um `viewUniversalIdentifier` seja esperado, como uma entrada de barra lateral [`NavigationMenuItemType.VIEW`](/l/pt/developers/extend/apps/layout/navigation-menu-items). Para simplesmente abrir a lista principal de um objeto, prefira `NavigationMenuItemType.OBJECT` com `targetObjectUniversalIdentifier`: isso não precisa de derivação.
`getSystemViewFieldUniversalIdentifier` resolve uma única **coluna** em uma visualização de sistema, a partir da visualização e do campo que ela exibe:
```ts
import { getSystemViewFieldUniversalIdentifier } from 'twenty-sdk/define';
const rocketNameColumnId = getSystemViewFieldUniversalIdentifier({
fieldMetadataApplicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
viewUniversalIdentifier: rocketIndexViewId,
fieldMetadataUniversalIdentifier: ROCKET_NAME_FIELD_UNIVERSAL_IDENTIFIER,
});
```
Observe o primeiro argumento: uma coluna é colocada em namespace pelo aplicativo proprietário do **campo que ela exibe**, não pelo que é proprietário da visualização. Um campo que seu app adiciona a um objeto padrão tem sua coluna derivada sob o seu aplicativo, em uma visualização de propriedade do Twenty.
<Warning>
As visualizações de sistema e suas colunas são **de propriedade do servidor**: resolva seus identificadores
para referenciá‑las, nunca para declará‑las. `key` em
[`defineView()`](/l/pt/developers/extend/apps/layout/views) está obsoleto e
é ignorado, portanto uma visualização de manifesto nunca pode reivindicar a chave `INDEX`, e o servidor
já provisiona uma coluna para cada campo que você adiciona, então declarar seu próprio
`defineViewField()` para esse mesmo campo em uma visualização de sistema entra em conflito com ela.
</Warning>
## Objetos Padrão do Twenty
Para um objeto **padrão** do Twenty (Person, Company, Opportunity, …), você não precisa derivar nada: os identificadores são constantes pré‑computadas que você pode importar diretamente, tanto para campos quanto para visualizações.
```ts
import { STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
// STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.createdAt.universalIdentifier
// STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.fields.updatedAt.universalIdentifier
// STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.views.allPeople.universalIdentifier
```
Use os helpers acima quando o objeto for um que **seu app** define com [`defineObject()`](/l/pt/developers/extend/apps/data/objects), em que não existe tal constante.
<Note>
`name` é um campo **padrão**, não um campo de sistema. Ele mantém seu próprio identificador universal
hardcoded e não é resolvido por meio de
`getFieldUniversalIdentifier`. Em objetos que você define, referencie o campo
`name` pelo identificador que você atribuiu a ele em `defineObject()`.
</Note>