snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
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 3s

This commit is contained in:
upstream-mirror
2026-09-17 23:28:13 +05:00
commit e7da97194a
32688 changed files with 4208681 additions and 0 deletions

View File

@@ -0,0 +1,121 @@
---
title: Resposta automática a e-mails de entrada
description: Crie um fluxo de trabalho que use IA para fazer a triagem dos e-mails de entrada e enviar respostas encadeadas automaticamente.
---
Responda a e-mails de entrada em segundos — não em horas. Este fluxo de trabalho usa um Agente IA para filtrar ruído (boletins informativos, spam, respostas automáticas) e rascunhar uma resposta personalizada para mensagens reais. Então, AI o envia como uma resposta em tópico dentro da conversa original.
## Como funciona o encadeamento de e-mails
Cada e-mail contém um cabeçalho oculto `Message-ID` — uma impressão digital única atribuída pelo servidor de e-mail do remetente. Quando você responde a um e-mail, seu cliente de e-mail define um cabeçalho `In-Reply-To` que faz referência a essa impressão digital. É assim que o Gmail, o Outlook e todos os outros clientes agrupam as mensagens em conversas.
No Twenty, essa impressão digital é armazenada como `headerMessageId` no objeto Message. Seu fluxo de trabalho obtém isso e o passa para o campo In-Reply-To da ação Enviar e-mail.
## Criando o fluxo de trabalho
### Etapa 1: Criar um novo fluxo de trabalho
Vá para **Configurações -> Fluxos de trabalho** e clique em **+ Novo fluxo de trabalho**.
### Etapa 2: Acionar com mensagens recebidas
Escolha **When a Record is Created** e selecione **Messages**.
Sempre que um e-mail chega ao Twenty, isto é acionado.
<img src="/images/user-guide/workflows/auto-reply/workflow-overview.png" style={{width:'100%'}} />
### Etapa 3: Procurar quem enviou
Adicione uma ação **Pesquisar Registros**.
O endereço do remetente não está na própria mensagem — está no registro relacionado Message Participant.
| Campo | Valor |
| ---------- | ------------------------------ |
| **Objeto** | Participantes da Mensagem |
| **Filtro** | Message **é** `{{trigger.id}}` |
| **Filtro** | Função **é** From |
| **Limite** | 1 |
Isso fornece o e-mail do remetente em `handle` e o nome dele em `displayName`.
<img src="/images/user-guide/workflows/auto-reply/find-sender.png" style={{width:'100%'}} />
### Passo 4: Triage e rascunhar uma resposta com IA
Adicione uma ação **Agente de IA**. Esta única etapa faz duas coisas: decide se o e-mail merece uma resposta e, se sim, redige uma.
Use um prompt como:
```
You are an email triage assistant for a sales team. Read the following
inbound email and decide if it deserves a reply.
Subject: {{trigger.subject}}
Body: {{trigger.text}}
From: {{Find Sender.first.displayName}} ({{Find Sender.first.handle}})
If this email is spam, a newsletter, an automated notification, or
otherwise does not need a human reply, respond with exactly: SKIP
Otherwise, write a short, professional reply (3-4 sentences max) that:
- Acknowledges their specific message
- Lets them know someone from the team will follow up shortly
- Is warm but not overly casual
Respond with only the reply text, no subject line or greeting prefix.
```
O Agente de IA produz sua resposta em um campo `response` ao qual as próximas etapas podem se referir.
<img src="/images/user-guide/workflows/auto-reply/ai-triage.png" style={{width:'100%'}} />
### Etapa 5: Ramificar com base na decisão da IA
Adicione uma ação **If/Else** para verificar se a IA decidiu responder ou pular.
| Campo | Valor |
| ------------------ | -------------------------------------------------- |
| **Condição** | A `response` do Agente de IA **não contém** `SKIP` |
| **Se verdadeiro** | Continuar para Enviar e-mail |
| **Caso contrário** | Não fazer nada (o fluxo de trabalho termina) |
Spam, boletins informativos e mensagens geradas automaticamente são descartados. Todo o restante segue para a próxima etapa.
<img src="/images/user-guide/workflows/auto-reply/should-reply.png" style={{width:'100%'}} />
### Etapa 6: Enviar uma resposta encadeada
Adicione uma ação **Enviar e-mail** no ramo "se verdadeiro". Clique em **Opções avançadas** e depois em **Adicionar In-Reply-To**.
| Campo | Valor |
| --------------- | -------------------------------------- |
| **Para** | `{{Find Sender.first.handle}}` |
| **Assunto** | `Re: {{trigger.subject}}` |
| **Corpo** | `{{AI Triage & Draft Reply.response}}` |
| **In-Reply-To** | `{{trigger.headerMessageId}}` |
O campo In-Reply-To é o que faz disso uma resposta em vez de uma nova conversa. O destinatário a vê encadeada sob o e-mail original no Gmail, Outlook ou qualquer outro cliente.
<img src="/images/user-guide/workflows/auto-reply/send-email.png" style={{width:'100%'}} />
<Tip>
**In-Reply-To** espera um `message.headerMessageId` do acionador — é a impressão digital única do e-mail, não um endereço do destinatário. Se você deixá-lo vazio, o e-mail ainda será enviado, apenas como uma mensagem independente.
</Tip>
<Warning>
O Gmail usa a linha de assunto para agrupar mensagens em conversas. O assunto **deve** começar com `Re:` (incluindo os dois-pontos e o espaço) para que o Gmail exiba a resposta dentro da conversa original. Sem isso, a resposta aparecerá como uma conversa separada — mesmo que o cabeçalho In-Reply-To esteja definido corretamente.
</Warning>
### Etapa 7: Testar e ativar
Clique em **Test** e, em seguida, verifique seu cliente de e-mail. A resposta deve aparecer aninhada sob a mensagem original.
Ative quando estiver satisfeito com isso.
## Ideias para desenvolver
* **Responder apenas a VIPs** — adicione um ramo que verifique o domínio do remetente ou se ele existe como um Contato no Twenty
* **Roteie por intenção** — use prompts separados do Agente de IA para lidar com consultas de vendas de forma diferente de solicitações de suporte
* **Enriquecer antes de responder** — adicione uma etapa Pesquisar Registros para trazer a empresa do remetente ou o histórico de negócios para o prompt de IA, obtendo respostas mais personalizadas

