// Grape Elevate — Roadmap / Technical plan screen // Comprehensive deliverable for handing off to a developer: architecture, // stack, costs, Meta setup checklist, code skeletons, and timeline. function Roadmap({ t }) { return ( <>

Plano técnico para tirar do papel

Tudo que falta entre esse protótipo e um produto que roda de verdade no Instagram + WhatsApp. Pode mandar pra um dev ou estudar pra fazer você mesmo.

Resumo

MVP em ~4 semanas, custo inicial < R$ 100/mês

O protótipo já cobre 100% da UX. O que falta é o backend que conversa com a API do Instagram, um banco de dados pra guardar contatos e fluxos, e a aprovação do app na Meta (passo mais demorado, mas é trabalho de espera, não de código).

🛠️

Stack recomendada

FrontendEste protótipo (React + HTML) — só trocar dados mockados por fetch('/api/...')
BackendNode.js (Fastify) ou Python (FastAPI) — leve e rápido pra webhooks
BancoPostgres no Supabase ou Neon — grátis até 500MB
HospedagemRailway, Fly.io ou Render — R$ 0 a R$ 50/mês
FilaBullMQ + Redis (Upstash grátis) — pra atrasos e retentativas
AuthSupabase Auth ou Clerk — pronto, com login social
PagamentoStripe (cartão internacional) ou Pagar.me (PIX/boleto)
💸

Custos estimados

Fase 1 — Validação (você sozinho)
R$ 0–80/mês
  • Hospedagem free tier (Railway/Fly)
  • Supabase free
  • Domínio: ~R$ 40/ano
  • WhatsApp Cloud API: 1.000 conversas grátis/mês
Fase 2 — Primeiros 100 clientes
R$ 300–800/mês
  • Hospedagem paga ($20–50/mês)
  • Postgres médio
  • Custo variável de WhatsApp por mensagem
⚠️ Variável: WhatsApp
~R$ 0,03–0,30/conversa
  • "Conversa" = 24h de troca de mensagens com 1 número
  • Mensagem iniciada pelo usuário (resposta) costuma ser grátis
📋

Checklist Meta — o caminho oficial

Tudo aqui é grátis, mas leva tempo. Comece já em paralelo ao desenvolvimento.

  1. Crie uma conta Meta Business em business.facebook.com. Use CNPJ se possível.
  2. Verifique a empresa (Configurações → Centro de segurança) — exige documento da empresa.
  3. Vincule a página do Facebook que vai representar o app.
  4. Conecte sua conta do Instagram como Business (perfis pessoais não funcionam).
  5. Registre o app em developers.facebook.com → Meus Apps → Criar app → tipo "Business".
  6. Adicione os produtos: Instagram Graph API, WhatsApp Business Platform, Webhooks.
  7. Configure URL de webhook apontando pro seu backend (precisa ser HTTPS).
  8. Solicite as permissões: instagram_basic, instagram_manage_messages, instagram_manage_comments, pages_show_list, pages_messaging. ⏱️ Revisão demora 3–14 dias
  9. Grave um vídeo (~3 min) demonstrando o app pra revisão — exigência da Meta.
  10. Saia do "modo desenvolvimento" — quando aprovado, o app vai ao ar pra qualquer usuário.
🧱

Esqueleto do backend

Node + Fastify. Cole isso num repositório novo pra começar.

