# Daily Digest

Manda a cada responsável uma DM no Slack com as leituras de KPI do dia e registra cada tentativa no Communication.

| Platform | Workflow ID | Status | Version | Last saved | Nodes | Systems |
| --- | --- | --- | --- | --- | --- | --- |
| n8n | V8YNeLy4FbFiPvsM | Active | cf9165c2-706b-4bfb-8658-c62f1bb4dac5 | 2026-11-06T19:41:05.769Z | 36 | KPIs & OKRs, Communication, Tooling and Access |

O Communication — Daily Digest pede a cada pessoa responsável, numa mensagem direta no Slack, as leituras de KPI devidas no dia. Toda manhã ele acha as Recurrence Configurations ativas cuja cadência vence, tira as leituras já registradas, agrupa o resto por membership responsável, acha a conta de Slack de cada pessoa em Tooling and Access, manda um digest com checkboxes por membership e registra cada tentativa como uma Message no Communication. As respostas voltam pelo workflow separado Communication — Reading Reply, que trata os checkboxes.

O maintainer de KPIs & OKRs cuida das agendas e da regra de vencimento; o maintainer do Communication revisa as linhas de Message; o maintainer de Tooling and Access mantém as pessoas ligadas às suas contas de Slack.

## Fluxo

Gerado da versão do n8n do quadro acima: cada caixa é um nó e cada seta é uma ligação no n8n. Pílulas rosa são gatilhos, hexágonos amarelos são nós If e Switch com as saídas nas setas, cilindros azuis leem (Airtable, Data Table, HTTP GET), cilindros verdes gravam, caixas roxas chamam outro workflow e setas tracejadas são saídas de erro.

```mermaid
flowchart TD
  subgraph g0["Início e schema"]
    n6(["Every day 09:00"]):::trigger
    n33(["Webhook"]):::trigger
    n34(["When clicking ‘Execute workflow’"]):::trigger
    n4["Config"]:::logic
    n0["Airtable Schema"]:::logic
    n20[("Meta (Operation)<br/><small>getSchema KPIs base</small>")]:::read
    n19[("Meta (Communication)<br/><small>getSchema Communication base</small>")]:::read
    n21[("Meta (Tooling)<br/><small>getSchema Tooling base</small>")]:::read
    n27["Resolve Schema"]:::logic
    n30{{"Schema OK"}}:::decision
  end
  subgraph g1["Leituras devidas"]
    n17[("List Due Schedules<br/><small>search KPIs Recurrence Configuration</small>")]:::read
    n10[("Get Cadences<br/><small>search KPIs Cadence</small>")]:::read
    n3["Compute Due Items"]:::logic
    n16{{"Is OK"}}:::decision
    n1["Build Answered Filter"]:::logic
    n7[("Find Answered<br/><small>search KPIs Observation</small>")]:::read
    n14["Group by Recipient"]:::logic
    n15{{"Has Digests"}}:::decision
    n18["Log Nothing To Do"]:::logic
  end
  subgraph g2["Destinatário no Slack"]
    n13[("Get Slack Accounts<br/><small>search Tooling Tool Account</small>")]:::read
    n11[("Get Identity Bindings<br/><small>search Tooling Identity Binding</small>")]:::read
    n12[("Get Persons (Tooling)<br/><small>search Tooling Person</small>")]:::read
    n29["Resolve Slack Recipient"]:::logic
    n25{{"Recipient Resolved?"}}:::decision
    n9["Get Cached Notification Bot<br/><small>Slack — Workspace Token Cache</small>"]:::subflow
    n28["Resolve Slack Account"]:::logic
  end
  subgraph g3["Enviar e registrar"]
    n2["Build Slack Blocks"]:::logic
    n32{{"User Found"}}:::decision
    n22{{"Not Dry Run"}}:::decision
    n23[("Open DM<br/><small>POST Slack conversations.open</small>")]:::write
    n24[("Post Digest<br/><small>POST Slack chat.postMessage</small>")]:::write
    n8[("Find Membership (Communication)<br/><small>search Communication Membership</small>")]:::read
    n31["Shape Message Row"]:::logic
    n5[("Create Message<br/><small>create Communication Message</small>")]:::write
    n26["Report"]:::logic
  end
  n6 --> n4
  n4 --> n0
  n0 --> n20
  n20 --> n19
  n19 --> n21
  n21 --> n27
  n27 --> n30
  n17 --> n10
  n10 --> n3
  n3 --> n16
  n1 --> n7
  n7 --> n14
  n14 --> n15
  n13 --> n11
  n11 --> n12
  n12 --> n29
  n2 --> n32
  n23 --> n24
  n24 --> n8
  n8 --> n31
  n31 --> n5
  n5 --> n26
  n30 -->|sim| n17
  n30 -->|não| n18
  n16 -->|sim| n1
  n16 -->|não| n18
  n15 -->|sim| n13
  n15 -->|não| n18
  n32 -->|sim| n22
  n32 -->|não| n8
  n22 -->|sim| n23
  n22 -->|não| n8
  n34 --> n4
  n33 --> n4
  n29 --> n25
  n25 -->|sim| n9
  n25 -->|não| n28
  n9 --> n28
  n28 --> n2
  classDef trigger fill:#fde7f3,stroke:#d6409f,color:#111
  classDef decision fill:#fff7e0,stroke:#c99a00,color:#111
  classDef read fill:#e8f1ff,stroke:#3b82f6,color:#111
  classDef write fill:#e7f8ee,stroke:#16a34a,color:#111
  classDef subflow fill:#f3e8ff,stroke:#9333ea,color:#111
  classDef wait fill:#f1f1f1,stroke:#888,color:#111
  classDef logic fill:#ffffff,stroke:#999,color:#111
```