View File

@@ -0,0 +1,179 @@
---
title: Automatizações para Closed Won
description: Automatize as atividades pós-ganho quando as oportunidades forem encerradas.
---
Quando um negócio é encerrado, várias coisas precisam acontecer: atualizar o status da empresa, notificar os membros da equipe, criar tarefas de onboarding. Automatize tudo isso com um único fluxo de trabalho.
## O Problema
Quando uma oportunidade passa para "Closed Won":
* O tipo de empresa precisa mudar de "Prospect" para "Customer"
* Tarefas de onboarding precisam ser criadas
* A equipe de Customer Success precisa ser notificada
* O representante de vendas precisa de confirmação
Fazer isso manualmente consome tempo e é suscetível a erros.
## A Solução
Crie um fluxo de trabalho que trate automaticamente todas as atividades pós-ganho.
## Configuração Completa do Fluxo de Trabalho
### Etapa 1: Criar o fluxo de trabalho
1. Vá para **Configurações → Fluxos de trabalho**
2. Clique em **+ Novo fluxo de trabalho**
3. Nomeie como "Deal Won - Post-Win Automation"
### Etapa 2: Configurar o gatilho
1. Selecione **Record is Updated**
2. Escolha **Oportunidades**
3. Em "Campos para monitorar", selecione **Estágio**
### Etapa 3: Adicionar filtro de estágio
1. Adicione a ação **Filtro**
2. Condição: `{{trigger.object.stage}}` é igual a "Closed Won"
### Etapa 4: Atualizar o tipo de empresa
1. Adicione a ação **Atualizar registro**
2. Configurar:
| Campo | Valor |
| ---------------------------- | ------------------------------- |
| **Objeto** | Empresas |
| **Registro** | `{{trigger.object.company.id}}` |
| **Tipo** | Cliente |
| **Data do primeiro negócio** | `{{trigger.object.closedAt}}` |
| **Proprietário da Conta** | `{{trigger.object.owner.id}}` |
### Etapa 5: Criar tarefa de onboarding
1. Adicione a ação **Criar registro**
2. Configurar:
| Campo | Valor |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------- |
| **Objeto** | Tarefas |
| **Título** | `Onboarding: {{trigger.object.name}}` |
| **Responsável** | Membro da equipe de Customer Success |
| **Data de vencimento** | Daqui a 3 dias |
| **Prioridade** | Alta |
| **Empresa relacionada** | `{{trigger.object.company.id}}` |
| **Oportunidade relacionada** | `{{trigger.object.id}}` |
| **Descrição** | `Onboarding de novo cliente para {{trigger.object.company.name}}. Valor do negócio: {{trigger.object.amount}}` |
### Etapa 6: Notificar Customer Success
1. Adicione a ação **Enviar e-mail**
2. Configurar:
| Campo | Valor |
| ----------- | -------------------------------------------------- |
| **Para** | customer-success@yourcompany.com |
| **Assunto** | `🎉 New Customer: {{trigger.object.company.name}}` |
| **Corpo** | Veja o exemplo abaixo |
**Exemplo de corpo do e-mail**:
```
Hi CS Team,
We have a new customer!
Company: {{trigger.object.company.name}}
Deal: {{trigger.object.name}}
Value: {{trigger.object.amount}}
Sales Rep: {{trigger.object.owner.name}}
Close Date: {{trigger.object.closedAt}}
An onboarding task has been created automatically.
Let's give them a great start!
```
### Etapa 7: Confirmar para o representante de vendas
1. Adicione outra ação **Enviar e-mail**
2. Configurar:
| Campo | Valor |
| ----------- | -------------------------------------------------------------------------------------------------------------- |
| **Para** | `{{trigger.object.owner.email}}` |
| **Assunto** | `✅ Deal Closed: {{trigger.object.name}}` |
| **Corpo** | Parabéns! Seu negócio foi processado. A equipe de Customer Success foi notificada e o onboarding foi iniciado. |
### Etapa 8: Testar e ativar
1. Teste movendo uma oportunidade de teste para "Closed Won"
2. Verificar:
* Tipo de empresa alterado para "Customer"
* Tarefa de onboarding criada
* A equipe de CS recebeu o e-mail
* O representante de vendas recebeu a confirmação
3. Ative quando estiver pronto
## Tratamento de Closed Lost
Crie um fluxo de trabalho semelhante para negócios perdidos:
### Disparador
* Registro é atualizado (Oportunidades, Estágio = "Closed Lost")
### Ações
1. **Criar registro**: Tarefa para "Análise de negócio perdido"
2. **Atualizar registro**: Adicionar o motivo da perda ao registro da empresa
3. **Enviar e-mail**: Notificar o gerente sobre o negócio perdido
## Avançado: Onboarding em várias etapas
Para um onboarding complexo, crie várias tarefas:
```javascript
export const main = async (params) => {
const tasks = [
{ title: "Welcome call", daysFromNow: 1, assignee: "CS" },
{ title: "Send onboarding materials", daysFromNow: 2, assignee: "CS" },
{ title: "Technical setup", daysFromNow: 5, assignee: "Support" },
{ title: "30-day check-in", daysFromNow: 30, assignee: "CS" }
];
return { tasks };
};
```
Use **Iterator** para criar cada tarefa a partir do array.
## Ideias de personalização
### Mantenha suas outras ferramentas atualizadas
* Crie o cliente no sistema de faturamento com uma **Requisição HTTP**
### Ações condicionais
Use ações **Filtro** para:
* Onboarding diferente para enterprise vs. SMB
* Responsáveis diferentes com base na região
* Ignorar notificações para negócios pequenos
### Incluir detalhes da oferta
Use a ação **Código** para formatar:
* Documentos de resumo do negócio
* Notas de repasse para a equipe de CS
* Checklists de onboarding personalizadas
## Relacionados
* [Ações de Fluxo de Trabalho](/l/pt/user-guide/workflows/capabilities/workflow-actions)
* [Enviar e-mails a partir de Fluxos de Trabalho](/l/pt/user-guide/workflows/capabilities/send-emails-from-workflows)