{`{ "dependencies": { "fastify": "^4", "@supabase/supabase-js": "^2", "axios": "^1", "bullmq": "^5", "dotenv": "^16", "zod": "^3" } }`} {`import Fastify from 'fastify'; import { runAutomation } from './engine.js'; const app = Fastify(); const VERIFY_TOKEN = process.env.META_VERIFY_TOKEN; // 1. Verificação inicial do webhook (Meta envia GET pra confirmar URL) app.get('/webhook/instagram', async (req, reply) => { const { 'hub.mode': mode, 'hub.verify_token': token, 'hub.challenge': challenge } = req.query; if (mode === 'subscribe' && token === VERIFY_TOKEN) return reply.send(challenge); return reply.code(403).send(); }); // 2. Eventos: comentários, mensagens, story replies... app.post('/webhook/instagram', async (req, reply) => { const { entry } = req.body; for (const e of entry) { for (const change of e.changes || []) { // Ex: novo comentário em um post if (change.field === 'comments') { const { id, text, from } = change.value; await runAutomation({ type: 'comment', text, sender: from, commentId: id }); } } for (const msg of e.messaging || []) { // Ex: DM recebida await runAutomation({ type: 'dm', text: msg.message.text, sender: msg.sender }); } } return reply.send('OK'); }); app.listen({ port: process.env.PORT || 3000, host: '0.0.0.0' });`} {`import axios from 'axios'; import { supabase } from './db.js'; // Casa um evento com automações ativas e roda os passos do fluxo. export async function runAutomation(event) { const { data: autos } = await supabase .from('automations') .select('*') .eq('status', 'live') .eq('trigger_type', event.type); for (const auto of autos || []) { // Filtro por palavra-chave (case-insensitive) if (auto.trigger_keyword && !event.text?.toLowerCase().includes(auto.trigger_keyword.toLowerCase())) continue; for (const step of auto.flow) { if (step.type === 'wait') await sleep(step.config.mins * 60_000); if (step.type === 'sendDm') await sendDm(event.sender.id, step.config.text); if (step.type === 'sendLink') await sendDm(event.sender.id, step.config.cta + ' ' + step.config.url); if (step.type === 'tag') await tagContact(event.sender.id, step.config.tag); } // Conta execução pro analytics await supabase.rpc('increment_runs', { auto_id: auto.id }); } } async function sendDm(userId, text) { await axios.post(\`https://graph.facebook.com/v18.0/me/messages\`, { recipient: { id: userId }, message: { text }, }, { params: { access_token: process.env.IG_ACCESS_TOKEN } }); }`}
🗓️

Roadmap de 4 semanas (MVP)

Quer ajuda pra encontrar um dev?

