# Make Systems para agentes de IA

Este arquivo é para o agente de IA (Claude, Gemini, ChatGPT, Codex ou outro) que entra no navegador de uma pessoa para mexer no Make Systems dela. Leia tudo antes do primeiro clique.

Endereço deste arquivo: https://makesystems.pro/agentes.md

## O que é o Make Systems

Um quadro infinito para desenhar funis de venda, sistemas de marketing e mapas mentais. Cada projeto tem blocos (páginas, anúncios, e-mails, planilhas, notas) ligados por setas. O app fica em https://app.makesystems.pro e a pessoa precisa estar logada.

Tipos de projeto e endereço de cada um:

| Tipo (`kind`) | Nome na tela | Endereço |
|---|---|---|
| `funnel` | Sistema | `/system/<id>` |
| `map` | Mapa mental | `/mapa/<id>` |
| `strategy` | Estratégia | `/strategy/<id>` |
| `freedraw` | InfiniDraw | `/draw/<id>` |
| `slides` | Slides | `/slides/<id>` |

A lista de projetos fica em `/d/todos`. O id tem 8 caracteres, como `f_12qsjo6h`.

## Você e o Agente Ignite

O Make Systems tem um assistente próprio, o Agente Ignite, no ícone de IA do editor. Ele gasta os créditos de IA da conta da pessoa. Você, agente de fora, gasta os tokens do plano que a pessoa paga na sua IA, e não usa crédito nenhum do Make Systems.

Por isso a pessoa escolheu você para esta tarefa. Não abra o Agente Ignite para fazer o trabalho no seu lugar, porque isso gasta os créditos dela. A exceção são mapas mentais (veja "Mapas mentais"). Nesse caso, pergunte antes.

## Regras antes de tudo

1. Nunca apague um projeto, uma seção inteira ou um grupo de blocos sem a pessoa pedir com essas palavras.
2. Antes de gravar, leia o projeto do servidor. Outra pessoa pode estar editando junto.
3. Grave um passo de cada vez e confira se entrou. Não mande 300 blocos de uma vez sem testar com 3.
4. Se o servidor recusar a gravação, pare e releia. Nunca force.
5. Use o bloco certo para cada coisa. A seção "Qual bloco usar" diz qual. O erro mais comum é montar tabela com dezenas de notas (veja "Planilha").
6. Não mexa em Minha conta, plano, pagamento, compartilhamento ou lixeira sem pedido explícito.

## Dois jeitos de trabalhar

Clicando na tela: serve para ajustes pequenos (mudar um texto, ligar dois blocos). É lento para muitos blocos.

Pela API, de dentro da aba logada: serve para criar ou mudar muitos blocos. O navegador já tem o cookie da sessão, então um `fetch` feito na própria aba do Make Systems funciona sem chave nenhuma. É o caminho recomendado para qualquer coisa com mais de 5 blocos.

A tela aberta no mesmo projeto puxa as mudanças sozinha a cada 2,5 segundos. A pessoa vê os blocos aparecendo.

## A API (rodar na aba de app.makesystems.pro)

Todas as rotas são do mesmo domínio e usam o cookie da sessão.

| Ação | Rota |
|---|---|
| Listar projetos | `GET /api/funnels` |
| Ler um projeto | `GET /api/funnels/<id>` |
| Versão atual (leve) | `GET /api/funnels/<id>/peek` devolve `{ updatedAt }` |
| Gravar mudanças | `PUT /api/funnels/<id>` |
| Criar projeto | `POST /api/funnels` com `{ name, kind, nodes, edges }` |
| Subir imagem | `POST /api/upload` com `{ dataUrl }` devolve `{ url }` |

### Receita de gravação segura

```js
const ID = 'f_xxxxxxxx'
const f = await fetch(`/api/funnels/${ID}`, { cache: 'no-store' }).then(r => r.json())

// 1. mude f.nodes e f.edges aqui (acrescente, nunca recrie a lista do zero)
const novos = [/* blocos novos */]
const nodes = [...f.nodes, ...novos]

// 2. grave dizendo em qual versão você se baseou
const r = await fetch(`/api/funnels/${ID}`, {
  method: 'PUT',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ nodes, edges: f.edges, baseUpdatedAt: f.updatedAt, strict: true }),
}).then(r => r.json())

// 3. confira a resposta
if (r.rejected) console.log('Alguém salvou no meio. Releia e refaça a mudança em cima da versão nova.')
else if (r.staleBlocked) console.log('O servidor recusou porque o projeto ia encolher. Releia.')
else console.log('Gravado. Blocos agora:', r.nodes.length, 'versão', r.updatedAt)
```

O que o servidor faz para proteger o projeto:

- `strict: true` com `baseUpdatedAt`: se alguém salvou depois da sua leitura, nada é gravado e a resposta volta com `rejected: true`.
- Gravação atrasada que tem menos blocos que o atual é recusada (`staleBlocked`).
- Lista de blocos vazia num projeto com 5 blocos ou mais é recusada.
- Toda gravação guarda uma versão no histórico. A pessoa desfaz pelo menu de versões do editor.

Para apagar um bloco de propósito, tire ele de `nodes` e tire as setas dele de `edges`, com a leitura em dia.

## Formato dos dados

### Projeto

```json
{ "id": "f_12qsjo6h", "name": "Funil do curso", "kind": "funnel",
  "nodes": [], "edges": [], "updatedAt": "2026-10-27T19:50:45.061Z" }
```

### Bloco (node)

```json
{ "id": "a1B2c3D4", "type": "page", "position": { "x": 451, "y": 100 },
  "data": { "catalogType": "pagina-vendas", "label": "VSL", "url": "https://..." },
  "style": { "width": 170, "height": 280 } }
```

- `id`: 8 letras e números aleatórios. Tem que ser único no projeto. Nunca reaproveite id de outro bloco.
- `type`: a família do bloco (tabela abaixo).
- `data.catalogType`: qual bloco do catálogo é. Define ícone e nome.
- `data.label`: o nome que aparece no bloco.
- `data.notes`: texto livre que abre ao clicar no bloco. Use para explicar o bloco.
- `position`: em pixels no quadro. `x` cresce para a direita, `y` para baixo.
- `style.width` e `style.height`: tamanho. Use o padrão da tabela.

### Seta (edge)

```json
{ "id": "e1f2g3h4", "source": "<id do bloco de origem>", "target": "<id do destino>",
  "sourceHandle": "r", "targetHandle": "l", "type": "default", "data": {} }
```

Pontos de saída (`sourceHandle`): `r` (direita), `b` (embaixo), `l-s` (esquerda), `t-s` (em cima).
Pontos de chegada (`targetHandle`): `l` (esquerda), `t` (em cima), `r-t` (direita), `b-t` (embaixo).
O bloco Se/ou (`logic`) tem duas saídas: `sim` e `nao`.

## Qual bloco usar

| Quero mostrar | `type` | `catalogType` | Tamanho padrão |
|---|---|---|---|
| Página (vendas, captura, obrigado, VSL) | `page` | `pagina-vendas`, `pagina-captura`, `pagina-obrigado`, `pagina-branco` | 170 × 280 |
| Checkout | `page` | `pedido` | 170 × 280 |
| Upsell, downsell | `page` | `upsell`, `downsell` | 170 × 280 |
| Área de membros | `page` | `area-membros` | 170 × 280 |
| Quiz ou pesquisa | `page` | `pesquisa-pagina` | 170 × 280 |
| Origem de tráfego (Meta Ads, Google Ads, Instagram, YouTube) | `traffic` | `meta-ads`, `google-ads`, `instagram-base`, `youtube` | 56 × 56 |
| Ferramenta ou integração (Hubla, Hotmart, Utmify, Zapier, ChatGPT) | `traffic` | `hubla`, `hotmart`, `utmify`, `zapier`, `chatgpt` | 56 × 56 |
| Anúncio (imagem ou vídeo) | `creative` | `criativo` | 150 × 200 |
| Evento (compra, reembolso, lead, esperar, tag) | `action` | `compra`, `reembolso`, `lead`, `esperar`, `tag` | 56 × 56 |
| E-mail, WhatsApp, SMS | `action` | `email-base`, `sequencia-email`, `whatsapp`, `sequencia-whatsapp`, `sms` | 56 × 56 |
| Decisão (se/ou) | `logic` | `se-ou` | 60 × 60 |
| Botão com link clicável | `component` | `botao-link` | 150 × 50 |
| Texto, explicação, lista | `note` | (sem catalogType) | 200 × 150 |
| Área que agrupa blocos | `section` | `secao` | 480 × 340 |
| Imagem | `image` | (sem catalogType) | 240 × 160 |
| Tabela com números e contas | `sheet` | `planilha` | 980 × 560 |
| Calculadora de ROI, CPA, ROAS | `metrics` | `calculadora-metricas` | 440 × 600 |
| Concorrente (biblioteca de anúncios) | `competitor` | `concorrente` | 256 × 212 |

O catálogo tem 349 blocos. Para achar o `catalogType` de uma ferramenta, leia um bloco igual que já exista em algum projeto, ou insira um pelo navegador de elementos (dock da esquerda) e leia o projeto pela API. O id costuma ser o nome em minúsculas, com hífen entre palavras (`google-sheets`, `meta-ads`), mas há exceções (`activecampaign`, `pedido` para Checkout).

Páginas de venda, checkout, upsell, downsell e order bump com `price` entram na conta do TDR (teto de receita) da seção onde estão.

Campos que valem a pena preencher:

- Página: `url`, `button` (texto do botão), `price` (como texto, "297,00"), `currency` ("R$"), `priceOn` (false esconde o preço).
- Checkout: `price`, `currency`, `billing` ("once" ou "monthly"), `gateways: [{ "type": "hubla", "url": "..." }]`.
- Tráfego: `url` ou `docUrl` (link que abre no clique).
- Esperar: `waitAmount` ("3") e `waitUnit` ("dias", "horas", "minutos").
- Botão com link: `url`.
- Imagem: `src` (URL pública, suba antes por `/api/upload` se for arquivo local) e `radius`.

### Nota

```json
{ "id": "n0t3AbCd", "type": "note", "position": { "x": 1500, "y": 60 },
  "data": { "html": "<b>Números do mês</b><ul><li>47 vendas</li><li>15 reembolsos</li></ul>",
            "color": "#FEF3C7", "fsize": 16, "align": "left" },
  "style": { "width": 280, "height": 170 } }
```

HTML aceito: `b`, `strong`, `i`, `em`, `u`, `s`, `mark`, `br`, `div`, `p`, `span`, `ul`, `ol`, `li`, `h1`, `h2`, `h3`, `blockquote`, `a`. O resto é removido.

### Seção

```json
{ "id": "s3cAbCdE", "type": "section", "position": { "x": -80, "y": -110 },
  "data": { "catalogType": "secao", "label": "1 · Funil de venda", "color": "#e11d48", "opacity": 0.04 },
  "style": { "width": 2400, "height": 1200 } }
```

A seção é um retângulo atrás dos blocos. Os blocos não ficam "dentro" dela no JSON. Um bloco pertence à seção quando o centro dele cai dentro da área. Deixe 40 px de folga nas bordas.

## Planilha

Use a Planilha sempre que o conteúdo for uma tabela: relatório diário, balanço, lista de leads, custos, metas. Ela calcula sozinha, aceita fórmulas em português e em inglês e tem formato de moeda.

Erro real que motivou esta seção: um agente montou um balanço de 26 dias com 350 blocos de nota, um por célula. Ficou pesado, não recalculava e cada dia novo exigia 13 notas novas. Uma Planilha com fórmulas resolve isso num bloco só.

Na tela, a Planilha fica no dock da esquerda, em Utilidades (o botão com a chave inglesa). No mesmo menu tem "Importar planilha (.xlsx ou .csv)", que cria uma Planilha a partir de um arquivo. Se a pessoa já tem o relatório em CSV, importar é o caminho mais curto.

### Formato

```json
{ "id": "pL4nIlhA", "type": "sheet", "position": { "x": 0, "y": 8300 },
  "style": { "width": 1300, "height": 700 },
  "data": {
    "catalogType": "planilha",
    "label": "Balanço diário",
    "active": "t1",
    "tabs": [{
      "id": "t1", "name": "Outubro", "rows": 100, "cols": 26,
      "cells": {
        "A1": "Dia", "B1": "Gasto", "C1": "Vendas", "D1": "Faturamento", "E1": "Lucro", "F1": "ROAS",
        "A2": "01/10", "B2": "493,07", "C2": "1", "D2": "273,16", "E2": "=D2-B2", "F2": "=SEERRO(D2/B2;0)",
        "A3": "02/10", "B3": "417,77", "C3": "1", "D3": "273,16", "E3": "=D3-B3", "F3": "=SEERRO(D3/B3;0)",
        "A33": "Total", "B33": "=SOMA(B2:B32)", "C33": "=SOMA(C2:C32)", "D33": "=SOMA(D2:D32)",
        "E33": "=D33-B33", "F33": "=SEERRO(D33/B33;0)"
      },
      "st": {
        "A1": { "b": 1, "bg": "#E5E7EB" }, "B1": { "b": 1, "bg": "#E5E7EB" },
        "B2": { "f": "brl" }, "D2": { "f": "brl" }, "E2": { "f": "brl" },
        "A33": { "b": 1 }, "B33": { "f": "brl", "b": 1 }
      },
      "notes": {}, "colW": { "0": 90, "1": 120 }, "rowH": {}, "merges": [],
      "freezeR": 1, "freezeC": 1
    }]
  } }
```

- `cells`: a chave é a célula (A1, B2). O valor é sempre texto. Começando com `=` vira fórmula. Número pode ir com vírgula decimal ("493,07").
- Fórmulas aceitas: SOMA, MÉDIA, MED, MÍNIMO, MÁXIMO, MULT, CONT.NÚM, CONT.VALORES, CONTAR.VAZIO, ARRED, ARREDONDAR.PARA.CIMA, ARREDONDAR.PARA.BAIXO, INT, RESTO, POTÊNCIA, RAIZ, ABS, SE, SES, E, OU, NÃO, SEERRO, SOMASE, CONT.SE, MÉDIASE, PROCV, CONCATENAR, NÚM.CARACT, MAIÚSCULA, MINÚSCULA, ARRUMAR, ESQUERDA, DIREITA, HOJE, DATA, DIA, MÊS, ANO. Os nomes em inglês também valem (SUM, IF, VLOOKUP). Separador de argumentos: `;`.
- Referência a outra página: `='Setembro'!B33`.
- `st` (estilo por célula): `b` negrito, `i` itálico, `u` sublinhado, `color` cor do texto, `bg` fundo, `fs` tamanho da letra, `ha` alinhamento ("left", "center", "right"), `f` formato ("brl", "usd", "eur", "pct", "date", "num", "text"), `dec` casas decimais.
- `colW`: largura da coluna em px, pelo número da coluna (0 = A). `freezeR` e `freezeC` congelam linhas e colunas.
- Várias páginas: mais itens em `tabs`, cada um com `id` e `name` próprios.

Para acrescentar um dia novo, leia o bloco, escreva só as células da linha nova e as fórmulas dela, e grave. Não recrie a planilha.

## Calculadora de Métricas

Bloco `type: "metrics"`, `catalogType: "calculadora-metricas"`. Calcula lucro, ROI, ROAS, ROAS de empate e CPA máximo a partir de tráfego, funil, ofertas e custos. Crie com `data: { "catalogType": "calculadora-metricas", "label": "Métricas do funil" }` e preencha os campos pela tela, que mostra o nome de cada um.

## Mapas mentais

Mapas mentais (`/mapa/<id>`) têm layout automático e formato interno próprio. Para criar ou reorganizar um mapa, importe um arquivo .opml, .rtf ou .mm (o caminho preferido, sem custo) ou, se a pessoa autorizar o gasto de créditos, use o Agente Ignite dentro do editor (ícone de IA). Pela API, mude só o texto de blocos que já existem.

## Organização no quadro

- Fluxo da esquerda para a direita. Passos seguidos ficam a 170 a 300 px um do outro no eixo x.
- Caminhos alternativos (reembolso, recusou) ficam embaixo do passo de origem, ligados pela saída `b`.
- Uma seção por assunto, uma embaixo da outra, com 150 px entre elas. Numere os nomes ("1 · Funil hoje", "2 · Área de membros").
- Explicação longa vai em `data.notes` do bloco, ou numa nota ao lado. Não escreva parágrafos no `label`.
- Antes de criar uma área nova, procure o maior `y` usado no projeto e comece 200 px abaixo dele.

## Receitas

Relatório diário (Utmify, gerenciador de anúncios, gateway): uma Planilha por mês, uma linha por dia, colunas com fórmulas para lucro, ROAS e CPA, linha de total com SOMA. Uma nota curta ao lado com o que fazer amanhã.

Funil a partir de uma descrição: tráfego → criativo → página → checkout → compra → upsell → obrigado, com reembolso saindo da compra pela saída de baixo. Uma seção em volta.

Auditoria de um projeto: leia o JSON, liste blocos sem `label`, setas que apontam para blocos que não existem, ids repetidos e páginas sem `url`. Mostre a lista para a pessoa antes de corrigir.

## Ajuda

Central de Ajuda para pessoas: https://help.makesystems.pro