View File

@@ -0,0 +1,136 @@
---
title: Detectar oportunidades estagnadas
description: Notifique automaticamente os gestores quando as oportunidades não tiverem sido atualizadas.
---
Mantenha o seu pipeline saudável alertando os gestores quando as oportunidades ficarem estagnadas. Este fluxo de trabalho verifica oportunidades que não foram atualizadas há um número específico de dias.
## O Problema
Oportunidades sem atualizações levam a:
* Negócios a arrefecer
* Previsões pouco fiáveis
* Perda de receita
## A Solução
Crie um fluxo de trabalho agendado que encontre oportunidades estagnadas e envie e-mails aos respetivos gestores.
## Configuração passo a passo
### Etapa 1: Criar o fluxo de trabalho
1. Vá para **Configurações → Fluxos de trabalho**
2. Clique em **+ Novo fluxo de trabalho**
3. Dê o nome "Alerta de Oportunidade Estagnada"
### Etapa 2: Configurar o gatilho
1. Selecione **Agendado**
2. Defina para executar diariamente (por exemplo, todos os dias às 08:00)
### Etapa 3: Pesquisar oportunidades estagnadas
1. Adicione a ação **Pesquisar Registos**
2. Configurar:
| Campo | Valor |
| ---------- | --------------------------------------------- |
| **Objeto** | Oportunidades |
| **Filtro** | Atualizado em é anterior a (hoje - 7 dias) |
| **Filtro** | Fase não é "Closed Won" E não é "Closed Lost" |
| **Limite** | 100 |
### Etapa 4: Verificar se algum foi encontrado
1. Adicione a ação **Filtro**
2. Condição: `{{searchRecords.length}}` é maior do que 0
3. Se não houver oportunidades estagnadas, o fluxo de trabalho termina aqui
### Etapa 5: Formatar o alerta (Ação de Código)
Adicione uma ação de **Código** para formatar o e-mail:
```javascript
export const main = async (params) => {
const opportunities = params.opportunities;
// Group opportunities by owner
const byOwner = {};
opportunities.forEach(opp => {
const ownerEmail = opp.owner?.email || 'unassigned';
if (!byOwner[ownerEmail]) {
byOwner[ownerEmail] = [];
}
byOwner[ownerEmail].push({
name: opp.name,
amount: opp.amount,
lastUpdated: opp.updatedAt,
stage: opp.stage
});
});
// Format summary for manager
let summary = "Stale Opportunities Report\n\n";
Object.entries(byOwner).forEach(([owner, opps]) => {
summary += `${owner}: ${opps.length} stale opportunities\n`;
opps.forEach(opp => {
summary += ` - ${opp.name} (${opp.stage})\n`;
});
summary += "\n";
});
return {
summary,
totalCount: opportunities.length
};
};
```
### Etapa 6: Enviar e-mail de alerta
Adicione a ação **Enviar e-mail**:
| Campo | Valor |
| ----------- | --------------------------------------------------------------------- |
| **Para** | sales-manager@yourcompany.com |
| **Assunto** | `🚨 {{code.totalCount}} oportunidades estagnadas precisam de atenção` |
| **Corpo** | `{{code.summary}}` |
### Etapa 7: Testar e ativar
1. Clique em **Testar** para executar o fluxo de trabalho
2. Verifique se o e-mail contém os dados corretos
3. Ative quando estiver pronto
## Opções de personalização
### Alterar o limite de estagnação
Modifique o filtro de Pesquisar Registos para alterar de 7 dias para o período da sua preferência:
* 3 dias para vendas de alto ritmo
* 14 dias para negócios empresariais
* 30 dias para ciclos de vendas longos
### Alertar representantes individualmente
Em vez de um e-mail único para o gestor, use **Iterator** para enviar e-mails personalizados a cada representante sobre os seus próprios negócios estagnados.
### Adicionar escalonamento
Crie vários fluxos de trabalho com gravidade crescente:
1. Dia 7: E-mail para o representante
2. Dia 14: E-mail para o representante + gestor
3. Dia 21: Criar tarefa para o gestor intervir
### Incluir no Slack
Use **HTTP Request** para enviar para um webhook do Slack em vez de ou além do e-mail.
## Relacionados
* [Ações de Fluxo de Trabalho](/l/pt/user-guide/workflows/capabilities/workflow-actions)
* [Enviar e-mails a partir de Fluxos de Trabalho](/l/pt/user-guide/workflows/capabilities/send-emails-from-workflows)

