# Manual da IA — FOXY Planner

## Conectando ao ChatGPT / Claude (MCP)

Para conectar o Foxy Planner ao seu chat de IA favorito, use as seguintes informações:

- **Nome:** Foxy Planner
- **Descrição:** Gerencie clientes, projetos e entregas no Foxy Planner.
- **URL do servidor MCP:** `https://imwnuqpnqbtexfozmvhr.supabase.co/functions/v1/mcp`
- **Tipo:** MCP (Model Context Protocol)
- **Autenticação:** OAuth 2.1 com PKCE — Client ID e Secret não são necessários

Protocolo versão **1.0**.

Este documento é gerado a partir do próprio registro de comandos do sistema. Se um comando
existe, ele está aqui; se um campo mudou, a mudança já está refletida abaixo.

## O que este sistema é

O FOXY Planner organiza a operação de duas empresas (MELLOW e FOXY) e dos clientes delas.
Em vez de navegar pela interface, uma IA descreve o que quer em comandos estruturados, o
sistema valida contra o estado atual, mostra uma prévia e só então executa.

## Hierarquia oficial

```
Unidade             (MELLOW, FOXY, DESTINOS INCRIVEIS, CONSULTORIA IA, PESSOAL)
  -> Workspace/Pasta (o cliente ou a marca: TURAZZA, M2E, FILTROS SA...)
       -> Projeto/Card
            -> Entrega/Subcard
                 -> Tarefas, checklist, arquivos, comentarios e historico
```

Equivalência no banco, útil para entender mensagens de erro:

| Camada | Tabela |
| --- | --- |
| Unidade | `business_units` |
| Workspace | `workspaces` |
| Projeto/Card | `missions` |
| Entrega/Subcard | `mission_steps` ou `cards`, conforme o modulo legado |
| Tarefas e detalhes | `mission_steps`, comentarios, anexos e historico |

Nao crie niveis infinitos. A interface deve parar em Entrega/Subcard; abaixo disso ficam
tarefas, checklist, descricao, arquivos, comentarios, responsavel, status, prioridade, prazo
e proxima acao. Um card vive numa coluna (`columns`) de um board (`boards`), e opcionalmente
aponta para um projeto.

## Envelope

Todo lote é um único objeto JSON:

```json
{
  "version": "1.0",
  "source": "chatgpt",
  "intent": "Montar a campanha de agosto da TURAZZA",
  "confirmDestructive": false,
  "commands": [
    {
      "command": "create_project",
      "ref": "campanha-agosto",
      "params": {
        "title": "Campanha Agosto",
        "workspace": "TURAZZA",
        "status": "active"
      }
    },
    {
      "command": "create_card",
      "params": {
        "title": "Roteiro",
        "column": "Conteúdo TURAZZA / A fazer",
        "project": "ref:campanha-agosto"
      }
    }
  ]
}
```

`source` aceita: `chatgpt`, `claude`, `codex`, `gemini`, `agent`, `ui`, `unknown`.

## Como apontar para um objeto

Todo campo do tipo `entity` aceita três formas:

1. **O id** (UUID). Sempre sem ambiguidade — prefira quando você já leu o objeto.
2. **O nome exato.** Acento e caixa são ignorados. Se o nome casar com mais de um objeto,
   a validação devolve `ambiguous` e nada é executado.
3. **`ref:apelido`.** Aponta para algo que um comando anterior *do mesmo lote* vai criar.
   É assim que se cria um projeto e seus cards numa única requisição.

Colunas repetem nome entre boards ("A fazer" existe em vários). Para essas, use a forma
qualificada `"Board / Coluna"`.

## Comandos em lote

Os comandos rodam na ordem em que aparecem. Um `create_card` pode referenciar o projeto
que o `create_project` anterior cria, via `ref`. Se qualquer comando falhar durante a
execução, os que já rodaram são desfeitos automaticamente — o lote é tudo ou nada.

## Validação

Antes de executar, o sistema confere:

- o comando existe e a versão do protocolo bate;
- todo campo obrigatório está preenchido e com o tipo certo;
- todo `entity` foi encontrado, e encontrado uma vez só;
- não há duplicidade: workspace com nome repetido, projeto repetido no mesmo workspace,
  card repetido na mesma coluna, apelido `ref` repetido no lote;
- não há conflito: mover um card para a coluna onde ele já está, `update` sem nenhum campo
  para alterar, subtarefa sem card nem projeto;
- comandos que exigem confirmação vieram com `confirmDestructive: true`.

Qualquer problema aborta o lote inteiro. A resposta traz `index` (qual comando), `field`
(qual campo), `code` e um `hint` com o que fazer.

## Segurança

Nenhum comando apaga linha do banco. Não existe `delete_*` no protocolo: arquivar é
visibilidade e encerrar projeto é status, ambos reversíveis.

Estes comandos exigem `confirmDestructive: true`:

- `archive_workspace` — Some da navegação inteira: sidebar, dashboard, missões, calendário e financeiro deixam de mostrar o conteúdo.
- `create_contract` — Mexe em valores financeiros e altera o recorrente mensal conhecido.
- `update_contract` — Mexe em valores financeiros e altera o recorrente mensal conhecido.
- `add_access` — Altera permissões: muda o que uma pessoa enxerga no sistema.
- `update_access` — Altera permissões: muda o que uma pessoa pode fazer no sistema.

Fora do protocolo, e portanto impossível para uma IA: excluir workspace, projeto ou
contrato, e alterar senhas e credenciais. Isso continua sendo feito por um humano na
interface.

## Desfazer

Toda execução grava a operação inversa de cada comando: o que foi criado guarda o id para
remoção, o que foi alterado guarda os valores anteriores. O botão Desfazer replica esses
inversos na ordem contrária. Um lote já desfeito não pode ser desfeito de novo.

## Boas práticas

1. **Leia antes de escrever.** Peça a estrutura atual e use ids quando puder.
2. **Um lote por intenção.** "Montar a campanha de agosto" é um lote; três pedidos soltos
   viram três históricos e três undos.
3. **Preencha `intent`.** É o que o humano lê no histórico meses depois.
4. **Defina `next_action` em todo projeto ativo.** O painel "Onde focar" cobra isso.
5. **Não invente valores financeiros.** Contrato e receita exigem confirmação por um motivo.
6. **Prefira `update_*` a recriar.** Recriar duplica e a validação vai recusar.

## Fluxos completos

### Montar uma campanha do zero

```json
{
  "version": "1.0",
  "source": "claude",
  "intent": "Campanha de agosto da TURAZZA com as quatro etapas",
  "commands": [
    {
      "command": "create_project",
      "ref": "camp-ago",
      "params": {
        "title": "Campanha de Agosto",
        "workspace": "TURAZZA",
        "status": "active",
        "next_action": "Fechar roteiro com o cliente"
      }
    },
    {
      "command": "create_card",
      "ref": "c1",
      "params": {
        "title": "Roteiro",
        "column": "A fazer",
        "project": "ref:camp-ago"
      }
    },
    {
      "command": "create_card",
      "params": {
        "title": "Gravação",
        "column": "A fazer",
        "project": "ref:camp-ago"
      }
    },
    {
      "command": "create_card",
      "params": {
        "title": "Edição",
        "column": "A fazer",
        "project": "ref:camp-ago"
      }
    },
    {
      "command": "create_card",
      "params": {
        "title": "Aprovação",
        "column": "A fazer",
        "project": "ref:camp-ago"
      }
    },
    {
      "command": "create_subtask",
      "params": {
        "title": "Levantar referências",
        "card": "ref:c1"
      }
    }
  ]
}
```

### Fechar o dia

```json
{
  "version": "1.0",
  "source": "chatgpt",
  "intent": "Fechamento de quinta na M2E",
  "commands": [
    {
      "command": "move_card",
      "params": {
        "card": "Roteiro",
        "column": "Concluído"
      }
    },
    {
      "command": "update_card",
      "params": {
        "card": "Gravação",
        "status": "in_production"
      }
    },
    {
      "command": "add_comment",
      "params": {
        "card": "Gravação",
        "content": "Gravação marcada para segunda, 14h."
      }
    },
    {
      "command": "update_project",
      "params": {
        "project": "HUB M2E",
        "next_action": "Revisar onboarding de RH"
      }
    }
  ]
}
```

## Referência dos comandos

São 21 comandos.

### `create_workspace`

Cria um workspace (cliente ou marca) dentro de uma unidade.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `name` | string | **sim** | Nome do workspace. |
| `business_unit` | entity(business_unit) | não | Unidade dona do workspace (MELLOW, FOXY, PESSOAL). Sem isto fica "sem unidade". |
| `workspace_kind` | enum(client_or_brand \| product_base \| client_implementation \| internal \| personal) | não | Natureza do workspace. Padrão: `"client_or_brand"`. |
| `description` | text | não | Descrição livre. |

*Novo cliente na MELLOW*

```json
{
  "command": "create_workspace",
  "ref": "nova-marca",
  "params": {
    "name": "NOVA MARCA",
    "business_unit": "MELLOW",
    "workspace_kind": "client_or_brand"
  }
}
```

### `update_workspace`

Renomeia um workspace ou muda a unidade/natureza dele.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `workspace` | entity(workspace) | **sim** | Workspace alvo. |
| `name` | string | não | Novo nome. |
| `business_unit` | entity(business_unit) | não | Nova unidade. |
| `workspace_kind` | enum(client_or_brand \| product_base \| client_implementation \| internal \| personal) | não | Nova natureza. |
| `description` | text | não | Nova descrição. |

*Renomear PRO ACE*

```json
{
  "command": "update_workspace",
  "params": {
    "workspace": "PRO ACE",
    "name": "POSTO 011"
  }
}
```

### `archive_workspace`

Tira um workspace da navegação. Não apaga nada e é reversível.

> **Exige confirmação.** Some da navegação inteira: sidebar, dashboard, missões, calendário e financeiro deixam de mostrar o conteúdo. Envie `"confirmDestructive": true` no envelope, senão a validação recusa o lote inteiro.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `workspace` | entity(workspace) | **sim** | Workspace alvo. |
| `archived` | boolean | não | false para desarquivar. Padrão: `true`. |

*Arquivar OUTROS*

```json
{
  "command": "archive_workspace",
  "params": {
    "workspace": "OUTROS"
  }
}
```

### `create_project`

Cria um projeto dentro de um workspace. Projeto é uma missão no banco.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `title` | string | **sim** | Nome do projeto. |
| `workspace` | entity(workspace) | **sim** | Workspace dono. |
| `parent_project` | entity(project) | não | Projeto-pai, quando este é um subprojeto (a "pasta" que agrupa). |
| `objective` | text | não | Objetivo do projeto. |
| `description` | text | não | Descrição livre. |
| `status` | enum(planning \| active \| paused \| completed \| cancelled) | não | Status. Padrão: `"planning"`. |
| `mission_type` | enum(pontual \| continuo \| recorrente \| campanha) | não | Tipo. Padrão: `"pontual"`. |
| `priority` | enum(low \| medium \| high \| critical) | não | Prioridade. Padrão: `"medium"`. |
| `start_date` | date | não | Início (YYYY-MM-DD). |
| `end_date` | date | não | Prazo (YYYY-MM-DD). |
| `next_action` | string | não | Próxima ação. Todo projeto ativo deveria ter uma. |
| `next_action_due_date` | date | não | Prazo da próxima ação. |
| `estimated_hours` | number | não | Horas estimadas, usadas no cálculo de sobrecarga. |

*Projeto novo na TURAZZA*

```json
{
  "command": "create_project",
  "ref": "campanha-agosto",
  "params": {
    "title": "Campanha Agosto",
    "workspace": "TURAZZA",
    "status": "active",
    "next_action": "Fechar roteiro"
  }
}
```

### `update_project`

Altera campos de um projeto existente.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `project` | entity(project) | **sim** | Projeto alvo. |
| `title` | string | não | Novo nome. |
| `objective` | text | não | Novo objetivo. |
| `description` | text | não | Nova descrição. |
| `status` | enum(planning \| active \| paused \| completed \| cancelled) | não | Novo status. |
| `priority` | enum(low \| medium \| high \| critical) | não | Nova prioridade. |
| `start_date` | date | não | Novo início. |
| `end_date` | date | não | Novo prazo. |
| `next_action` | string | não | Nova próxima ação. |
| `next_action_due_date` | date | não | Novo prazo da próxima ação. |
| `estimated_hours` | number | não | Novas horas estimadas. |

*Definir próxima ação*

```json
{
  "command": "update_project",
  "params": {
    "project": "Campanha Agosto",
    "next_action": "Aprovar roteiro com o cliente"
  }
}
```

### `archive_project`

Conclui um projeto (status completed). Ele passa a viver em Arquivados.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `project` | entity(project) | **sim** | Projeto alvo. |
| `status` | enum(completed \| cancelled) | não | Como encerrar. Padrão: `"completed"`. |

*Concluir*

```json
{
  "command": "archive_project",
  "params": {
    "project": "Campanha Agosto"
  }
}
```

### `create_card`

Cria um card. Precisa de uma coluna; informe a coluna ou o projeto e o board.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `title` | string | **sim** | Título do card. |
| `column` | entity(column) | **sim** | Coluna onde o card nasce. Use "Board / Coluna" quando o nome da coluna se repetir. |
| `project` | entity(project) | não | Projeto ao qual o card pertence. |
| `description` | text | não | Descrição. |
| `card_type` | enum(content \| financial \| task \| mixed \| recording \| campaign \| meeting \| credential) | não | Tipo do card. Padrão: `"task"`. |
| `status` | enum(planned \| in_production \| scheduled \| posted \| cancelled) | não | Status. Padrão: `"planned"`. |
| `production_stage` | enum(idea \| recording \| editing \| approval \| scheduled \| posted) | não | Etapa de produção. |
| `start_date` | date | não | Data de início (YYYY-MM-DD). |
| `end_date` | date | não | Data de entrega (YYYY-MM-DD). |

*Card dentro do projeto recém-criado*

```json
{
  "command": "create_card",
  "params": {
    "title": "Roteiro",
    "column": "A fazer",
    "project": "ref:campanha-agosto",
    "card_type": "task"
  }
}
```

### `update_card`

Altera campos de um card. Para trocar de coluna use move_card.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `card` | entity(card) | **sim** | Card alvo. |
| `title` | string | não | Novo título. |
| `description` | text | não | Nova descrição. |
| `status` | enum(planned \| in_production \| scheduled \| posted \| cancelled) | não | Novo status. |
| `card_type` | enum(content \| financial \| task \| mixed \| recording \| campaign \| meeting \| credential) | não | Novo tipo. |
| `production_stage` | enum(idea \| recording \| editing \| approval \| scheduled \| posted) | não | Nova etapa. |
| `start_date` | date | não | Nova data de início. |
| `end_date` | date | não | Nova data de entrega. |
| `project` | entity(project) | não | Vincular a outro projeto. |

*Marcar como em produção*

```json
{
  "command": "update_card",
  "params": {
    "card": "Roteiro",
    "status": "in_production"
  }
}
```

### `move_card`

Move um card para outra coluna e/ou posição.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `card` | entity(card) | **sim** | Card a mover. |
| `column` | entity(column) | **sim** | Coluna de destino. |
| `position` | number | não | Posição na coluna. Sem isto, vai para o fim. |

*Mover para Concluído*

```json
{
  "command": "move_card",
  "params": {
    "card": "Roteiro",
    "column": "Concluído"
  }
}
```

### `create_subtask`

Cria uma subtarefa dentro de um card ou de um projeto.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `title` | string | **sim** | Título da subtarefa. |
| `card` | entity(card) | não | Card dono. Informe card ou project. |
| `project` | entity(project) | não | Projeto dono. Informe card ou project. |
| `description` | text | não | Detalhe. |
| `due_date` | date | não | Prazo (YYYY-MM-DD). |
| `position` | number | não | Ordem. Sem isto, vai para o fim. |

*Subtarefa de um card*

```json
{
  "command": "create_subtask",
  "params": {
    "title": "Levantar referências",
    "card": "Roteiro"
  }
}
```

### `update_subtask`

Altera ou conclui uma subtarefa.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `subtask` | entity(subtask) | **sim** | Subtarefa alvo. |
| `title` | string | não | Novo título. |
| `description` | text | não | Novo detalhe. |
| `is_completed` | boolean | não | true conclui, false reabre. |
| `due_date` | date | não | Novo prazo. |

*Concluir subtarefa*

```json
{
  "command": "update_subtask",
  "params": {
    "subtask": "Levantar referências",
    "is_completed": true
  }
}
```

### `create_contract`

Cria um contrato para um cliente da operação, com um ou mais itens de receita.

> **Exige confirmação.** Mexe em valores financeiros e altera o recorrente mensal conhecido. Envie `"confirmDestructive": true` no envelope, senão a validação recusa o lote inteiro.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `client` | entity(workspace) | **sim** | Cliente da operação (casa por nome ou alias). |
| `name` | string | **sim** | Nome do contrato. |
| `items` | string[] | **sim** | Itens de receita no formato "Nome|valor|tipo", com valor em reais e tipo em service/hosting/barter/sporadic/future_product/internal. Hospedagem entra como item separado do serviço. |
| `confirmed_schedule` | string | não | Blocos fixos combinados, em texto. |
| `billing_notes` | text | não | Observações de cobrança. |

*Contrato com serviço e hospedagem separados*

```json
{
  "command": "create_contract",
  "params": {
    "client": "FILTROS SA",
    "name": "Google Ads + hospedagem",
    "items": [
      "Gestão de Google Ads|600|service",
      "Hospedagem|49.90|hosting"
    ]
  }
}
```

### `update_contract`

Altera um contrato existente.

> **Exige confirmação.** Mexe em valores financeiros e altera o recorrente mensal conhecido. Envie `"confirmDestructive": true` no envelope, senão a validação recusa o lote inteiro.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `contract` | entity(contract) | **sim** | Contrato alvo. |
| `name` | string | não | Novo nome. |
| `status` | enum(active \| paused \| archived) | não | Novo status. |
| `confirmed_schedule` | string | não | Novos blocos fixos. |
| `billing_notes` | text | não | Novas observações. |

*Pausar contrato*

```json
{
  "command": "update_contract",
  "params": {
    "contract": "Google Ads + hospedagem",
    "status": "paused"
  }
}
```

### `add_access`

Dá a um membro acesso a um board específico.

> **Exige confirmação.** Altera permissões: muda o que uma pessoa enxerga no sistema. Envie `"confirmDestructive": true` no envelope, senão a validação recusa o lote inteiro.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `user` | entity(user) | **sim** | Membro (e-mail ou id). |
| `board` | entity(board) | **sim** | Board liberado. |

*Liberar um board*

```json
{
  "command": "add_access",
  "params": {
    "user": "pessoa@exemplo.com",
    "board": "Conteúdo TURAZZA"
  }
}
```

### `update_access`

Muda o papel de um membro dentro de um workspace.

> **Exige confirmação.** Altera permissões: muda o que uma pessoa pode fazer no sistema. Envie `"confirmDestructive": true` no envelope, senão a validação recusa o lote inteiro.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `user` | entity(user) | **sim** | Membro (e-mail ou id). |
| `workspace` | entity(workspace) | **sim** | Workspace. |
| `role` | enum(admin \| member \| viewer) | **sim** | Novo papel. |

*Promover a admin*

```json
{
  "command": "update_access",
  "params": {
    "user": "pessoa@exemplo.com",
    "workspace": "TURAZZA",
    "role": "admin"
  }
}
```

### `assign_user`

Atribui um membro a um card.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `user` | entity(user) | **sim** | Membro (e-mail ou id). |
| `card` | entity(card) | **sim** | Card. |

*Atribuir responsável*

```json
{
  "command": "assign_user",
  "params": {
    "user": "pessoa@exemplo.com",
    "card": "Roteiro"
  }
}
```

### `add_comment`

Comenta em um card.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `card` | entity(card) | **sim** | Card. |
| `content` | text | **sim** | Texto do comentário. |

*Registrar decisão*

```json
{
  "command": "add_comment",
  "params": {
    "card": "Roteiro",
    "content": "Cliente aprovou o gancho na reunião de quarta."
  }
}
```

### `link_client_drive_folder`

Define a pasta oficial do cliente no Google Drive.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `workspace` | entity(workspace) | **sim** | Cliente alvo. |
| `folder_url` | string | **sim** | Link da pasta no Drive, ou o id dela. Link de arquivo não serve. |
| `folder_name` | string | não | Nome da pasta como está no Drive. Só para conferência na tela. |

*Vincular a pasta do cliente*

```json
{
  "command": "link_client_drive_folder",
  "params": {
    "workspace": "FILTROS S.A.",
    "folder_url": "https://drive.google.com/drive/folders/145nwW10PWhibuZQLPENFX4oNDeBZN7yo",
    "folder_name": "FILTROS S.A."
  }
}
```

### `unlink_client_drive_folder`

Remove o vínculo de pasta do cliente. Não apaga nada no Drive.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `workspace` | entity(workspace) | **sim** | Cliente alvo. |

*Desvincular pasta errada*

```json
{
  "command": "unlink_client_drive_folder",
  "params": {
    "workspace": "FILTROS S.A."
  }
}
```

### `link_project_drive_folder`

Define a pasta do projeto no Google Drive.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `project` | entity(project) | **sim** | Projeto alvo. |
| `folder_url` | string | **sim** | Link da pasta no Drive, ou o id dela. Pode ser a mesma pasta do cliente. |
| `folder_name` | string | não | Nome da pasta como está no Drive. |

*Vincular a subpasta do projeto*

```json
{
  "command": "link_project_drive_folder",
  "params": {
    "project": "Campanha Agosto",
    "folder_url": "https://drive.google.com/drive/folders/1abcDEF_ghiJKL234"
  }
}
```

### `unlink_project_drive_folder`

Remove o vínculo de pasta do projeto. Não apaga nada no Drive.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `project` | entity(project) | **sim** | Projeto alvo. |

*Desvincular pasta do projeto*

```json
{
  "command": "unlink_project_drive_folder",
  "params": {
    "project": "Campanha Agosto"
  }
}
```
