mozak.tech Engenharia de IA Corporativa 84%

Parte IV — Gestão de Projetos e Produto com Suporte de IA

4.9 — Integração de Ferramentas de Gestão: Notion e Slack como Pipeline (Notion & Slack)

Objetivo da Aula

Ao concluir esta aula, você será capaz de:

Atualizar status de tarefas no Notion via API com propriedades e timestamps

Enviar notificações formatadas para Slack via webhook

Implementar atualizarStatusNotion(pageId, status, comentario, token) completo

Implementar notificarSlack(mensagem, webhookUrl) com Block Kit

Conectar Notion + Slack em um pipeline automático de atualização

Por que isso importa

Atualizar status no Notion e depois avisar o time no Slack são duas ações manuais que ocorrem dezenas de vezes por semana. Automação elimina o esquecimento — o sistema notifica automaticamente quando uma tarefa muda de status, quem mudou, e qual o próximo passo.

Conceitos Fundamentais

TODO 1: atualizarStatusNotion(pageId, novoStatus, comentario, token)

async function atualizarStatusNotion(pageId, novoStatus, comentario, token) {

  // Atualizar propriedades da página

  const resProps = await fetch(`https://api.notion.com/v1/pages/${pageId}`, {

    method: 'PATCH',

    headers: {

      'Authorization': `Bearer ${token}`,

      'Notion-Version': '2022-06-28',

      'Content-Type': 'application/json',

    },

    body: JSON.stringify({

      properties: {

        Status: { select: { name: novoStatus } },

        'Última Atualização': { date: { start: new Date().toISOString() } },

      },

    }),

  })

  

  if (!resProps.ok) {

    const erro = await resProps.json()

    throw new Error(`Notion API error: ${erro.message}`)

  }

  

  // Adicionar comentário como bloco na página (se fornecido)

  if (comentario) {

    await fetch(`https://api.notion.com/v1/blocks/${pageId}/children`, {

      method: 'PATCH',

      headers: {

        'Authorization': `Bearer ${token}`,

        'Notion-Version': '2022-06-28',

        'Content-Type': 'application/json',

      },

      body: JSON.stringify({

        children: [{

          object: 'block',

          type: 'callout',

          callout: {

            icon: { emoji: '📝' },

            rich_text: [{

              type: 'text',

              text: { content: `[${new Date().toLocaleDateString('pt-BR')}] ${comentario}` },

            }],

          },

        }],

      }),

    })

  }

  

  return { sucesso: true, pageId, novoStatus, timestamp: new Date().toISOString() }

}

TODO 2: notificarSlack(mensagem, webhookUrl)

async function notificarSlack(mensagem, webhookUrl) {

  // Mensagem estruturada com Slack Block Kit

  const payload = {

    blocks: [

      {

        type: 'header',

        text: { type: 'plain_text', text: mensagem.titulo },

      },

      {

        type: 'section',

        fields: [

          { type: 'mrkdwn', text: `*Status:*\n${mensagem.status}` },

          { type: 'mrkdwn', text: `*Responsável:*\n${mensagem.responsavel || 'N/A'}` },

          { type: 'mrkdwn', text: `*Atualizado por:*\n${mensagem.autor}` },

          { type: 'mrkdwn', text: `*Hora:*\n${new Date().toLocaleTimeString('pt-BR')}` },

        ],

      },

      ...(mensagem.comentario ? [{

        type: 'section',

        text: { type: 'mrkdwn', text: `💬 ${mensagem.comentario}` },

      }] : []),

      ...(mensagem.link ? [{

        type: 'actions',

        elements: [{

          type: 'button',

          text: { type: 'plain_text', text: 'Ver no Notion' },

          url: mensagem.link,

          style: 'primary',

        }],

      }] : []),

    ],

  }

  

  const res = await fetch(webhookUrl, {

    method: 'POST',

    headers: { 'Content-Type': 'application/json' },

    body: JSON.stringify(payload),

  })

  

  if (!res.ok) throw new Error(`Slack webhook error: ${res.status}`)

  return { sucesso: true, status: res.status }

}

Aprofundamento Técnico

Slack Block Kit: Elementos Essenciais

Tipo

Uso

header

Título principal (sem markdown)

section

Texto ou campos par-a-par

divider

Linha separadora visual

actions

Botões clicáveis com URL

callout

Destaque com ícone (só Notion)

Slack renderiza emojis nativos: :white_check_mark:, :warning:, :rocket:.

Pipeline Completo

async function atualizarENotificar(pageId, novoStatus, autor, comentario, opts) {

  const { notionToken, slackWebhook, pageUrl, responsavel } = opts

  

  // 1. Atualizar Notion

  const resultado = await atualizarStatusNotion(pageId, novoStatus, comentario, notionToken)

  

  // 2. Notificar Slack

  if (slackWebhook) {

    const emoji = novoStatus === 'Concluído' ? '✅' : novoStatus === 'Em Progresso' ? '🔄' : '⏸️'

    await notificarSlack({

      titulo: `${emoji} Task atualizada: ${novoStatus}`,

      status: novoStatus,

      responsavel,

      autor,

      comentario,

      link: pageUrl,

    }, slackWebhook)

  }

  

  return resultado

}

Exemplos Anotados

Exemplo 1: Atualização sem credenciais reais (mock)

// No starter.js, se não tiver credenciais:

async function notificarSlackMock(mensagem, webhookUrl) {

  console.log('SLACK MOCK — Mensagem que seria enviada:')

  console.log(JSON.stringify(mensagem, null, 2))

  return { sucesso: true, mock: true }

}



const notificar = process.env.SLACK_WEBHOOK ? notificarSlack : notificarSlackMock

await notificar({ titulo: 'Tarefa concluída', status: 'Concluído', autor: 'Maria' }, url)

Padrões e Armadilhas

Padrões

Padrão 1: Idempotência na atualização

// Verificar se já está no status desejado antes de fazer PATCH

const pagina = await fetch(`https://api.notion.com/v1/pages/${pageId}`, { headers })

const status_atual = (await pagina.json()).properties.Status?.select?.name

if (status_atual === novoStatus) return { sucesso: true, sem_mudanca: true }

Padrão 2: Fallback gracioso para Slack Se webhook falhar, logar o erro mas não bloquear a atualização do Notion.

Armadilhas

⚠️ Armadilha 1: Notion pageId vs blockId pageId de uma página database tem UUID format: 32char. Blocos dentro da página têm IDs diferentes. Use pageId para propriedades, blockId para adicionar conteúdo.

⚠️ Armadilha 2: Slack webhooks não suportam edição Uma vez enviado, não há como editar mensagem via webhook. Use Slack Bot API se precisar atualizar mensagens.

⚠️ Armadilha 3: Propriedade Notion com nome errado

// Notion é case-sensitive em property names

// "Status" ≠ "status" ≠ "STATUS"

// Verificar o nome exato na UI do Notion
⚗ Laboratório prático — mozak.tech
Se não for realizar o laboratório, pule para o próximo capítulo.

Ponte para o Lab

TODO 1 — atualizarStatusNotion(pageId, novoStatus, comentario, token): PATCH em /v1/pages/{id} com properties.Status, e PATCH em /v1/blocks/{id}/children para comentário callout.

TODO 2 — notificarSlack(mensagem, webhookUrl): POST para webhook com Block Kit (header, section fields, button de link).

Agora você está pronto para o lab.