## Sistemas que ele toca

| Sistema | Tabela | Lê | Grava |
| --- | --- | --- | --- |
| KPIs & OKRs | Recurrence Configuration | List Due Schedules | Nada |
| KPIs & OKRs | Cadence (mirror) | Get Cadences | Nada |
| KPIs & OKRs | Observation | Find Answered | Nada |
| Tooling and Access | Tool Account | Get Slack Accounts | Nada |
| Tooling and Access | Identity Binding | Get Identity Bindings | Nada |
| Tooling and Access | Person (mirror) | Get Persons (Tooling) | Nada |
| Communication | Membership (mirror) | Find Membership (Communication) | Nada |
| Communication | Message | Nada | Create Message |

Meta (Operation), Meta (Communication) e Meta (Tooling) também leem a lista de tabelas e campos das três bases. A linha de Message liga o Channel Slack DM e a Notification Rule Reading due today por ID de registro, e a tag kpis-okrs-daily-digest-n8n.

Fora do Airtable, o Get Cached Notification Bot chama o workflow Slack — Workspace Token Cache para obter o token do bot do workspace de cada destinatário, e Open DM e Post Digest chamam a Web API do Slack.

Os nós do Airtable são nós nativos do Airtable com a credencial Airtable PAT (Fully Scoped). Eles leem e gravam pelo nome da coluna, mas todo nome vem do Resolve Schema, que traduz a cada execução os IDs de campo guardados no Airtable Schema para os nomes atuais. Renomear uma coluna não quebra o fluxo; apagar uma o para no Schema OK.

Veja [Daily Digest](/pt-br/automations/daily-digest) para o lado das leituras em KPIs & OKRs e [Entrega do Daily Digest](/pt-br/automations/daily-digest) para as linhas de Message no Communication.

## Gatilhos e agenda

Três gatilhos iniciam a mesma execução no Config:

| Gatilho | Quando |
| --- | --- |
| Every day 09:00 | Cron `0 9 * * *` no fuso da instância do n8n; o workflow não define um. As linhas de Message das execuções agendadas são criadas por volta das 12:00 UTC |
| Webhook | Um GET num path fixo, sem autenticação. Responde na hora. `?runDate=YYYY-MM-DD` roda o digest para aquela data |
| When clicking ‘Execute workflow’ | Execução manual pelo editor do n8n |

O Config define as constantes da execução:

| Configuração | Valor |
| --- | --- |
| timezone | America/Chicago, usado para o dia da semana, a chave de período e o rótulo da data |
| dryRun | false |
| dmChannelRecordId | O Channel Slack DM |
| ruleRecordId | A Notification Rule Reading due today |
| biweeklyAnchorIsoWeekParity | 0 (cadências quinzenais disparam nas semanas ISO pares) |
| maxItemsPerDigest | 25 |
| workspaceByOrganization | Workspace do Slack por organização: Snack Prompt, Corp; Sons Design , LLC; Sons Of Liberty Coffee, LLC; Score Milk (Top Score), LLC; Nexa Roofing, LLC; REFS Labs, Inc. |
| defaultWorkspaceTeamId | O workspace da Snack Prompt, Corp |
| runDate | `runDate` da query do webhook; senão, a data de hoje no relógio do n8n |

## Conferência do schema

O Airtable Schema guarda os IDs de base, tabela e campo que o fluxo usa em KPIs & OKRs, Communication e Tooling and Access. Meta (Operation), Meta (Communication) e Meta (Tooling) leem o schema de cada base, e o Resolve Schema mapeia cada ID para o nome atual. Quando falta uma tabela ou campo, o Resolve Schema devolve "Schema drift — not found in Airtable: …" e o Schema OK manda a execução para o Log Nothing To Do, que a encerra.

## Leituras devidas

1. **Agendas.** O List Due Schedules lê as Recurrence Configurations com Lifecycle Status* Active e um Cadence (Key). O Get Cadences lê o catálogo Cadence (mirror) inteiro.
2. **Devidas hoje.** O Compute Due Items pula a agenda cuja chave de cadência não está no catálogo, cuja cadência não está Active ou que não tem Accountable Membership*. Fica com as que vencem na data da execução:

   | Chave da cadência | Vence quando |
   | --- | --- |
   | daily | Todo dia |
   | daily-working-days | O dia da semana está no By Day da cadência |
   | weekly | Segunda-feira |
   | biweekly | Segunda-feira de semana ISO par |
   | monthly | Dia 1 |
   | quarterly | Dia 1 de janeiro, abril, julho e outubro |
   | semiannual | Dia 1 de janeiro e julho |
   | annual | 1º de janeiro |
   | on-demand, ou qualquer outra chave | Nunca |

   Cada item devido ganha uma chave de período a partir do Period Key Format da cadência e uma chave de ocorrência `<ID do registro da Recurrence Configuration>:<chave de período>`. Os destinatários são as memberships responsáveis da agenda, com nome, e-mail, Membership # e organização. O nome vem do Accountable Display Name; quando ele é só um ID de registro, é tirado do Accountable (Membership #), que tem a forma "número - nome - organização".
3. **Já respondidas.** O Build Answered Filter monta fórmulas de Occurrence Key em lotes de 40, e o Find Answered lê essas Observations. O Group by Recipient tira o item de uma membership quando uma Observation tem a mesma Occurrence Key, traz essa membership em Observation About (Membership)* e tem Collection Status* vazio ou Recorded.
4. **Um digest por membership.** O Group by Recipient agrupa o que sobrou por membership responsável, fica com os 25 primeiros itens e conta o resto como excedente. Um destinatário sem nome fica de lado como inalcançável. O Has Digests encerra a execução no Log Nothing To Do quando não sobra nada.

## Destinatário no Slack

O Get Slack Accounts lê as Tool Accounts com Kind human (só Name, External Identifier, Kind e Workspace (External Identifier); nunca Access Token). Get Identity Bindings e Get Persons (Tooling) leem as duas tabelas inteiras. Para cada digest, o Resolve Slack Recipient:

1. acha a Person (mirror) cujo Full name* é igual ao nome do destinatário, ignorando maiúsculas e espaços extras;
2. fica com as Identity Bindings dessa pessoa cujo Valid Through está vazio ou no futuro, e com as Tool Accounts human delas;
3. escolhe a conta no workspace mapeado para a organização da membership; senão, a única conta; senão, a conta no workspace padrão;
4. confere que o ID do workspace começa com T e o ID do usuário do Slack com U.

Cada falha vira um erro no item ("Person not found in Tooling mirror: …", "No Slack account bound to …", "No Slack account for … in workspace …", INVALID_WORKSPACE, INVALID_SLACK_USER). O Recipient Resolved? manda os itens resolvidos para o Get Cached Notification Bot, que roda o Slack — Workspace Token Cache com o ID do workspace, `cacheOnly` false, `forceRefresh` false e `refreshAll` false, e espera a resposta. O Resolve Slack Account só aceita a resposta quando ela está ok, é do mesmo workspace, traz token e ID de usuário do bot e não venceu; senão, o item recebe TOKEN_CACHE_UNAVAILABLE, TOKEN_WORKSPACE_MISMATCH ou TOKEN_CACHE_INVALID.

## Enviar e registrar

O Build Slack Blocks monta o digest: um cabeçalho "&lt;data&gt; · 0 of N responses recorded", depois seções de até 10 checkboxes com a ação `reading_reply`, um por leitura (nome, descrição, meta), cada um com o valor `<chave de ocorrência>|<ID do registro da membership>|<ID do usuário no Slack>`. O excedente acrescenta a linha "N additional readings are not shown in this message."

| Estado do item | Caminho |
| --- | --- |
| Erro de roteamento ou do cache de token | User Found falso → Find Membership (Communication) → Message Failed |
| Dry run | Not Dry Run falso → Find Membership (Communication) → Message Sent com External Message Id começando em `dry-run-` |
| Pronto | Open DM (`conversations.open`) → Post Digest (`chat.postMessage` com os blocos e o evento de metadata `reading_digest`) → Find Membership (Communication) → Message Sent ou Failed conforme a resposta do Slack |

Open DM e Post Digest usam a credencial do n8n Systems Slack Automation - Dynamic, que usa o token do bot resolvido para o item. O Find Membership (Communication) procura em Membership (mirror) pelo Membership # (igual, ou começando com "&lt;número&gt; - "). O Shape Message Row monta a linha e o Create Message a salva. O Report conta digests, enviados e falhos da execução.

## Campos gravados

### Message do Communication (Create Message)

| Campo | Valor |
| --- | --- |
| Subject | "Daily digest · &lt;pessoa&gt; · &lt;data da execução&gt;" |
| Body | "&lt;data&gt;: N readings awaiting a response." |
| Status | Sent quando o Slack (ou o dry run) respondeu ok, Failed nos outros casos |
| Sent At | Hora em que foi salva, quando Sent |
| External Message Id | Timestamp da mensagem no Slack, ou `dry-run-…`, quando Sent |
| Failure Reason | O erro, quando Failed |
| Channel | Slack DM |
| Rule | Reading due today |
| Recipients (Membership) | A membership achada pelo Find Membership (Communication), quando achada |
| About Keys | Uma chave de ocorrência por leitura do digest, uma por linha |
| Tags | kpis-okrs-daily-digest-n8n |

O fluxo não grava mais nada: nenhuma Observation, nenhuma Recurrence Configuration e nada em Tooling and Access.

## Nós

O workflow tem 36 nós: 35 que executam e uma nota adesiva. Num nó If, a saída 0 é verdadeiro e a saída 1 é falso.

| Nó | Tipo | O que faz |
| --- | --- | --- |
| Every day 09:00 | scheduleTrigger | Inicia a execução às 09:00 no horário da instância |
| Webhook | webhook | Inicia a execução por um GET; `runDate` opcional |
| When clicking ‘Execute workflow’ | manualTrigger | Inicia a execução pelo editor |
| Config | set | Constantes da execução |
| Airtable Schema | code | IDs de base, tabela e campo usados pelo fluxo |
| Meta (Operation) | airtable | Lê o schema de KPIs & OKRs |
| Meta (Communication) | airtable | Lê o schema do Communication |
| Meta (Tooling) | airtable | Lê o schema de Tooling and Access |
| Resolve Schema | code | Mapeia IDs de campo para os nomes atuais; aponta divergências |
| Schema OK | if | Schema resolvido ou não |
| List Due Schedules | airtable | Recurrence Configurations ativas com chave de cadência |
| Get Cadences | airtable | O catálogo Cadence (mirror) |
| Compute Due Items | code | Agendas devidas, chaves de período, chaves de ocorrência e destinatários |
| Is OK | if | Agendas achadas ou não |
| Build Answered Filter | code | Fórmulas de Occurrence Key em lotes de 40 |
| Find Answered | airtable | Observations dessas chaves de ocorrência |
| Group by Recipient | code | Tira itens respondidos; um digest por membership, até 25 itens |
| Has Digests | if | Sobrou algo para enviar ou não |
| Log Nothing To Do | code | Encerra uma execução sem nada para enviar |
| Get Slack Accounts | airtable | Tool Accounts human |
| Get Identity Bindings | airtable | Todas as Identity Bindings |
| Get Persons (Tooling) | airtable | Todas as linhas de Person (mirror) |
| Resolve Slack Recipient | code | Pessoa → vínculo → conta e workspace do Slack |
| Recipient Resolved? | if | Roteamento deu certo ou não |
| Get Cached Notification Bot | executeWorkflow | Roda o Slack — Workspace Token Cache para o workspace |
| Resolve Slack Account | code | Valida o token do bot em cache |
| Build Slack Blocks | code | Blocos do digest com checkboxes e texto resumo |
| User Found | if | Item sem erro ou não |
| Not Dry Run | if | Envio real ou dry run |
| Open DM | httpRequest | Abre a mensagem direta no Slack |
| Post Digest | httpRequest | Publica o digest |
| Find Membership (Communication) | airtable | Membership do Communication pelo Membership # |
| Shape Message Row | code | Monta a linha de Message |
| Create Message | airtable | Salva a linha de Message |
| Report | code | Resumo da execução |
| Sticky Note | stickyNote | Notas no canvas; não executa |

## Ligações

| De | Saída | Para |
| --- | --- | --- |
| Every day 09:00 | 0 | Config |
| Config | 0 | Airtable Schema |
| Airtable Schema | 0 | Meta (Operation) |
| Meta (Operation) | 0 | Meta (Communication) |
| Meta (Communication) | 0 | Meta (Tooling) |
| Meta (Tooling) | 0 | Resolve Schema |
| Resolve Schema | 0 | Schema OK |
| List Due Schedules | 0 | Get Cadences |
| Get Cadences | 0 | Compute Due Items |
| Compute Due Items | 0 | Is OK |
| Build Answered Filter | 0 | Find Answered |
| Find Answered | 0 | Group by Recipient |
| Group by Recipient | 0 | Has Digests |
| Get Slack Accounts | 0 | Get Identity Bindings |
| Get Identity Bindings | 0 | Get Persons (Tooling) |
| Get Persons (Tooling) | 0 | Resolve Slack Recipient |
| Build Slack Blocks | 0 | User Found |
| Open DM | 0 | Post Digest |
| Post Digest | 0 | Find Membership (Communication) |
| Find Membership (Communication) | 0 | Shape Message Row |
| Shape Message Row | 0 | Create Message |
| Create Message | 0 | Report |
| Schema OK | 0 | List Due Schedules |
| Schema OK | 1 | Log Nothing To Do |
| Is OK | 0 | Build Answered Filter |
| Is OK | 1 | Log Nothing To Do |
| Has Digests | 0 | Get Slack Accounts |
| Has Digests | 1 | Log Nothing To Do |
| User Found | 0 | Not Dry Run |
| User Found | 1 | Find Membership (Communication) |
| Not Dry Run | 0 | Open DM |
| Not Dry Run | 1 | Find Membership (Communication) |
| When clicking ‘Execute workflow’ | 0 | Config |
| Webhook | 0 | Config |
| Resolve Slack Recipient | 0 | Recipient Resolved? |
| Recipient Resolved? | 0 | Get Cached Notification Bot |
| Recipient Resolved? | 1 | Resolve Slack Account |
| Get Cached Notification Bot | 0 | Resolve Slack Account |
| Resolve Slack Account | 0 | Build Slack Blocks |

## Configurações e tratamento de erro