View File

@@ -0,0 +1,69 @@
---
title: Exibir o número de e-mails recebidos
description: Crie um fluxo de trabalho para contar e exibir automaticamente o número de e-mails recebidos de cada contato.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<img src="/images/user-guide/workflows/workflow-number-of-emails-received.png" style={{width:'100%'}} />
## Visão Geral
Esse fluxo de trabalho é acionado sempre que um novo e-mail é recebido e atualiza um campo personalizado no registro de Pessoa com a contagem total de e-mails desse remetente.
## Pré-requisitos
Antes de configurar esse fluxo de trabalho, crie um campo personalizado no objeto **Pessoas**:
1. Vá para **Configurações → Modelo de Dados → Pessoas**
2. Adicione um novo campo **Número**
3. Dê a ele um nome como "Número de e-mails recebidos desta pessoa"
## Configuração passo a passo
<VimeoEmbed videoId="1148700336" title="Demonstração em vídeo" />
### Etapa 1: Configurar o gatilho
1. Vá para **Fluxos de Trabalho** e crie um novo fluxo de trabalho
2. Selecione **Registro é criado** como o gatilho
3. Escolha **Participantes da Mensagem** (disponível em Objetos avançados)
<Note>
Um Participante da Mensagem é a combinação de um ID de mensagem e um ID de pessoa, criando um registro exclusivo por mensagem. Isso é mais fácil de acompanhar do que Mensagens diretamente porque podemos acessar o campo `handle`, que contém o endereço de e-mail do remetente (ou do destinatário).
</Note>
### Etapa 2: Filtrar por função
1. Adicione a ação **Filtro**
2. Defina a condição: **Role** igual a **FROM**
Isso garante que você conte apenas as mensagens enviadas por essa pessoa, e não as mensagens enviadas para ela.
### Etapa 3: Pesquisar todos os Participantes da Mensagem com o mesmo handle
1. Adicione a ação **Pesquisar Registros**
2. Selecione **Participantes da Mensagem** como o objeto
3. Adicione filtros: **Handle** igual ao handle do gatilho (o endereço de e-mail do remetente) e **Role** igual a **FROM**
4. Aumente o **Limite** de 1 para **200** (o máximo)
Isso encontra todas as mensagens desse endereço de e-mail para obter a contagem total.
<Note>
A ação Pesquisar Registros é limitada a retornar no máximo 200 registros. No entanto, como você está usando apenas o valor `totalCount` (não os registros individuais), esta etapa retornará o número total de e-mails enviados por essa pessoa.
</Note>
### Etapa 4: Atualizar o registro de Pessoa com uma ação Criar ou Atualizar Registro
1. Adicione a ação **Criar ou Atualizar Registro**
2. Selecione **Pessoas** como o objeto
3. Encontre a pessoa cujo e-mail corresponde ao `handle` do Participante da Mensagem
4. Defina seu campo personalizado "Número de e-mails recebidos" como `{{searchRecords.totalCount}}`
O valor `totalCount` da ação Pesquisar Registros representa o número total de e-mails recebidos dessa pessoa.
## Relacionados
* [Ações de Fluxo de Trabalho](/l/pt/user-guide/workflows/capabilities/workflow-actions)
* [Criar campos personalizados](/l/pt/user-guide/data-model/how-tos/customize-your-data-model)
* [Ação Pesquisar Registros](/l/pt/user-guide/workflows/capabilities/workflow-actions#search-records)

View File

@@ -0,0 +1,170 @@
---
title: Apresentar dados de registos relacionados
description: Mostrar dados de registos relacionados (por exemplo, informações da Empresa em Oportunidades) usando fluxos de trabalho.
---
Apresente dados de registos relacionados diretamente nos seus registos — por exemplo, mostre o número de funcionários de uma Empresa nas suas Oportunidades. Esta solução alternativa com fluxos de trabalho é útil até que os campos aninhados estejam disponíveis nativamente.
## Casos de Uso Comuns
| Fonte | Destino | Campos a Copiar |
| ------------ | ------------ | ------------------------------------------------------- |
| Empresa | Oportunidade | Setor, Tamanho da Empresa, ARR |
| Pessoa | Oportunidade | Email, Telefone, Cargo |
| Oportunidade | Empresa | Valor do Último Negócio, Data do Último Negócio Ganhado |
## Cópia Básica de Campo
### Exemplo: Copiar Email do Contacto para a Oportunidade
**Objetivo**: Ao definir um Ponto de Contacto numa oportunidade, copiar o email dessa pessoa para a oportunidade para acesso facilitado.
### Pré-requisito
Crie os campos de destino em **Definições → Modelo de Dados → Oportunidades** antes de construir o fluxo de trabalho:
* Email do Contacto (tipo: Email)
* Telefone do Contacto (tipo: Telefone)
### Configuração
1. **Gatilho**: Registo é atualizado (Oportunidades, campo Ponto de Contacto)
2. **Filtro**: Verificar que o Ponto de Contacto não está vazio
3. **Pesquisar Registos**: Encontrar a pessoa associada
* Objeto: Pessoas
* Filtro: ID igual a `{{trigger.object.pointOfContact.id}}`
4. **Atualizar Registo**:
* Objeto: Oportunidades
* Registo: `{{trigger.object.id}}`
* Email do Contacto: `{{searchRecords[0].email}}`
* Telefone do Contacto: `{{searchRecords[0].phone}}`
## Copiar Vários Campos
### Exemplo: Sincronizar Informações da Empresa com Todas as Oportunidades Relacionadas
**Objetivo**: Quando os detalhes da empresa mudarem, atualizar todas as oportunidades relacionadas.
### Configuração
1. **Gatilho**: Registo é atualizado (Empresas)
* Campos: Setor, Tamanho da Empresa, Receita Anual
2. **Pesquisar Registos**: Encontrar todas as oportunidades desta empresa
* Objeto: Oportunidades
* Filtro: ID da Empresa igual a `{{trigger.object.id}}`
3. **Iterador**: Percorrer cada oportunidade
4. **Atualizar Registo** (dentro do iterador):
* Objeto: Oportunidades
* Registo: `{{iterator.currentItem.id}}`
* Setor da Empresa: `{{trigger.object.industry}}`
* Tamanho da Empresa: `{{trigger.object.companySize}}`
* ARR da Empresa: `{{trigger.object.annualRevenue}}`
## Copiar na Criação do Registo
### Exemplo: Preencher a Oportunidade com Dados da Empresa
**Objetivo**: Ao criar uma oportunidade vinculada a uma empresa, copiar automaticamente as informações principais da empresa.
### Pré-requisito
Crie os campos de destino em **Definições → Modelo de Dados → Oportunidades**:
* Setor da Empresa (tipo: Texto)
* Tamanho da Empresa (tipo: Número)
### Configuração
1. **Gatilho**: Registo é criado (Oportunidades)
* Filtro: Empresa não está vazia
2. **Pesquisar Registos**: Obter os detalhes da empresa associada
* Objeto: Empresas
* Filtro: ID igual a `{{trigger.object.company.id}}`
3. **Atualizar Registo**:
* Objeto: Oportunidades
* Registo: `{{trigger.object.id}}`
* Setor da Empresa: `{{searchRecords[0].industry}}`
* Tamanho da Empresa: `{{searchRecords[0].employees}}`
<Note>
**Limitação de Tarefas e Notas**: As relações em Tarefas e Notas são pré-definidas como muitos-para-muitos e ainda não estão disponíveis em gatilhos ou ações de fluxos de trabalho. Para aceder a estas relações, use antes a [API](/l/pt/developers/extend/api).
</Note>
## Sincronização Bidirecional
### Exemplo: Manter o Contacto Principal Sincronizado
**Objetivo**: Quando o contacto principal de uma empresa mudar, atualizar o contacto. Quando uma pessoa se tornar principal, atualizar a empresa.
### Fluxo de Trabalho 1: Empresa → Pessoa
1. **Gatilho**: Registo é atualizado (Empresas, campo Contacto Principal)
2. **Atualizar Registo**: Definir "É Contacto Principal" da pessoa como verdadeiro
3. **Pesquisar Registos**: Encontrar o contacto principal anterior
4. **Atualizar Registo**: Definir "É Contacto Principal" do contacto anterior como falso
### Fluxo de Trabalho 2: Pessoa → Empresa
1. **Gatilho**: Registo é atualizado (Pessoas, É Contacto Principal = verdadeiro)
2. **Atualizar Registo**: Definir o Contacto Principal da empresa para esta pessoa
<Note>
Tenha cuidado com sincronizações bidirecionais para evitar ciclos infinitos. Use filtros para verificar se o valor realmente mudou antes de atualizar.
</Note>
## Usar Código para Mapeamento Complexo
### Exemplo: Transformar Dados Durante a Cópia
**Objetivo**: Copiar e formatar o número de telefone da pessoa para a oportunidade.
```javascript
export const main = async (params) => {
const { phone } = params;
if (!phone) return { formattedPhone: null };
// Remove non-numeric characters
const digits = phone.replace(/\D/g, '');
// Format as (XXX) XXX-XXXX
const formatted = digits.length === 10
? `(${digits.slice(0,3)}) ${digits.slice(3,6)}-${digits.slice(6)}`
: phone;
return { formattedPhone: formatted };
};
```
## Melhores Práticas
### Evitar Ciclos
* Não crie fluxos de trabalho que disparem uns aos outros indefinidamente
* Use condições específicas de campo
* Adicione verificações para ver se o valor realmente mudou
### Tratar Dados em Falta
* Verifique sempre se o registo de origem existe antes de copiar
* Forneça valores predefinidos para campos opcionais
* Use filtros para ignorar quando o campo de origem estiver vazio
### Desempenho
* Agrupe atualizações ao copiar para muitos registos
* Use fluxos de trabalho agendados para operações de sincronização em massa
* Considere usar o Iterador para atualizações de múltiplos registos
## Relacionados
* [Ações de Fluxo de Trabalho](/l/pt/user-guide/workflows/capabilities/workflow-actions)
* [Gatilhos de Fluxo de Trabalho](/l/pt/user-guide/workflows/capabilities/workflow-triggers)

View File

@@ -0,0 +1,202 @@
---
title: Campos de Fórmula
description: Crie campos de fórmula usando fluxos de trabalho até que o suporte nativo esteja disponível.
---
A Twenty ainda não oferece suporte nativo a campos de fórmula (chegando em 2026), mas você pode obter o mesmo resultado usando fluxos de trabalho. Esta solução alternativa permite calcular e preencher automaticamente os valores dos campos — de concatenações simples a lógica de negócios complexa.
## Casos de Uso Comuns
| Caso de uso | Exemplo de fórmula |
| ------------------------- | ----------------------------------- |
| **Nome completo** | Nome + " " + Sobrenome |
| **Valor esperado** | Valor × Probabilidade |
| **Dias até o vencimento** | Data de vencimento - hoje |
| **Dias na etapa** | Hoje - Data de entrada na etapa |
| **Pontuação de lead** | Pontos com base em vários critérios |
<Tip>
Para um exemplo completo de rastreamento do tempo nas etapas do pipeline, consulte [Acompanhar por quanto tempo as oportunidades permanecem em cada etapa](/l/pt/user-guide/views-pipelines/how-tos/track-time-in-stage).
</Tip>
## Fórmula básica: Concatenação
### Exemplo: Preencher automaticamente o nome completo
**Objetivo**: Combinar automaticamente nome e sobrenome em um campo de nome completo.
### Configuração
1. **Gatilho**: Registro é atualizado ou criado (Pessoas)
2. **Filtro**: Verifique se o nome ou o sobrenome foi alterado
3. **Ação de código**:
```javascript
export const main = async (params) => {
const { firstName, lastName } = params;
const fullName = [firstName, lastName]
.filter(Boolean)
.join(' ');
return { fullName };
};
```
4. **Atualizar registro**: Definir Nome completo como `{{code.fullName}}`
## Fórmula numérica: Valor esperado
### Exemplo: Calcular a receita esperada
**Objetivo**: Multiplicar o valor da oportunidade pela probabilidade para obter o valor esperado.
Consulte [Como mostrar o valor esperado no pipeline](/l/pt/user-guide/views-pipelines/how-tos/show-expected-amount-in-pipeline) para o fluxo de trabalho completo.
### Configuração
1. **Gatilho**: Registro é atualizado (Oportunidades, campo Valor OU Probabilidade)
2. **Ação de código**:
```javascript
export const main = async (params) => {
const { amount, probability } = params;
const expectedAmount = (amount || 0) * (probability || 0) / 100;
return { expectedAmount };
};
```
3. **Atualizar registro**: Definir Valor esperado como `{{code.expectedAmount}}`
## Fórmula de data: Cálculo de dias
### Exemplo: Dias até o vencimento da tarefa
**Objetivo**: Calcular quantos dias faltam até a data de vencimento de uma tarefa.
### Configuração
1. **Gatilho**: Registro é atualizado ou criado (Tarefas, campo Data de vencimento)
2. **Ação de código**:
```javascript
export const main = async (params) => {
const { dueDate } = params;
if (!dueDate) {
return { daysUntilDue: null };
}
const due = new Date(dueDate);
const today = new Date();
const diffTime = due - today;
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return { daysUntilDue: diffDays };
};
```
3. **Atualizar registro**: Definir Dias até o vencimento como `{{code.daysUntilDue}}`
<Note>
Valores negativos indicam tarefas em atraso. Você pode usar este campo para filtrar ou classificar tarefas por urgência.
</Note>
## Fórmula condicional: Pontuação de lead
### Exemplo: Calcular a pontuação de lead com base em critérios
**Objetivo**: Pontuar leads com base no porte da empresa, setor e engajamento.
### Configuração
1. **Gatilho**: Registro é atualizado (Pessoas ou Empresas)
2. **Ação de código**:
```javascript
export const main = async (params) => {
const { companySize, industry, hasEmail, hasPhone, source } = params;
let score = 0;
// Company size scoring
if (companySize === 'Enterprise') score += 30;
else if (companySize === 'Mid-Market') score += 20;
else if (companySize === 'SMB') score += 10;
// Industry scoring
const targetIndustries = ['Technology', 'Finance', 'Healthcare'];
if (targetIndustries.includes(industry)) score += 25;
// Contact info scoring
if (hasEmail) score += 10;
if (hasPhone) score += 15;
// Source scoring
if (source === 'Referral') score += 20;
else if (source === 'Website') score += 10;
return { leadScore: score };
};
```
3. **Atualizar registro**: Definir Pontuação de lead como `{{code.leadScore}}`
## Fórmula de texto: Extração de domínio
### Exemplo: Extrair domínio do e-mail
**Objetivo**: Extrair e armazenar automaticamente o domínio do e-mail.
### Configuração
1. **Gatilho**: Registro é atualizado (Pessoas, campo E-mail)
2. **Ação de código**:
```javascript
export const main = async (params) => {
const { email } = params;
if (!email) return { domain: null };
const domain = email.split('@')[1]?.toLowerCase();
return { domain };
};
```
3. **Atualizar registro**: Definir o campo Domínio como `{{code.domain}}`
## Melhores Práticas
### Desempenho
* Acione apenas em alterações de campos relevantes
* Use filtros para ignorar registros que não precisam de cálculo
* Evite cálculos complexos em fluxos de trabalho de alto volume
### Tratamento de Erros
* Verifique valores null/undefined antes dos cálculos
* Use valores padrão quando faltarem dados
* Retorne mensagens de erro claras quando os cálculos falharem
### Testes
* Teste com casos extremos (campos vazios, valores zero)
* Verifique os cálculos manualmente antes de ativar
* Monitore as execuções de fluxos de trabalho para resultados inesperados
## Relacionados
* [Como mostrar o valor esperado no pipeline](/l/pt/user-guide/views-pipelines/how-tos/show-expected-amount-in-pipeline)
* [Como acompanhar o tempo na etapa](/l/pt/user-guide/views-pipelines/how-tos/track-time-in-stage)
* [Ações de Fluxo de Trabalho](/l/pt/user-guide/workflows/capabilities/workflow-actions)

View File

@@ -0,0 +1,127 @@
---
title: Notificar colegas de equipe sobre uma nota para revisão
description: Envie notificações automáticas por e-mail ao atribuir um colega para revisar uma nota.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<Note>
**Marcar colegas diretamente nas notas ainda não é suportado.** Esse recurso está planejado para o segundo semestre de 2026. Enquanto isso, este fluxo de trabalho oferece uma solução alternativa prática.
</Note>
## O desafio
Você quer marcar um colega em uma nota para que receba uma notificação para revisá-la. Hoje, a Twenty não oferece suporte a @mentions em notas ou tarefas.
## A solução alternativa
Em vez de marcar no texto da nota, você pode:
1. Crie um campo de relação **Revisor** no objeto Notas
2. Atribua o revisor ao criar ou editar a nota
3. Ter um fluxo de trabalho automaticamente enviar um e-mail ao revisor com um link para a nota
<Warning>
**Limitação**: Esta abordagem permite atribuir um revisor por campo. Se você precisar notificar várias pessoas, crie campos de relação adicionais (por exemplo, Revisor 1, Revisor 2). Isso não escala bem se você precisar marcar muitos colaboradores de uma só vez.
</Warning>
## Configuração passo a passo
### Etapa 1: Criar o campo Revisor
<img src="/images/user-guide/workflows/reviewer-field-for-note.png" style={{width:'100%'}} />
1. Vá para **Configurações → Modelo de Dados → Notas**
2. Clique em **Adicionar campo**
3. Configurar:
| Configuração | Valor |
| ---------------------- | ---------------------------------------------- |
| **Nome** | Revisor |
| **Tipo** | Relação |
| **Objeto Relacionado** | Membro do Workspace |
| **Tipo de Relação** | Muitas Notas → Um Membro do Espaço de Trabalho |
4. Salve o campo
### Etapa 2: Criar o fluxo de trabalho
<VimeoEmbed videoId="1151897168" title="Demonstração em vídeo" />
#### Criar o gatilho do fluxo de trabalho
1. Vá para a visualização principal e crie um novo fluxo de trabalho
2. Selecione **Registro atualizado** como o gatilho
3. Escolha **Nota** como o objeto e especifique o campo Revisor.
4. Isso será acionado sempre que o revisor de uma nota for atualizado.
#### Adicione um filtro para verificar se o revisor acabou de ser atribuído
Adicione uma ação de **Filtro** para garantir que o fluxo de trabalho só continue quando um revisor for atribuído:
| Condição | Valor |
| ----------- | -------------- |
| **Revisor** | não está vazio |
#### Pesquisar o Membro do Espaço de Trabalho
1. Adicione uma ação **Pesquisar Registros**
2. Selecione **Membro do Espaço de Trabalho** (em Objetos Avançados)
3. Adicione um filtro:
| Condição | Valor |
| -------- | ------------------------------- |
| **ID** | é igual a `{{note.reviewerId}}` |
Isso recupera o registro completo do membro do espaço de trabalho, incluindo seu endereço de e-mail e nome.
#### Enviar o e-mail de notificação
1. Adicione uma ação **Enviar e-mail**
2. Configurar:
| Campo | Valor |
| ----------- | -------------------------------------------------------------------------------- |
| **Para** | Registro de pesquisa → Primeiro Membro do Espaço de Trabalho → E-mail do usuário |
| **Assunto** | Uma nota precisa da sua revisão |
| **Corpo** | Veja o exemplo abaixo |
**Exemplo de corpo do e-mail:**
```text
Hi {{searchRecord.firstWorkspaceMember.name.firstName}},
You've been assigned to review a note.
View the note here:
https://yourSubDomain.twenty.com/object/note/{{recordIsUpdated.id}}
Best,
Twenty
```
<Note>
Substitua `yourSubDomain` pelo subdomínio real do seu espaço de trabalho Twenty.
</Note>
#### Testar e ativar
1. Clique em **Testar** para executar o fluxo de trabalho manualmente
2. Crie ou edite uma nota e atribua um revisor
3. Verifique a caixa de entrada do revisor para o e-mail de notificação
4. Ative o fluxo de trabalho
## Uso
Depois de configurado, sua equipe pode usar este fluxo de trabalho:
1. Criando uma nova nota (ou editando uma existente)
2. Selecionando um colega no campo **Revisor**
3. O colega recebe automaticamente um e-mail com um link direto para a nota
## Relacionados
* [Gatilhos de Fluxo de Trabalho](/l/pt/user-guide/workflows/capabilities/workflow-triggers)
* [Enviar e-mails a partir de Fluxos de Trabalho](/l/pt/user-guide/workflows/capabilities/send-emails-from-workflows)
* [Criar campos personalizados](/l/pt/user-guide/data-model/how-tos/create-custom-fields)
* [Criar campos de relação](/l/pt/user-guide/data-model/how-tos/create-relation-fields)

View File

@@ -0,0 +1,106 @@
---
title: Enviar alertas por e-mail sobre tarefas com vencimento
description: Notifique automaticamente os membros da equipe sobre suas tarefas próximas ou em atraso.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<img src="/images/user-guide/workflows/email_tasks_due.png" style={{width:'100%'}} />
Envie lembretes diários por e-mail para cada membro da equipe sobre suas tarefas com vencimento hoje.
## Visão Geral
Este fluxo de trabalho é executado conforme um cronograma e:
1. Busca todos os membros do espaço de trabalho
2. Percorre cada membro
3. Localiza suas tarefas com vencimento hoje
4. Formata e envia um e-mail personalizado
## Configuração passo a passo
<VimeoEmbed videoId="1147463514" title="Demonstração em vídeo" />
### Etapa 1: Configurar o gatilho
1. Vá até **Configurações → Fluxos de Trabalho** e crie um novo fluxo de trabalho
2. Selecione **Agendado** como o gatilho
3. Use uma expressão cron para executar diariamente às 8:00: `0 8 * * *`
### Etapa 2: Pesquisar todos os membros do espaço de trabalho
1. Adicione a ação **Pesquisar Registros**
2. Selecione **Membros do Espaço de Trabalho** (em objetos avançados)
3. Não são necessários filtros — isso retorna todos os membros
### Etapa 3: Adicionar um Iterador
1. Adicione a ação **Iterador**
2. Defina o array de entrada como os membros do espaço de trabalho da etapa anterior
3. Todas as ações dentro do iterador serão executadas uma vez por membro
### Etapa 4: Pesquisar tarefas com vencimento hoje (dentro do iterador)
1. Dentro do iterador, adicione a ação **Pesquisar Registros**
2. Selecione **Tarefas** como o objeto
3. Adicione filtros:
* **Responsável** = membro atual do espaço de trabalho (do iterador)
* **Data de vencimento** = hoje
### Etapa 5: Formatar as tarefas no corpo do e-mail (dentro do iterador)
Adicione uma ação **Código** para formatar as tarefas em uma lista legível com links:
```javascript
export const main = async (params: {
tasksDue?: Array<{ id: string; title: string }> | null | string;
}) => {
const tasksDue =
typeof params.tasksDue === "string"
? JSON.parse(params.tasksDue)
: params.tasksDue;
if (!Array.isArray(tasksDue) || tasksDue.length === 0) {
return {
formattedTasks: "No tasks due today."
};
}
const formattedTasks = tasksDue
.map(
t =>
`${t.title}\nhttps://yourSubDomain.twenty.com/object/task/${t.id}`
)
.join("\n\n");
return { formattedTasks };
};
```
<Note>
Substitua `yourSubDomain` pelo subdomínio real do seu espaço de trabalho Twenty.
</Note>
### Etapa 6: Enviar E-mail (dentro do iterador)
1. Adicione a ação **Enviar E-mail** (ainda dentro do iterador)
2. Configurar:
| Campo | Valor |
| ----------- | ----------------------------------------------------------------------------- |
| **Para** | `{{iterator.currentItem.userEmail}}` (e-mail do membro do espaço de trabalho) |
| **Assunto** | Suas tarefas com vencimento hoje |
| **Corpo** | `{{code.formattedTasks}}` |
### Etapa 7: Testar e ativar
1. Clique em **Testar** para executar o fluxo de trabalho manualmente
2. Verifique as caixas de entrada para os e-mails
3. Ative o fluxo de trabalho
## Relacionados
* [Ações de Fluxo de Trabalho](/l/pt/user-guide/workflows/capabilities/workflow-actions)
* [Enviar e-mails a partir de Fluxos de Trabalho](/l/pt/user-guide/workflows/capabilities/send-emails-from-workflows)
* [Lidar com arrays em ações de código](/l/pt/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions)