๐ฏ Caso: sincronizar leads do Tally para Notion
Tally manda webhook para servico Node. Servico transforma payload e cria pagina no Notion. Logging em Supabase.
Briefing
- โข Endpoint POST /webhook recebe payload do Tally
- โข Transforma: mapeia campos do Tally para schema do Notion
- โข Cria pagina no DB do Notion com os dados
- โข Loga sucesso/erro em tabela do Supabase
- โข Deploy: Vercel Edge Function
๐ Plano simplificado (1 paragrafo)
Para script pequeno, plano e 1 paragrafo. GPT-5.5 nem precisa โ DeepSeek le o briefing direto.
PLAN (inline no prompt)
Endpoint POST /webhook recebe Tally payload.
Valida com zod (email, name obrigatorios).
Transforma: { name, email, source } -> Notion props.
POST /pages para Notion API com page schema.
Insert em supabase.logs (timestamp, status, payload).
Retorna 200 ou 4xx/5xx apropriado.Plano demais em tarefa pequena vira fricao. Saber quando pular e parte do dominio.
โก DeepSeek implementa o servico inteiro
DeepSeek le briefing + docs do Notion API + schema do Supabase. Gera index.ts pronto para deploy em Vercel. ~80 linhas em 1 commit.
// api/webhook/route.ts
import { z } from 'zod';
import { createClient } from '@supabase/supabase-js';
import { Client as Notion } from '@notionhq/client';
const Schema = z.object({
data: z.object({
fields: z.array(z.object({
label: z.string(), value: z.unknown()
}))
})
});
export async function POST(req: Request) {
const body = await req.json();
const parsed = Schema.safeParse(body);
if (!parsed.success) return Response.json({ error: 'invalid' }, { status: 400 });
const fields = parsed.data.data.fields;
const get = (l: string) => fields.find(f => f.label === l)?.value;
const notion = new Notion({ auth: process.env.NOTION_KEY });
const supabase = createClient(process.env.SB_URL!, process.env.SB_KEY!);
try {
await notion.pages.create({
parent: { database_id: process.env.NOTION_DB! },
properties: {
Name: { title: [{ text: { content: String(get('name')) } }] },
Email: { email: String(get('email')) },
Source: { rich_text: [{ text: { content: 'Tally' } }] }
}
});
await supabase.from('logs').insert({ status: 'ok', payload: body });
return Response.json({ ok: true });
} catch (e) {
await supabase.from('logs').insert({ status: 'error', error: String(e), payload: body });
return Response.json({ error: 'sync_failed' }, { status: 500 });
}
}๐งช Testes com fixtures (DeepSeek)
5 cenarios: payload valido, faltando campo, tipo errado, Notion offline, duplicado.
- โ caso feliz: payload valido โ espera 200 + log "ok"
- โ email faltando: espera 400 + log nao criado
- โ email com tipo invalido: espera 400
- โ Notion API offline (mock 500): espera 500 + log "error"
- โ idempotencia: mesmo payload 2x โ Notion cria 2 pages (ok, comportamento esperado de webhook simples)
๐ Revisao rapida (so 2 itens)
Em script de integracao, 2 itens basta: idempotencia e tratamento de erro.
- โ Idempotencia: ok para webhook simples โ Notion cria 2 pages se Tally retentar. Para producao seria: hash do payload em tabela "processed".
- โ Tratamento de erro: ok โ captura, loga, retorna 500. Tally retentara automaticamente.
- โ ๏ธ Sugestao opcional: dedupe por email se virar problema.
Revisao proporcional ao risco. Script de plumbing tem 2 riscos principais.
๐ฐ Resultado: $0.05 e 20 min
90% DeepSeek, 10% revisao. Distribuicao adaptada โ em automacao "plumbing" Opus nao agrega nada.
- โข DeepSeek codigo + testes: $0.04 (40k tokens)
- โข GPT-5.5 review: $0.01
- โข Total: $0.05
- โข Tempo briefing โ deploy: 20 min
- โข Comparativo manual: ~2h, sem testes
Esse tipo de tarefa e onde DeepSeek mais paga. Saber adaptar o setup e parte do dominio.
๐ Resumo do Projeto
Proximo Projeto:
3.5 โ ๐ API + microservico com testes