| Configuração | Valor |
| --- | --- |
| Ordem de execução | v1 |
| Workflow de erro | Nenhum |
| Retry on fail | Desligado em todos os nós |
| On error | Continua em Get Cached Notification Bot, Open DM, Post Digest, Find Membership (Communication) e Create Message; para o workflow nos outros |
| Salvar execuções com sucesso | Não |
| Salvar execuções com falha | Não |
| Salvar execuções manuais | Não |
| Salvar progresso da execução | Não |
| Caller policy | Workflows do mesmo dono |
| Disponível no MCP | Sim |

Desde 06/11/2026 o n8n guarda toda execução deste workflow, com sucesso, com falha e manual, com progresso. Antes dessa data nada era guardado, então para execuções antigas as linhas de Message são o único registro.

## Lacunas conhecidas

Estas vêm da configuração dos nós e das linhas de Message que o fluxo gravou.

| Lacuna | Efeito |
| --- | --- |
| O Webhook não tem autenticação | Quem tem o endereço dispara uma execução real completa para qualquer `runDate` |
| A agenda roda às 09:00 no horário da instância, enquanto o Config e a Notification Rule dizem America/Chicago | As execuções caem por volta das 12:00 UTC; o dia da semana e a chave de período usam a data de Chicago, a data da execução usa o relógio da instância |
| Num dia sem nada devido, o Build Answered Filter devolve um item de erro que ninguém confere | O Find Answered roda com fórmula vazia e lê a tabela Observation inteira; a execução então termina dizendo que tudo já foi respondido |
| O Open DM continua em caso de erro | O Post Digest roda mesmo assim, e a Message guarda `invalid_arguments` em vez do erro original do Slack, como `user_not_found` |
| O Create Message continua em caso de erro | Um digest pode chegar ao Slack sem linha de Message; desde 06/11/2026 a execução do n8n ainda mostra isso |
| Destinatários inalcançáveis (sem nome) só são contados no Report | Não ganham linha de Message; o Report só aparece na execução guardada |
| Um ID de registro pode chegar como nome da pessoa | O digest é registrado Failed com "Person not found in Tooling mirror: rec…"; três linhas assim foram gravadas em 03/11/2026 |
| A pessoa é identificada só pelo nome completo | Duas pessoas com o mesmo nome em Person (mirror) caem na primeira; o Valid From do vínculo é ignorado |
| O Resolve Schema também exige o Access Token da Tool Account, que o fluxo nunca lê | Apagar essa coluna para todos os digests |
| Não há idempotência de entrega | Uma segunda execução no mesmo dia manda de novo os itens não respondidos; um dry run também grava linhas de Message |
| A nota adesiva diz que a restrição de teste está ligada | O Config não tem testMembershipId nem testScheduleId, então ela está desligada; o Build Slack Blocks ainda fixa um usuário do Slack para ela |
| Uma pessoa com duas memberships | Recebe dois digests |
| Mais de 25 itens para uma membership | O resto é contado, não enviado |

## Recuperar uma gravação parcial

Veja as linhas de Message da execução antes de iniciar outra: uma nova execução manda de novo para todos que têm algo sem resposta, e não há reenvio para um destinatário só.

| O que aconteceu | O que fazer |
| --- | --- |
| Message Failed com erro de roteamento | Corrija a Person (mirror), a Identity Binding ou a Tool Account em Tooling and Access; a próxima execução agendada tenta de novo |
| Message Failed com erro do Slack ou do token | Confira o bot do workspace no Slack — Workspace Token Cache; a próxima execução agendada tenta de novo |
| Digest no Slack mas sem linha de Message | Crie a Message à mão a partir da DM no Slack, se a entrega precisar ser contada |
| Execução parada na conferência do schema | Restaure ou remapeie a coluna que falta e espere a próxima execução, ou rode uma à mão sabendo que ela manda para todos |

## Manter esta página em dia

O quadro no topo mostra a versão do n8n que esta página descreve. Abra o workflow no n8n: quando o último salvamento dele é mais novo que a data do quadro, esta página está desatualizada até a próxima revisão. Todos os nós e todas as ligações dessa versão estão em [Nós](#nodes) e [Ligações](#connections).