Um freelancer Node + React experiente vai cobrar entre R$ 8k–25k pra implementar o MVP em ~1 mês. Plataformas: Workana, GetNinjas, ou peça indicação em grupos de devs no Telegram.

); } // ── Architecture diagram (inline SVG) ──────────────────────────────────────── function Architecture() { return ( {/* Instagram + WhatsApp */} Instagram Graph API + Webhooks WhatsApp Cloud API Stripe Cobrança {/* Backend */} Backend Grape Node + Fastify Webhooks REST API Engine de fluxos {/* DB + Queue */} Postgres Supabase Redis filas + cache Frontend (este app) {/* Arrows */} ); } function CodeBlock({ title, children }) { const [copied, setCopied] = React.useState(false); const copy = async () => { try { await navigator.clipboard.writeText(children); setCopied(true); setTimeout(() => setCopied(false), 1500); } catch {} }; return (
{title}
{children}
); } function Timeline() { const weeks = [ { w: 1, t: 'Setup', items: ['Repo + deploy básico (Railway)', 'Banco Postgres', 'Login + workspaces', 'Solicitar revisão Meta'] }, { w: 2, t: 'Conexão Instagram', items: ['OAuth com Meta', 'Receber webhooks de comentário', 'Endpoint de envio de DM', 'Persistir conversa no banco'] }, { w: 3, t: 'Engine de fluxos', items: ['CRUD de automações', 'Executor (palavra-chave → enviar DM)', 'Fila com BullMQ', 'Dashboard de runs'] }, { w: 4, t: 'Polimento', items: ['Conectar com este frontend', 'WhatsApp Cloud API', 'Cobrança Stripe', 'Beta com 10 usuários'] }, ]; return (
{weeks.map((w) => (
Sem {w.w}
{w.t}
))}
); } const roadmapStyles = ` .rm-hero { display: grid; grid-template-columns: 1fr 1.1fr; gap: 24px; padding: 28px; border-radius: var(--radius-lg); background: linear-gradient(135deg, color-mix(in oklch, var(--grape) 14%, var(--surface)) 0%, color-mix(in oklch, var(--cyan) 12%, var(--surface)) 100%); border: 1px solid var(--line); box-shadow: var(--shadow-card); } .rm-hero h2 { margin: 6px 0 10px; font-size: 24px; font-weight: 800; letter-spacing: -0.02em; } .rm-hero p { margin: 0; color: var(--text-soft); font-size: 14px; line-height: 1.55; } .rm-arch { background: var(--surface); border-radius: var(--radius); padding: 8px; } @media (max-width: 980px) { .rm-hero { grid-template-columns: 1fr; } } .rm-grid { display: grid; grid-template-columns: 1.2fr 1fr; gap: 14px; } @media (max-width: 980px) { .rm-grid { grid-template-columns: 1fr; } } .rm-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 22px; box-shadow: var(--shadow-card); display: flex; flex-direction: column; gap: 14px; } .rm-card-head { display: flex; align-items: center; gap: 10px; } .rm-card-head h3 { margin: 0; font-size: 17px; font-weight: 700; letter-spacing: -0.01em; } .rm-emoji { width: 36px; height: 36px; border-radius: 10px; background: var(--surface-2); display: flex; align-items: center; justify-content: center; font-size: 18px; } .rm-table { width: 100%; border-collapse: collapse; font-size: 13.5px; } .rm-table th { text-align: left; font-weight: 600; color: var(--text-soft); padding: 8px 0; width: 30%; vertical-align: top; } .rm-table td { padding: 8px 0; border-top: 1px dashed var(--line); color: var(--text); line-height: 1.5; } .rm-table tr:first-child td, .rm-table tr:first-child th { border-top: 0; } .rm-table code { font-family: var(--font-mono); font-size: 11.5px; padding: 1px 6px; background: var(--surface-2); border-radius: 5px; color: var(--coral); } .rm-cost-tier { padding: 14px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface-2); display: flex; flex-direction: column; gap: 6px; } .rm-cost-name { font-weight: 700; font-size: 13.5px; } .rm-cost-amount { font-size: 22px; font-weight: 800; letter-spacing: -0.02em; } .rm-cost-amount .muted { font-size: 13px; font-weight: 500; } .rm-cost-tier ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; color: var(--text-soft); font-size: 12.5px; } .rm-cost-tier li::before { content: "•"; color: var(--grape); margin-right: 6px; } .rm-steps { padding-left: 0; margin: 0; counter-reset: step; list-style: none; display: flex; flex-direction: column; gap: 10px; } .rm-steps li { padding: 10px 14px 10px 44px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2); font-size: 13.5px; line-height: 1.5; position: relative; counter-increment: step; } .rm-steps li::before { content: counter(step); position: absolute; left: 12px; top: 12px; width: 22px; height: 22px; border-radius: 50%; background: var(--grape); color: #fff; font-weight: 700; font-size: 11.5px; display: flex; align-items: center; justify-content: center; } .rm-steps code { font-family: var(--font-mono); font-size: 11.5px; padding: 1px 5px; background: var(--surface); border-radius: 5px; color: var(--coral); border: 1px solid var(--line); } .rm-warn { display: inline-block; margin-left: 6px; font-size: 11.5px; font-weight: 600; padding: 2px 8px; background: color-mix(in oklch, var(--sun) 16%, var(--surface)); color: var(--sun); border-radius: 999px; } .rm-code { border: 1px solid var(--line); border-radius: 12px; overflow: hidden; } .rm-code-head { display: flex; justify-content: space-between; align-items: center; padding: 8px 14px; background: var(--surface-2); border-bottom: 1px solid var(--line); font-size: 12px; font-weight: 600; color: var(--text-soft); } .rm-code pre { margin: 0; padding: 14px 16px; font-family: var(--font-mono); font-size: 12px; line-height: 1.55; color: var(--text); overflow-x: auto; background: var(--surface); white-space: pre; } .rm-timeline { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; } @media (max-width: 900px) { .rm-timeline { grid-template-columns: 1fr 1fr; } } .rm-week { border: 1px solid var(--line); border-radius: 12px; padding: 14px; background: var(--surface-2); display: flex; flex-direction: column; gap: 10px; } .rm-week-head { display: flex; align-items: baseline; gap: 8px; } .rm-week-num { font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; padding: 2px 8px; border-radius: 999px; background: color-mix(in oklch, var(--grape) 14%, var(--surface)); color: var(--grape); } .rm-week-title { font-weight: 700; font-size: 14px; } .rm-week ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; font-size: 12.5px; color: var(--text-soft); } .rm-week li { display: flex; align-items: center; gap: 6px; } .rm-week svg { color: var(--green); flex-shrink: 0; } .rm-cta { background: linear-gradient(135deg, color-mix(in oklch, var(--coral) 12%, var(--surface)), color-mix(in oklch, var(--grape) 10%, var(--surface))); } .rm-cta h3 { font-size: 16px; } `; window.Roadmap = Roadmap;