> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Guia de design de workflows

> Projete workflows do Flowker: tipos de nó, arestas, padrões reais, transições de status e boas práticas para uma orquestração confiável.

Este guia percorre tipos de nó, arestas, padrões reais, transições de status, limites técnicos e boas práticas.

## Tipos de nó

***

Todo workflow é formado por nós. Cada nó tem um `type` que define como o Flowker o processa em tempo de execução.

### trigger

Um nó de gatilho é um ponto de entrada de execução. Workflows em draft podem estar incompletos, mas a ativação exige pelo menos um nó de gatilho.

Os exemplos desta página mostram apenas a topologia dos nós. Um nó de gatilho real também carrega um `triggerType` e a configuração desse gatilho em seu `data`. Veja [Configurando um gatilho de webhook](https://docs.lerian.studio/pt/products/flowker/configuring-a-webhook-trigger.md) ou [Rodando um workflow em um agendamento](https://docs.lerian.studio/pt/products/flowker/running-a-workflow-on-a-schedule.md).

```json theme={null}
{
  "id": "node-trigger",
  "type": "trigger",
  "name": "Payment Received"
}
```

### executor

Chama um serviço externo por meio de uma configuração de provedor. Este nó é o principal ponto de integração para motores antifraude, provedores de pagamento, serviços de notificação e outros sistemas externos.

Os exemplos desta página mostram apenas a topologia dos nós. Um nó executor real também carrega um `providerConfigId` em seu `data`, além de um `executorId` que nomeia o executor do catálogo que ele invoca. Um nó que chama uma operação de um documento OpenAPI enviado omite o `executorId` e carrega `operation_path` e `operation_method` no lugar. Veja o [Guia de integração](https://docs.lerian.studio/pt/products/flowker/integration-guide.md).

```json theme={null}
{
  "id": "node-fraud-check",
  "type": "executor",
  "name": "Check Fraud Score"
}
```

### conditional

Avalia uma condição em relação ao contexto de execução e roteia para ramos diferentes conforme o resultado. Use nós condicionais para implementar lógica de ramificação, por exemplo, roteando para um caminho de aprovação quando o risco é alto, ou seguindo direto quando ele é baixo.

A condição fica no `data.condition` do nó. Uma expressão de texto livre é avaliada como booleano e produz o conector de saída `true` ou `false`. Cada aresta de saída declara qual conector ela segue por meio de `sourceHandle`. Nós condicionais criados no Console usam uma condição estruturada, baseada em casos, na qual cada caso roteia para o próprio conector de saída. Veja o [Editor de canvas](https://docs.lerian.studio/pt/products/flowker/console/canvas-editor.md).

```json theme={null}
{
  "id": "node-risk-decision",
  "type": "conditional",
  "name": "Evaluate Risk Score",
  "data": { "condition": "node-fraud-check.body.riskScore < 70" }
}
```

### action

Representa uma operação interna síncrona `set_output`. Ela pode escrever um valor de saída interpolado e, opcionalmente, substituir o status HTTP da resposta síncrona. Ela não oferece emissão genérica de eventos nem uma operação genérica de mudança de estado.

```json theme={null}
{
  "id": "node-record-approval",
  "type": "action",
  "name": "Record Approval Decision"
}
```

### wait

Pausa a execução por um tempo definido e depois continua com os nós que vêm depois dele. O nó carrega `data.durationSeconds`, um inteiro de 1 a 43200 (12 horas). A espera é só por tempo: ela não espera uma pessoa nem um evento.

```json theme={null}
{
  "id": "wait-1",
  "type": "wait",
  "name": "Wait two minutes",
  "data": { "durationSeconds": 120 }
}
```

Enquanto a execução está parada, o status dela é `waiting`, e as leituras de status e de lista mostram `wait` com o ID do nó e o `deadline`. Ela retoma no prazo ou logo depois. Os nós seguintes leem a saída `{deadline, firedAt}` sob o ID do nó, por exemplo `wait-1.firedAt`.

O Flowker confere estas regras quando você salva o workflow, e cada recusa responde `422`:

| Código | Regra |
| - | - |
| `FLK-0183` | `durationSeconds` é um inteiro de 1 a 43200. |
| `FLK-0184` | Um wait não fica em um ramo que roda ao lado de outro. Acima de um wait, o caminho pode se dividir só em saídas diferentes de um condicional. Um wait depois de um if/else com uma aresta por saída é permitido, e um fan-out depois do wait também. |
| `FLK-0185` | As esperas ao longo de um caminho a partir de um trigger somam no máximo 43200 segundos. Um condicional conta a saída mais longa dele. |
| `FLK-0186` | Um workflow que tem um wait não tem laço. |

Uma execução falha em vez de retomar quando o prazo dela, ou a própria retomada, cai mais de 16 horas depois do início da execução, e quando o workflow mudou nesse meio-tempo. [Desativar](https://docs.lerian.studio/pt/reference/products/flowker/deactivate-workflow.md) o workflow faz falhar as execuções dele em espera. As execuções em andamento terminam. Excluir o workflow tenta fazer falhar as execuções pendentes, em andamento e em espera. Um webhook síncrono que chega a um wait responde `202`. [Obter resultados de uma execução](https://docs.lerian.studio/pt/reference/products/flowker/get-execution-results.md) responde `FLK-0502` até a execução terminar.

## Arestas

***

Arestas conectam nós e definem caminhos de execução. Cada aresta inclui os campos a seguir:

| Campo | Descrição |
| - | - |
| `id` | Identificador único da aresta. |
| `source` | ID do nó de origem. |
| `target` | ID do nó de destino. |
| `sourceHandle` | Conector de saída do nó de origem que esta aresta segue. Obrigatório para rotear a partir de um nó condicional: ele deve corresponder ao resultado do ramo (`true` ou `false` para uma condição de texto livre). |
| `condition` | Campo legado de texto livre mantido por compatibilidade retroativa. O Flowker não o avalia para roteamento. Deixe-o vazio em novos workflows. |
| `label` | Rótulo legível usado para visualização e depuração. |

### Exemplo de aresta

```json theme={null}
{
  "id": "edge-approved",
  "source": "node-risk-decision",
  "target": "node-process-payment",
  "sourceHandle": "true",
  "label": "Approved"
}
```

O roteamento depende do tipo do nó de origem. Um nó condicional avalia o `data.condition` dele e segue todas as arestas de saída cujo `sourceHandle` corresponde ao resultado do ramo. Se nenhuma aresta corresponder, esse ramo termina. Todos os outros tipos de nó seguem todas as arestas de saída quando concluem com sucesso.

O Flowker recusa salvar ou ativar um workflow em que duas ramificações paralelas de uma mesma execução alcançam o mesmo nó (`FLK-0187`), porque esse nó rodaria uma vez por ramificação. Ramificações de saídas diferentes de um condicional podem se juntar de novo. O Flowker também recusa uma aresta que sai de um condicional sem `sourceHandle`, ou por um handle que não é uma das saídas dele (`FLK-0115`), um ID de nó vazio ou usado duas vezes (`FLK-0120`) e um nó cujo tipo não é um dos cinco (`FLK-0121`).

## Transições de status

***

Workflows seguem um ciclo de vida bem definido.

![Diagrama de transição de status do workflow mostrando três estados: draft, active e inactive. Uma seta rotulada 'activate' aponta de draft para active. Uma seta rotulada 'deactivate' aponta de active para inactive. Uma seta rotulada 'draft' aponta de inactive de volta para draft.](https://mintcdn.com/lerian-49cb71fc/vdBt8wfgjsNRO1rf/images/pt/d2/flowker-workflow-status-transitions.svg?fit=max\&auto=format\&n=vdBt8wfgjsNRO1rf\&q=85\&s=d9828dc789f5e48d064e941a3af9d0c5)

* **draft**: o estado inicial. Você pode adicionar nós, editar arestas e mudar a configuração apenas no status `draft`.
* **active**: um workflow que você ativou. O Flowker pode executá-lo. Ele não aceita modificação enquanto está ativo.
* **inactive**: um workflow que você desativou. O Flowker não pode mais executá-lo, mas você pode movê-lo de volta para `draft` para editar.

### Regras

* Você pode ativar apenas um workflow em `draft` (transição: `draft → active`).
* Você pode desativar apenas um workflow `active` (transição: `active → inactive`).
* Você pode mover de volta para draft apenas um workflow `inactive` (transição: `inactive → draft`).
* Tentar uma transição inválida retorna o erro `FLK-0102`.
* Tentar modificar um workflow que não está em `draft` retorna o erro `FLK-0103`.

### Movendo um workflow inativo de volta para draft

Se você desativou um workflow e quer editá-lo de novo, mova-o de volta para `draft` chamando [`POST /v1/workflows/{id}/draft`](https://docs.lerian.studio/pt/reference/products/flowker/move-workflow-to-draft). Isso torna o workflow editável sem precisar cloná-lo.

Use isso quando você desativou um workflow por engano, ou quando quer iterar sobre um workflow existente em vez de criar uma cópia.

> [!NOTE]
>
> Você pode mover para draft apenas workflows inativos. Para modificar um workflow ativo enquanto ele continua rodando, use a abordagem de clone descrita abaixo.

### Iterando com segurança usando clone

Para modificar um workflow ativo, clone-o primeiro. A clonagem cria um novo `draft` a partir de qualquer status, copiando todos os nós e arestas. Você pode então atualizá-lo sem impactar a versão atual.

Use esta abordagem para versionamento em produção.

## Limites técnicos

***

| Limite | Valor | Código de erro |
| - | - | - |
| Máximo de nós por workflow | 100 | `FLK-0113` |
| Máximo de arestas por workflow | 200 | `FLK-0114` |
| Payload máximo de entrada da execução | 1 MB | `FLK-0506` |

Workflows com mais de \~50 nós costumam indicar que o fluxo deveria ser dividido em workflows menores e combináveis.

## Padrões comuns

***

### Sequencial

O padrão mais simples. Os nós executam em uma sequência linear. Use quando cada passo depende do anterior e não precisa de ramificação.

![Padrão de workflow sequencial: um nó de gatilho se conecta a um primeiro nó executor, que se conecta a um segundo nó executor, que se conecta a um terceiro nó executor. Todas as ligações são setas direcionadas simples formando uma linha reta.](https://mintcdn.com/lerian-49cb71fc/vdBt8wfgjsNRO1rf/images/pt/d2/flowker-pattern-sequential.svg?fit=max\&auto=format\&n=vdBt8wfgjsNRO1rf\&q=85\&s=73607c3892907dd0055973e52530ca81)

**Exemplo: orquestração de pagamento**

```json theme={null}
{
  "nodes": [
    { "id": "n1", "type": "trigger",  "name": "Payment Initiated" },
    { "id": "n2", "type": "executor", "name": "Validate Payment Data" },
    { "id": "n3", "type": "executor", "name": "Route to Provider" },
    { "id": "n4", "type": "executor", "name": "Send Confirmation Notification" }
  ],
  "edges": [
    { "id": "e1", "source": "n1", "target": "n2", "label": "Start" },
    { "id": "e2", "source": "n2", "target": "n3", "label": "Valid" },
    { "id": "e3", "source": "n3", "target": "n4", "label": "Routed" }
  ]
}
```

### Ramificação condicional

Um nó `conditional` avalia a condição dele e roteia a execução de acordo. O resultado do ramo seleciona as arestas de saída que o nó segue, combinadas por `sourceHandle`.

![Padrão de workflow com ramificação condicional: um nó de gatilho se conecta a um nó executor, que se conecta a um nó condicional. O nó condicional tem duas setas de saída: uma rotulada 'Path A' apontando para um primeiro nó executor, e outra rotulada 'Path B' apontando para um segundo nó executor.](https://mintcdn.com/lerian-49cb71fc/vdBt8wfgjsNRO1rf/images/pt/d2/flowker-pattern-conditional.svg?fit=max\&auto=format\&n=vdBt8wfgjsNRO1rf\&q=85\&s=9e04bca7fc5e470c47e3677b4ab9527a)

**Exemplo: verificação antifraude**

```json theme={null}
{
  "nodes": [
    { "id": "n1", "type": "trigger",     "name": "Transaction Received" },
    { "id": "n2", "type": "executor",    "name": "Get Fraud Score" },
    {
      "id": "n3",
      "type": "conditional",
      "name": "Evaluate Score",
      "data": { "condition": "n2.body.fraudScore < 70" }
    },
    { "id": "n4", "type": "executor",    "name": "Approve Transaction" },
    { "id": "n5", "type": "executor",    "name": "Reject Transaction" }
  ],
  "edges": [
    { "id": "e1", "source": "n1", "target": "n2", "label": "Start" },
    { "id": "e2", "source": "n2", "target": "n3", "label": "Score received" },
    {
      "id": "e3",
      "source": "n3",
      "target": "n4",
      "sourceHandle": "true",
      "label": "Approved"
    },
    {
      "id": "e4",
      "source": "n3",
      "target": "n5",
      "sourceHandle": "false",
      "label": "Rejected"
    }
  ]
}
```

## Exemplos reais

***

### Verificação antifraude

Uma transação chega, um nó executor obtém a pontuação de fraude e um nó condicional roteia a execução para a aprovação ou a rejeição.

```json theme={null}
{
  "nodes": [
    { "id": "n1", "type": "trigger",     "name": "Transaction Received" },
    { "id": "n2", "type": "executor",    "name": "Get Fraud Score" },
    {
      "id": "n3",
      "type": "conditional",
      "name": "Evaluate Fraud Score",
      "data": { "condition": "n2.body.fraudScore < 70" }
    },
    { "id": "n4", "type": "executor",    "name": "Approve Transaction" },
    { "id": "n5", "type": "executor",    "name": "Reject and Notify" }
  ],
  "edges": [
    { "id": "e1", "source": "n1", "target": "n2", "label": "Start" },
    { "id": "e2", "source": "n2", "target": "n3", "label": "Score received" },
    {
      "id": "e3",
      "source": "n3",
      "target": "n4",
      "sourceHandle": "true",
      "label": "Low risk"
    },
    {
      "id": "e4",
      "source": "n3",
      "target": "n5",
      "sourceHandle": "false",
      "label": "High risk"
    }
  ]
}
```

### Orquestração de pagamento

Um fluxo linear que valida os dados de pagamento recebidos, roteia para o provedor adequado e envia uma confirmação.

```json theme={null}
{
  "nodes": [
    { "id": "n1", "type": "trigger",  "name": "Payment Initiated" },
    { "id": "n2", "type": "executor", "name": "Validate Payment Data" },
    { "id": "n3", "type": "executor", "name": "Route to Payment Provider" },
    { "id": "n4", "type": "executor", "name": "Send Confirmation" }
  ],
  "edges": [
    { "id": "e1", "source": "n1", "target": "n2", "label": "Start" },
    { "id": "e2", "source": "n2", "target": "n3", "label": "Valid" },
    { "id": "e3", "source": "n3", "target": "n4", "label": "Payment routed" }
  ]
}
```

### Onboarding de KYC

Use um workflow para enviar uma verificação de documento a um sistema externo de aprovação. Um nó wait pausa só por um tempo definido: para revisão humana assíncrona, inicie depois uma execução separada de workflow quando o seu sistema de aprovação publicar a decisão dele.

### Fluxo de aprovação manual

Um nó executor envia a solicitação de revisão. Um executor busca a decisão da revisão no sistema externo. Um nó condicional então roteia para o caminho de aprovado ou de rejeitado. Um nó wait pausa por um tempo definido e não espera uma pessoa, então uma decisão humana precisa vir de um sistema externo que o workflow consulta.

```json theme={null}
{
  "nodes": [
    { "id": "n1", "type": "trigger",     "name": "Request Submitted" },
    { "id": "n2", "type": "executor",    "name": "Submit for Review" },
    { "id": "n3", "type": "executor",    "name": "Get Approval Decision" },
    {
      "id": "n4",
      "type": "conditional",
      "name": "Decision Received",
      "data": { "condition": "n3.body.decision == 'approved'" }
    },
    { "id": "n5", "type": "executor",    "name": "Process Approved Request" },
    { "id": "n6", "type": "executor",    "name": "Notify Rejection" }
  ],
  "edges": [
    { "id": "e1", "source": "n1", "target": "n2", "label": "Start" },
    { "id": "e2", "source": "n2", "target": "n3", "label": "Submitted" },
    { "id": "e3", "source": "n3", "target": "n4", "label": "Decision received" },
    {
      "id": "e4",
      "source": "n4",
      "target": "n5",
      "sourceHandle": "true",
      "label": "Approved"
    },
    {
      "id": "e5",
      "source": "n4",
      "target": "n6",
      "sourceHandle": "false",
      "label": "Rejected"
    }
  ]
}
```

## Boas práticas

***

### Convenções de nomes de nós

Use nomes descritivos e orientados a ação, que comuniquem o que o nó faz, não de que tipo ele é.

* **correto**: `Validate Payment Data`, `Get Fraud Score`, `Notify Customer`, `Get Approval Decision`
* **errado**: `executor1`, `conditional node`, `node3`

Bons nomes deixam os workflows legíveis sem abrir a configuração do nó. Eles também aparecem nos registros de execução e nos traces.

### Expressões de condição

O Flowker avalia condições de texto livre em nós condicionais em relação ao contexto de execução, em tempo de execução. Um nó sem mapeamento de saída guarda o envelope da resposta, então uma condição lê um campo da resposta sob `body`. Mantenha as condições simples e explícitas:

* Use comparações diretas de campo: `<nodeId>.body.status == 'approved'`
* Use comparações numéricas: `<nodeId>.body.riskScore < 70`
* Use campos booleanos: `<nodeId>.body.reviewRequired == true`
* Combine com `AND` / `OR` quando precisar: `<nodeId>.body.score < 70 AND <nodeId>.body.verified == true`

Evite expressões complexas. Elas deixam o workflow difícil de ler e de depurar. Se a lógica não for trivial, dê ao nó `conditional` um nome claro que resuma a decisão.

Uma condição ausente faz a execução falhar, e o mesmo acontece com uma condição que não consegue ser avaliada em tempo de execução. Sempre teste as condições antes de ativar um workflow.

### Estratégias de tratamento de erros

Projete workflows para tratar a falha de forma explícita:

* Adicione caminhos de rejeição a partir de nós `conditional` para cada ponto de decisão que pode falhar.
* Use nós `executor` separados para a lógica de nova tentativa ou para provedores de fallback.
* Nomeie os caminhos de erro com clareza (por exemplo, `Reject and Notify`, `Fallback to Manual Review`) para que os registros de execução se expliquem sozinhos.

### Evitando ciclos

O Flowker usa um guarda de ciclos baseado em DFS em tempo de execução. Quando o guarda de ciclos encontra um ciclo durante a execução, o workflow falha com `FLK-0508`. O Flowker não detecta ciclos quando você salva um workflow, exceto em um workflow que tem um nó wait (`FLK-0186`), então valide a estrutura das arestas antes de ativar.

Regras para evitar ciclos:

* As arestas devem sempre apontar para frente no fluxo, nunca de volta para um nó já executado.
* Revise o grafo visualmente antes de ativar qualquer workflow com caminhos de ramificação ou de junção.
* Se você precisar de uma nova tentativa ou de um laço, modele isso como uma invocação de workflow separada, não como uma aresta de retorno no grafo atual.

### Versionamento via clone

Nunca edite um workflow ativo diretamente. Em vez disso:

**Step 1**

Clone o workflow (cria um novo `draft` com todos os nós e arestas copiados).

**Step 2**

Faça suas mudanças no draft.

**Step 3**

Valide ou pré-visualize o draft.

**Step 4**

Ative a nova versão. Um método e um caminho de webhook pertencem a um único workflow ativo por vez: para um workflow disparado por webhook, desative antes a versão antiga, ou dê à nova versão um caminho próprio.

**Step 5**

Desative a versão antiga se você não precisar mais dela.

Isso preserva o histórico de execução da versão ativa e dá a você um caminho de rollback limpo se a nova versão tiver problemas.

## Referência de erros

***

Os códigos de erro a seguir são relevantes para o design e a execução de workflows:

| Código | Descrição |
| - | - |
| `FLK-0102` | Transição de status inválida |
| `FLK-0103` | O workflow não pode ser modificado (não está em status draft) |
| `FLK-0113` | Nós demais (o máximo é 100) |
| `FLK-0114` | Arestas demais (o máximo é 200) |
| `FLK-0506` | Payload de entrada da execução grande demais (o máximo é 1 MB) |
| `FLK-0508` | Ciclo detectado durante a execução do workflow |
| `FLK-0115` | Uma aresta referencia um nó que não existe, ou sai de um condicional por um handle que ele não tem |
| `FLK-0183` a `FLK-0186` | Regras do nó wait |
| `FLK-0187` | Duas ramificações paralelas alcançam o mesmo nó |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.