# tracker by aquarela

> Rastreador de issues, testes e releases da Aquarela, com organizações (empresas) e projetos separados. Registra bugs e melhorias com evidências, ciclos de teste e o Release Gate de cada versão, e guarda a base de conhecimento (documentos) de cada empresa. A interface é em português.

O app inteiro exige login (aquarela ID). Agentes acessam pelo servidor MCP abaixo, e scripts e CI pela API REST, sempre em nome de uma pessoa e das organizações dela: as que ela escolhe ao autorizar o MCP (uma, várias ou todas), ou a do token pessoal.

Versão no ar: 0.2.0 · 4608e9a (versão semântica; o commit identifica o deploy). Também em `GET /api/v1/version`, no whoami e no serverInfo do MCP.

O mesmo manual, uma parte por página, está no portal para desenvolvedores: https://developers.tracker.aquarela.app

## Servidor MCP

- URL: https://tracker.aquarela.app/mcp
- Transporte: Streamable HTTP, sem sessão, respostas JSON (POST).
- Autenticação: OAuth 2.1 com PKCE (S256) e registro dinâmico de cliente (RFC 7591). O cliente descobre tudo a partir do 401 do /mcp (RFC 9728).
- Metadata do recurso: https://tracker.aquarela.app/.well-known/oauth-protected-resource/mcp
- Metadata do servidor de autorização: https://tracker.aquarela.app/.well-known/oauth-authorization-server
- Token de acesso vale 1 hora; o refresh token vale 30 dias e é trocado a cada uso.

## Como conectar

- Claude (web e desktop): Configurações > Conectores > Adicionar conector personalizado, com a URL https://tracker.aquarela.app/mcp.
- Claude Code: `claude mcp add --transport http tracker https://tracker.aquarela.app/mcp` e depois `/mcp` para autorizar.
- Codex: `codex mcp add tracker --url https://tracker.aquarela.app/mcp` e depois `codex mcp login tracker`.
- ChatGPT: Configurações > Apps e conectores > Criar, com a URL https://tracker.aquarela.app/mcp e autenticação OAuth.

Na tela de autorização a pessoa escolhe as organizações (uma, várias, ou todas, inclusive as em que entrar depois) e se o aplicativo pode criar issues. Com mais de uma, toda tool aceita o argumento `organization` (slug ou nome da empresa, veja whoami); sem ele, a empresa sai da issue ou do projeto do pedido quando só uma delas tem esse código, whoami e list_projects mostram todas, e search_issues sem `project` busca em todas (cada issue com `organization`). As conexões ficam em https://tracker.aquarela.app/account/connections, onde podem ser desfeitas.

Sem navegador (CI, agente rodando num pipeline), o /mcp também aceita o token pessoal da API REST no cabeçalho `Authorization: Bearer <token>`, por exemplo `claude mcp add --transport http tracker https://tracker.aquarela.app/mcp --header "Authorization: Bearer $TRACKER_TOKEN"`.

## Permissões

- `tracker:read`: Ler projetos, issues, releases, ciclos de teste e documentos
- `tracker:write`: Criar issues, mudar o status delas e escrever documentos em seu nome

Dentro da organização, a conexão vê só os projetos de que a pessoa é membro (admin e dono da organização veem todos) e cada ação respeita o perfil dela no projeto (PO/PM, QA, dev, stakeholder).

## Tools

- `whoami` (tracker:read): Mostra a pessoa conectada (com o idioma dela em user.locale: pt-BR, en, es, ou null no automático), as empresas desta conexão, o papel dela em cada empresa, os projetos que ela vê com o perfil em cada um e o que esta conexão pode fazer e a versão do tracker (server: version e commit do deploy). Bom primeiro passo.
- `list_projects` (tracker:read): Lista os projetos que a pessoa vê nas empresas desta conexão, com prefixo do código, tipo do projeto (kind: software, design, admin ou support), perfil dela, tipos de issue, campos personalizados, labels e módulos de cada um. Use antes de create_issue para saber os valores aceitos.
- `search_issues` (tracker:read): Busca issues com os mesmos filtros da lista do tracker. Devolve as mais recentes primeiro (por atualização; com done_last, as concluídas no fim), com código, título, status (e close_reason em Fechado), marca de bloqueio (blocked, blocked_reason), retest_failed (reprovada no último reteste), severidade, prioridade, responsável e QA, sprint, release, todas as releases (releases, como "GOP 1.4.8"), módulo, pai, épico, labels, datas, external_id, edit_version e link; description e custom_fields com include. Aceita também a consulta avançada da tela em `query` (ex.: projeto = MOB e status in (Aberto, "Em teste") e responsavel = eu login, ou bloqueio = sim) e um filtro salvo em `saved_filter`; os filtros se somam. Numa conexão de várias empresas, sem project nem organization, busca em todas (até 200 issues), com organization em cada uma.
- `list_saved_filters` (tracker:read): Lista os filtros salvos da pessoa e os compartilhados na empresa, com o nome e a query string. Para usar um, passe o nome em search_issues (saved_filter).
- `get_issue` (tracker:read): Abre uma issue pelo código (ex.: MOB-0012) ou id: todos os campos (com épico ou pai, filhas, sprint, estimativa, prazo, repetição e quem acompanha), todas as releases, campos personalizados, labels, vínculos, evidências (os anexos, com o comment_id quando vieram num comentário; get_attachment lê o conteúdo, e o download_url pede o token da API), comentários e histórico recentes (com o texto da tela, nomes em vez de ids). Quando alguém pediu o resumo da aqua na tela, aqua_summary traz o que aconteceu, o que falta e quem está com a bola (outdated: houve comentários ou mudanças depois). aqua_context é a ficha de contexto que a aqua escreve sozinha de cada issue (o problema em palavras neutras, onde acontece e os termos), a mesma que o search_similar cruza. Para conferir várias issues, peça só o que precisa em fields ou use search_issues, que já traz releases e edit_version.
- `list_comments` (tracker:read): Todos os comentários de uma issue, na ordem em que foram escritos, cada um com as respostas, o autor e as pessoas mencionadas. Editado traz edited_at; excluído fica no lugar sem o texto, com deleted. Use o id de um comentário em add_comment para responder a ele.
- `get_issue_history` (tracker:read): Histórico completo de uma issue, do mais recente para o mais antigo, em páginas: quem fez, quando e o quê (status, campos, responsável, release, sprint, labels, vínculos, evidências, reteste e horas), com os valores de antes e depois já com nome. get_issue traz só os 50 últimos eventos.
- `list_sprints` (tracker:read): Mostra o planejamento de um projeto: as sprints abertas (ativa e planejadas) com as issues e os pontos, o começo do backlog na ordem de prioridade e a velocidade das últimas sprints encerradas.
- `list_releases` (tracker:read): Lista releases com status, tipo (kind: version ou ota), momento (stage: current é a que está no ar, uma por trilho: versão e OTA têm cada uma a sua; previous as anteriores, approved, testing, development, planned, cancelled; is_next marca a próxima a ir ao ar), datas, quantas issues em aberto estão vinculadas e a última decisão do Release Gate.
- `get_release` (tracker:read): Abre uma release pelo id, ou pelo projeto + versão: dados, tipo e momento (kind, stage, is_next), o resumo da tela (summary: onde ela está, qual está no ar e o próximo passo), métricas e sugestão do Release Gate (gate.applies; em OTA sem BLOCKED registrado a sugestão é "not_applicable" e vem só a contagem das issues em gate.validation: ready_for_qa, testing, approved, failed), última decisão, issues vinculadas, ciclos de teste e as notas da versão (salvas ou o rascunho gerado das issues concluídas).
- `list_test_cycles` (tracker:read): Lista os ciclos de teste mais recentes com release, status e progresso (pass, fail, bloqueado, pendente).
- `get_test_cycle` (tracker:read): Abre um ciclo de teste: release, ambiente, status, totais e cada caso com o resultado (pass, fail, blocked, in_progress, not_started), o comentário, quem testou e a issue aberta a partir do fail.
- `list_test_cases` (tracker:read): Lista os casos de teste ativos (código TC-MOB-0001, título, módulo, prioridade e quantos passos), filtrando por projeto e por parte do código ou do título.
- `create_issue` (tracker:write): Cria uma issue em nome da pessoa conectada, com as mesmas regras da tela: o perfil dela no projeto precisa permitir (PO/PM, QA ou admin; dev cria só subtarefas, com o pai) e a prioridade só vale para PO/PM e admin (os demais criam com prioridade média). Consulte list_projects para tipos (e o nível de cada um: épico, comum, subtarefa), módulos e campos personalizados aceitos. Tipo com template tem modelo: siga a estrutura dele nos campos de texto; campo de texto omitido vem preenchido com o modelo, e texto vazio deixa o campo vazio. Com recurrence (weekly, monthly, quarterly, yearly), concluir a issue cria a próxima ocorrência. assignee e qa_owner atribuem na criação (veja list_people). Antes de criar, pergunte ao search_similar se já aconteceu (query com o título e a descrição): se a aqua disser que é o mesmo problema (relation same), não crie; comente na issue que já existe (add_comment) com o que há de novo. Depois de criar, similar traz as parecidas que a aqua confirmou (relation same ou related, com reason): vincule a nova com link_issues (type duplicates para o mesmo problema, relates_to para relacionada) e diga à pessoa.
- `update_issue` (tracker:write): Edita uma issue em nome da pessoa conectada, com as mesmas regras da tela. Só os campos enviados mudam; null tira o valor. Cobre título, tipo, severidade, prioridade, módulo, textos, campos personalizados (só as chaves enviadas), responsável e QA (veja list_people), registro técnico, pai, pontos, sprint, release (a principal, do projeto da issue), outras releases em que a correção também sai, inclusive de outros projetos (add_releases, remove_releases) e labels (add_labels, remove_labels). Cada grupo exige o perfil certo no projeto: editar é de PO/PM, QA ou admin; atribuir outra pessoa e sprint, de PO/PM ou admin; registro técnico, de dev ou admin; dev e PO/PM assumem a issue com assignee "me", e QA assume como QA responsável com qa_owner "me". Mande edit_version (lido em get_issue) para não sobrescrever a edição de outra pessoa: se a issue mudou depois (campos, pessoas, registro técnico, pai, pontos, sprint, release, labels, estimativa ou datas), nada é gravado e o erro pede para ler de novo. Para status use move_issue; para estimativa, início, prazo e repetição, plan_issue.
- `add_comment` (tracker:write): Comenta numa issue em nome da pessoa conectada, como na tela: quem vê a issue pode comentar. @Nome menciona alguém do canal (veja people em list_chat_messages) e a pessoa é avisada; parent_id responde a um comentário. Quem acompanha a issue recebe o comentário. attachments anexa arquivos ao comentário (cada um em content_base64 com file_name, ou url pública), com as regras de attach_file.
- `edit_comment` (tracker:write): Corrige o texto de um comentário da issue. Só quem escreveu pode corrigir; o texto anterior fica guardado para o admin e a edição entra no histórico. Quem passa a ser mencionado agora é avisado.
- `delete_comment` (tracker:write): Exclui um comentário da issue: ele fica no lugar como excluído, sem o texto, e as respostas continuam. Quem escreveu ou um admin da empresa pode excluir.
- `attach_file` (tracker:write): Anexa um arquivo à issue (as evidências da tela) em nome da pessoa conectada: relatório, print, log, planilha. Mande o conteúdo em content_base64 com file_name (a extensão define o formato), ou a url pública (https) para o tracker baixar; para arquivo grande, prefira url. Formatos: png, jpg, webp, mp4, mov, pdf, json, txt, log, md e csv, até 15 MB, 60 arquivos por hora. comment_id põe o arquivo embaixo de um comentário seu da issue (para comentar e anexar de uma vez, use attachments em add_comment). Perfil que anexa: PO/PM, QA, dev ou admin. Devolve o anexo com download_url; os anexos da issue aparecem em get_issue (evidences), e get_attachment lê o conteúdo.
- `get_attachment` (tracker:read): Lê o conteúdo de um anexo (evidência) de uma issue que a pessoa conectada vê: md, csv, txt, log e json voltam em text (até 200 mil caracteres, com truncated quando passa), e png, jpg e webp até 5 MB voltam como imagem. PDF e vídeo voltam só com o download_url, que pede um token pessoal da API. O id do anexo está em get_issue (evidences), nos attachments de list_comments ou na resposta de attach_file.
- `remove_attachment` (tracker:write): Remove um anexo (evidência) da issue e apaga o arquivo. Só quem enviou ou um admin do projeto; o arquivo de uma versão enviada para aprovação não sai. O id está em get_issue (evidences) ou na resposta de attach_file.
- `link_issues` (tracker:write): Vincula a issue a outra (blocks, relates_to ou duplicates), como na tela: exige editar a issue, e a outra precisa ser de um projeto que a pessoa vê. Devolve os vínculos da issue, cada um com o id para unlink_issues.
- `unlink_issues` (tracker:write): Remove um vínculo da issue pelo id (o id em links de get_issue ou de link_issues). Exige editar a issue.
- `bulk_update_issues` (tracker:write): Aplica a mesma ação a várias issues (até 100), como a barra de ações da lista: mudar status, responsável, prioridade, severidade ou release, pôr ou tirar label, acompanhar, deixar de acompanhar ou excluir. Cada issue passa pela regra da ação individual (perfil no projeto dela, fluxo de status); as que não puderem mudar voltam em failed com o motivo, e as outras mudam. Responsável e release são achados no projeto de cada issue.
- `update_issues` (tracker:write): Fecha várias issues numa chamada só (até 50), cada uma com o que muda nela: os campos de update_issue (registro técnico, release, outras releases com add_releases, sprint, labels, responsável...), os PRs e commits a ligar (code_links, como link_code) e o status final (status, como move_issue), nessa ordem. Cada passo segue a regra da chamada individual. Um item que falha não para os outros: results traz, por issue, ok, os grupos gravados (updated), os links ligados (linked), o status final e, se falhou, failed_at (issue, fields, code_links ou status) e o motivo; edit_version protege o item todo; os passos anteriores ao que falhou ficam gravados. Para a mesma ação em todas (só status, só release), use bulk_update_issues.
- `list_proofs` (tracker:read): Versões de uma peça enviadas para aprovação (Design), da mais nova para a mais antiga: número, status (pending, approved, changes_requested, superseded), nota de quem enviou, decisão com comentário e o arquivo (download_url com o token da API). pending é o id da versão que espera decisão. O envio de versão nova é pela API REST (POST /issues/{ref}/proofs, multipart).
- `decide_proof` (tracker:write): Decide a versão que espera aprovação (o pending de list_proofs): approve aprova; changes pede ajustes e exige feedback. PO/PM, QA, admin ou o cliente do projeto (stakeholder). Com o fluxo de Design, a issue vai para Aprovado ou Ajustes. Devolve as versões e o status da issue.
- `list_people` (tracker:read): Lista as pessoas ativas que participam de um projeto, com o id e o perfil de cada uma (PO/PM, QA, dev, stakeholder, admin). Use para escolher o responsável em update_issue.
- `get_person` (tracker:read): O perfil de uma pessoa da empresa, como na tela: nome, e-mail, papel na empresa, desde quando está nela, os projetos com o perfil em cada um (all_projects quando é admin ou dona da empresa), quantas tarefas estão com ela (em aberto como responsável e como QA, concluídas nos últimos 30 dias), as tarefas em aberto mais recentes e a atividade recente (comentários e mudanças). Só entram os projetos e as tarefas que a pessoa conectada vê. person: "me", id, e-mail ou nome (veja list_people). Quem só acompanha os projetos vê só quem participa deles, sem o e-mail.
- `set_avatar` (tracker:write): Troca ou tira a foto da pessoa conectada (a de Sua conta → Perfil), que aparece no menu, no perfil, nas listas de pessoas e nas conversas, para quem divide uma empresa com ela. A imagem vai em image_base64 (PNG, JPG ou WebP até 2 MB); remove: true tira e ficam as iniciais. Só a própria foto. Devolve avatar_url, o endereço novo da foto com o token (null sem foto).
- `set_language` (tracker:write): Troca o idioma da pessoa conectada no tracker (o de Sua conta → Perfil → Idioma): as telas, os e-mails e os apps passam a usar este idioma, em todas as empresas dela. locale: "pt-BR" (português), "en" (inglês) ou "es" (espanhol); null volta ao automático, pelo idioma do navegador ou do aparelho. O idioma atual vem em whoami (user.locale). Não muda o que já foi escrito nas tarefas e conversas. Devolve locale.
- `watch_issue` (tracker:write): Liga ou desliga o "Acompanhar" numa issue: quem acompanha recebe os avisos de mudança de status e de comentário novo. Sem person, vale para a pessoa conectada; pôr ou tirar outra pessoa do projeto exige editar a issue (PO/PM, QA ou admin). Devolve person (a pessoa da ação e se ela acompanha agora), watching (se a pessoa conectada acompanha) e a lista watchers.
- `move_issue` (tracker:write): Muda o status de uma issue (para levar a outro projeto, use move_issue_to_project). Move uma issue (código, ex.: MOB-0012, ou id) para outro status do fluxo do projeto dela, com as mesmas regras da tela e do quadro: a transição precisa existir no fluxo e o perfil da pessoa no projeto precisa poder levar a issue até lá. Veja os status de cada projeto em list_projects. Para "closed" (Fechado, modelo QA), mande close_reason; com a issue já em closed, troca só o motivo. Bloqueio não é status: use block_issue.
- `block_issue` (tracker:write): Marca uma issue como bloqueada, com o motivo, ou tira a marca (blocked: false). O bloqueio vale em qualquer status e fluxo (não é uma coluna) e sai sozinho quando a issue conclui; marcar de novo troca o motivo. Todo perfil do projeto menos stakeholder. Devolve blocked (since e reason) ou null. Para achar as bloqueadas, search_issues com blocked_only.
- `move_issue_to_project` (tracker:write): Leva uma issue criada no projeto errado para outro projeto da mesma empresa, com as mesmas regras da tela: a pessoa precisa editar a issue e criar issue no destino. A issue ganha o código seguinte do destino e o antigo continua achando ela. Tipo, status, módulo, release e campos personalizados vão para o equivalente no destino; sem equivalente, caem no padrão de lá. Comentários, anexos, horas e histórico vão junto; subtarefas acompanham a issue pai. Chame primeiro sem confirm para ver os avisos, mostre-os à pessoa e só então chame com confirm: true. Para mudar o status dentro do mesmo projeto, use move_issue.
- `delete_issue` (tracker:write): Exclui a issue como na tela: ela some de listas, busca, API e MCP e pode ser restaurada (restore_issue) por 30 dias. Admin ou PO/PM do projeto. Issue com issues dentro dela (épico, subtarefas) não é excluída.
- `restore_issue` (tracker:write): Restaura uma issue excluída nos últimos 30 dias, pelo código ou id (veja list_deleted_issues), com comentários, evidências e histórico. Admin ou PO/PM do projeto.
- `duplicate_issue` (tracker:write): Cria uma cópia da issue no mesmo projeto, como o Duplicar da tela: conteúdo, classificação, pai, pontos, campos personalizados e labels. Não copia comentários, evidências, vínculos, pessoas, sprint, release nem o registro técnico; a cópia nasce no status inicial. Exige criar issue no projeto.
- `list_deleted_issues` (tracker:read): Lista as issues excluídas que a pessoa pode restaurar (admin ou PO/PM do projeto), com quem excluiu e até quando dá para restaurar.
- `create_release` (tracker:write): Cria uma release (versão) no projeto, no status planned. Exige PO/PM ou admin. A versão é única no projeto: pedir de novo a mesma versão devolve a release que já existe, com already_existed (bom para o CI criar a release a cada deploy). kind "ota" para atualização sem loja; o padrão é "version". Release que já foi ao ar (OTA enviada, deploy do backend, versão publicada fora do tracker) pode nascer com status "production" (sem o gate) e released_date.
- `set_release_status` (tracker:write): Muda o status de uma release (pelo id, ou projeto + versão), com as regras da tela: planned → in_development → staging (em teste), e de approved para production; cancelled sai do caminho. PO/PM ou admin. OTA vai a production direto (de planned, in_development, staging ou approved), sem a decisão do gate, a não ser que a última decisão seja BLOCKED; a validação segue depois pelas issues vinculadas. As outras releases chegam a approved pela decisão APPROVED do Release Gate, registrada por uma pessoa na tela, e produção exige essa decisão. Fora desse caminho (approved direto, inclusive) só admin, com override_note.
- `move_release` (tracker:write): Move uma release (pelo id, ou projeto + versão) para outro projeto da empresa, por exemplo as releases de deploy do backend que nasceram no app para o projeto da plataforma. Leva o histórico, as decisões do gate e as notas; as issues continuam vinculadas (a principal e as de "Também sai em"), mesmo as de outros projetos. Exige PO/PM ou admin nos dois projetos. A versão não pode existir no destino, e release com ciclo de teste não se move (ciclo é do projeto).
- `save_release_notes` (tracker:write): Grava as notas da versão de uma release (pelo id, ou projeto + versão), o texto para o cliente que a tela copia e manda por e-mail. PO/PM ou admin. Para escrever em linguagem de cliente, leia em get_release as issues e o rascunho gerado (release_notes): diga o que muda para quem usa, sem códigos de issue nem jargão técnico, e deixe de fora o que o cliente não percebe. Substitui o texto inteiro; vazio ou null volta ao rascunho gerado. Não envia o e-mail: o envio é na tela.
- `create_test_case` (tracker:write): Cria um caso de teste com os passos (ação e resultado esperado de cada um). Exige perfil QA ou admin no projeto. O código (TC-MOB-0001) é gerado.
- `create_test_cycle` (tracker:write): Cria um ciclo de teste no projeto, de uma release (pela versão) ou avulso, com os casos escolhidos pelo código, ou com todos os casos ativos do projeto quando cases não vem. Exige perfil QA ou admin. Devolve o ciclo com os casos, para registrar os resultados com record_test_results.
- `record_test_results` (tracker:write): Registra o resultado de um ou mais casos (até 200) num ciclo de teste em nome da pessoa conectada (QA ou admin), como na execução da tela: pass, fail, blocked ou in_progress, com comentário obrigatório para fail e blocked. Ciclo planejado passa a em andamento. Com open_issue, o fail abre a issue já preenchida com o caso (ou devolve a que já existe); se a issue não abrir, o resultado fica gravado e o item volta com warning. Item a item: um recusado não desfaz os outros. Gravar de novo o mesmo caso substitui o resultado.
- `set_test_cycle_status` (tracker:write): Inicia (start), encerra (finish), cancela (cancel) ou reabre (reopen) um ciclo de teste. Ciclo encerrado não aceita resultados até ser reaberto.
- `time_report` (tracker:read): Horas registradas num período (padrão: mês corrente), por pessoa, por projeto e por issue, com os registros mais recentes. person "me" mostra só as suas. Só cobre projetos em que o perfil da pessoa vê horas (stakeholder não vê).
- `log_time` (tracker:write): Registra tempo trabalhado numa issue em nome da pessoa conectada (perfis PO/PM, QA, dev ou admin). Use duration em texto ("1h30", "45m") ou minutes. Sem work_date, vale hoje. Devolve o total registrado e o restante da estimativa.
- `plan_issue` (tracker:write): Define estimativa ("8h", "2d"), início, prazo e repetição de uma issue. Campo omitido fica como está; null tira o valor. As datas aparecem no cronograma do projeto. Com recurrence (weekly, monthly, quarterly, yearly), concluir a issue cria a próxima ocorrência com início e prazo avançados.
- `list_code_links` (tracker:read): Lista os PRs (GitHub), MRs (GitLab) e commits ligados a uma issue, com repositório, estado (aberto, mergeado, fechado), branch, autor e link. Os que vêm da integração com o repositório se atualizam sozinhos; os ligados na mão ficam como foram ligados.
- `link_code` (tracker:write): Liga um PR ou commit do GitHub, ou um MR ou commit do GitLab (inclusive self-hosted), a uma issue, pelo link. Aparece no card Código da issue e no histórico. Não muda o status: quem move a issue é a integração do repositório ou move_issue. Perfis PO/PM, QA, dev ou admin.
- `unlink_code` (tracker:write): Tira um PR/MR ou commit da issue, pelo id do link (veja list_code_links) ou pelo mesmo link usado para ligar. Fica no histórico.
- `list_repositories` (tracker:read): Lista os repositórios do GitHub e projetos do GitLab conectados a um projeto do tracker, com o status que cada evento aplica (PR aberto, mergeado, fechado, commit) e o último evento recebido. connection diz como chega: github_app (o app do GitHub da empresa), gitlab_token (o tracker criou e cuida do webhook no GitLab) ou webhook (configurado à mão). Um PR ou commit que cita o código da issue (ex.: MOB-0012) nesses repositórios aparece na issue sozinho.
- `search_similar` (tracker:read): Busca issues (com os comentários) e chamados do Atendimento parecidos com um texto ou com uma issue, pelo sentido e pelas palavras (busca híbrida). Use antes de criar uma issue (query com o título e a descrição) e na triagem de um erro ou chamado, para saber se já aconteceu antes; com relation same, comente ou vincule a que já existe em vez de criar outra. likely_duplicate marca o que parece ser o mesmo problema; mode diz se a busca foi também pelo significado (hybrid) ou só por texto (text); semantic diz se a busca por significado está ligada na empresa (on, com indexed: quantos itens já estão no índice) e, se não, por quê (reason: no_vector, a busca pelo sentido não está disponível neste servidor; no_key, aqua desligada, chave própria da empresa ou sem créditos de IA). Com issue, a busca parte da ficha de contexto que a aqua escreve de cada issue. Com explain (padrão), a aqua confere cada achado: tira o que só divide palavras e devolve relation (same: o mesmo problema; related: relacionado) e reason (a ligação numa frase); explained diz se ela conferiu. Para filtrar por status, responsável ou datas, use search_issues.
- `list_aqua_recommendations` (tracker:read): As sugestões abertas da aqua (a IA do tracker) para as issues abertas, como na tela aqua: cada issue com código, título, status, o resumo da revisão (summary), reviewed_at, outdated (a issue mudou depois da revisão) e as recommendations (id, kind: comment, status, field, custom_field, label, duplicate ou move; title, before, after, reason e comment, o texto do pedido de informações). Traz também available (a IA ligada na empresa), can_review, a revisão diária (daily_review) e sentry_waiting (erros do Sentry esperando decisão; veja list_sentry_errors). Só de quem edita issues. Use apply_aqua_recommendation ou dismiss_aqua_recommendation para decidir.
- `get_ai_credits` (tracker:read): Os créditos de IA da empresa, como em Empresa → Integrações → Assistente de IA. Sem chave própria, a aqua usa a chave do tracker e gasta créditos de um pacote por ciclo de 30 dias, que renova sozinho; key_source diz qual chave a empresa usa (server: créditos; organization: chave própria, sem créditos e credits null). credits traz state (ok, low: 20% ou menos; empty: acabou e a aqua pausa até renovar; expired), remaining, used, total (per_cycle mais granted, os créditos que a equipe Aquarela lançou no ciclo), cycle_start, cycle_end, auto_renew e renews_at. usage (só admin e dono; null para os demais) traz o uso por ação desde since (o início do ciclo; com a chave própria, os últimos 30 dias), das mais usadas para as menos: action, label, calls, failures, credits. Nunca há valores em dinheiro. Quando a aqua recusar um pedido por falta de créditos, use isto para dizer à pessoa quando renova.
- `list_inbox` (tracker:read): A caixa de entrada da pessoa conectada, como na tela Caixa de entrada: os comentários em que alguém a mencionou (kind mention) e as respostas nas conversas em que ela escreveu (kind reply; own_thread: a conversa começou com um comentário dela), as mais recentes primeiro. Cada item traz id, text (a frase da tela), author, excerpt (o trecho do comentário), issue (id, code, title, project), url (direto ao comentário), at, read e hidden; unread conta as não lidas. Escrever na tarefa depois do comentário, abrir a tarefa ou ler a notificação no sino também contam como lida. As menções e respostas nas Conversas dos projetos vêm à parte, em chat_items (com chat_unread): cada uma traz id, kind (mention ou reply, a resposta numa thread em que ela está), own_thread (a thread começou com uma mensagem dela), thread, text, author, excerpt (o trecho da mensagem), project, url (direto à mensagem), at, read e hidden; abrir a thread ou ler o canal conta como lida. Use update_inbox para marcar como lida, ocultar ou trazer de volta (os ids de items e chat_items), get_issue ou list_comments para ler a conversa da tarefa e list_chat_messages para a das Conversas.
- `update_inbox` (tracker:read): Marca itens da caixa de entrada da pessoa conectada como lidos (action read, com ids ou all: true), oculta (hide, com ids ou older_than_days para as antigas; ocultar também conta como lida) ou traz de volta da aba Ocultadas (unhide, com ids). Vale para os itens das tarefas e das Conversas. Ler também marca no sino as notificações dos mesmos comentários. Devolve updated (quantos mudaram), unread e chat_unread.
- `get_aqua_summary` (tracker:read): O resumo da aqua do dia (period day, o padrão) ou do mês (month) da pessoa conectada, como no topo da Caixa de entrada: headline (o principal), highlights (o que aconteceu nas tarefas dela, nas que ela registrou e nas que acompanha), attention (o que pede a atenção dela: menção não lida, prazo, bloqueio), issues (as tarefas citadas, com code, id e url), generated_at e outdated (chegou novidade depois). Sem refresh, devolve o último resumo do período (summary null quando ela ainda não pediu); refresh: true pede um novo, com os créditos de IA da empresa. available diz se a aqua está ligada.
- `list_chat_channels` (tracker:read): Os canais das Conversas da pessoa conectada, como na lista da tela: um por projeto ativo em que ela conversa (o stakeholder não tem canal). Cada canal traz project (id, slug, name), unread (mensagens novas na conversa principal), mentions (menções e respostas nas threads dela ainda não lidas), last_message_at e url. directs traz as conversas diretas dela (só ela e a outra pessoa leem), a mais recente primeiro: id, person (id, name), unread, last_message_at e url; people, com quem ela pode abrir uma (id, name e url). unread no topo soma os canais e as conversas diretas; mentions, os canais. Use list_chat_messages para ler um canal (project) ou uma conversa direta (person).
- `list_chat_messages` (tracker:read): As mensagens do canal de um projeto em Conversas (project) ou da conversa direta com uma pessoa da equipe (person: id ou e-mail; abre a conversa na primeira vez; não tem thread nem @menção), na ordem em que foram escritas. Sem thread_id, a conversa principal: sem cursor, as últimas; before traz as anteriores e after as que chegaram depois. Com thread_id (o id da primeira mensagem de uma thread), devolve thread (essa mensagem) e replies (as respostas da thread). A conversa é da equipe do projeto (o stakeholder não vê). Cada mensagem traz id, thread_id (a thread em que é resposta, ou null), in_channel e thread_root (a resposta da thread que também foi para a conversa principal, com author e text da mensagem da thread), author, app (a mensagem escrita por um app das Conversas, com key e name; null na de uma pessoa), text (markdown), at, edited_at, deleted, mine (escrita pela pessoa conectada), can_edit e can_delete (o que ela pode fazer com a mensagem), mentions, mentions_me, issues (as tarefas citadas pelo código, com code, title, open e url), reactions (emoji, count, mine e people), thread (na conversa principal: replies, last_reply_at e people de quem respondeu, ou null) e url. people traz quem pode ser mencionado com @Nome no canal (id, name e me). unread conta as não lidas da pessoa conectada; mark_read: true marca como lida até a última devolvida (na thread, as menções e respostas dela).
- `send_chat_message` (tracker:write): Envia uma mensagem no canal do projeto em Conversas (project) em nome da pessoa conectada, como na tela: a equipe do projeto lê na hora. Com thread_id, responde na thread daquela mensagem (quem está na thread é avisado); com also_in_channel: true, a resposta também aparece na conversa principal; sem thread_id, vai para a conversa principal. @Nome menciona alguém do canal (veja people em list_chat_messages) e a pessoa recebe na Caixa de entrada, no sino e no aparelho; o código de uma tarefa (ex.: MOB-0012) vira link e cartão. Com person (id ou e-mail) no lugar de project, escreve na conversa direta com essa pessoa da equipe (só as duas leem; ela é avisada no aparelho; sem thread). Para falar de uma tarefa específica, prefira add_comment nela.
- `react_to_chat_message` (tracker:write): Marca (remove: false, o padrão) ou tira (remove: true) a reação da pessoa conectada a uma mensagem das Conversas (do canal, com project, ou da conversa direta, com person), com um emoji (ex.: 👍, ✅, 🎉). Cada pessoa marca cada emoji uma vez por mensagem; uma mensagem aceita até 20 emojis diferentes. Devolve reacted.
- `edit_chat_message` (tracker:write): Corrige o texto de uma mensagem das Conversas (do canal, com project, ou da conversa direta, com person). Só quem escreveu pode corrigir; no canal, o texto anterior fica no histórico da empresa e quem passa a ser mencionado agora é avisado.
- `delete_chat_message` (tracker:write): Exclui uma mensagem das Conversas (do canal, com project, ou da conversa direta, com person): fica no lugar como excluída, sem o texto. No canal, o texto vai para o histórico da empresa e quem escreveu ou um admin da empresa exclui; na conversa direta, só quem escreveu.
- `suggest_chat_issues` (tracker:read): As tarefas para citar numa mensagem das Conversas (do canal, com project, ou da conversa direta, com person), como a lista que abre ao escrever "#" no campo da tela. Sem q, sugere pelo contexto: as citadas por último na conversa (reason cited), as abertas com a pessoa conectada (mine) e as abertas do projeto do canal mexidas por último (project). Com o começo de um código (MOB-12), completa pelo código; com palavras, usa a busca da aqua (texto e significado). Cada uma traz id, code, title, open, project, reason e url; escreva o code na mensagem (send_chat_message) para virar link e cartão.
- `list_chat_apps` (tracker:read): Os apps das Conversas, que escrevem nos canais sem ser uma pessoa. Sem project, o catálogo da empresa: key, name, summary, description, official, built_in (vem com o tracker), permissions (o que o app pode fazer), events, installed, installed_at e channels (em quantos canais está ligado). Com project, os apps do canal do projeto: can_manage (a pessoa conectada pode ligar e desligar: PO/PM ou admin), can_install (admin) e apps (key, name, summary, built_in, installed, enabled e, em task_updates, events, os avisos que o canal recebe). Os oficiais: task_updates (Avisos de tarefas: tarefa criada, status mudou, responsável mudou, comentário novo), automations (Automações: escreve quando uma regra de automação manda) e google_meet (Google Meet: cria reuniões no canal; no canal vem account, a conta Google da pessoa conectada: configured, connected e email). A conversa direta fica fora dos apps. Use install_chat_app e set_chat_app para mudar e start_meeting para criar a reunião.
- `install_chat_app` (tracker:write): Instala (o padrão) ou desinstala (uninstall: true) um app das Conversas na empresa, como em Empresa → Apps. Só admin e dono. Instalado, o PO/PM do projeto ou um admin liga o app em cada canal (set_chat_app). Desinstalar desliga em todos os canais; as mensagens que o app já escreveu ficam. Os que vêm com o tracker (built_in) não se instalam. Devolve key e installed.
- `set_chat_app` (tracker:write): Liga (enabled: true) ou desliga (enabled: false) um app instalado na empresa no canal de um projeto em Conversas, como em "Apps", no topo do canal. Só o PO/PM do projeto ou um admin. Em task_updates (Avisos de tarefas), events escolhe o que o canal recebe: issue.created, issue.status_changed, issue.assigned e comment.created (sem events, fica o que estava ou o padrão: tarefa criada e status mudou). Devolve project e app (enabled e events).
- `start_meeting` (tracker:write): Cria uma reunião no Google Meet na conta Google da pessoa conectada e posta no canal do projeto o cartão com o link de entrar, como o botão da câmera ou /meet nas Conversas. O app google_meet precisa estar instalado na empresa e ligado no canal (set_chat_app), e a pessoa precisa ter conectado a conta Google pelo navegador (o erro traz o link). title é o assunto (opcional); thread_id cria dentro da thread daquela mensagem. Devolve project, message (id, thread_id, url) e meeting (url para entrar, code e title).
- `list_issues_to_review` (tracker:read): As issues abertas que a aqua ainda não revisou ou que mudaram desde a última revisão, as nunca revisadas primeiro (id, código e título). Para revisar todas de uma vez, use start_aqua_review; para revisar uma a uma, review_issue_with_aqua com batch: true.
- `start_aqua_review` (tracker:write): O botão "Revisar issues abertas" da tela aqua: a aqua revisa no servidor, uma de cada vez, todas as issues abertas que ainda não viu ou que mudaram desde a revisão (até 500), e grava as sugestões. Uma revisão por vez na empresa: se já houver uma rodando, devolve essa. Sem nada pendente, run: null. Acompanhe com get_aqua_review e pare com stop_aqua_review. Exige editar issues e a IA ligada na empresa.
- `get_aqua_review` (tracker:read): O andamento de uma revisão de start_aqua_review: status (running, done, stopped ou failed), total, reviewed, failed, suggestions, error e issues (id, code, title, state: waiting, running, done ou failed; suggestions e error). Sem id, a que roda na empresa ou a última.
- `stop_aqua_review` (tracker:write): Para uma revisão de start_aqua_review: a issue da vez termina, as que faltam ficam sem revisar.
- `review_issue_with_aqua` (tracker:write): A aqua lê a issue (campos, comentários e histórico) e grava sugestões: pedir informações, mover de status, corrigir campos, labels, apontar duplicada ou mover de projeto. Nada muda na issue até alguém aplicar. Devolve a revisão e as sugestões abertas. Exige editar issues no projeto e a IA ligada na empresa. batch: true usa o modelo da revisão em lote (para a fila de list_issues_to_review).
- `apply_aqua_recommendation` (tracker:write): Aplica uma sugestão da aqua pela regra de sempre (comentário, status, campo, label, vínculo de duplicada ou mudança de projeto), em nome da pessoa e com o perfil dela. comment troca o texto do pedido de informações. A sugestão que já não vale (a issue mudou) é recusada: revise de novo.
- `dismiss_aqua_recommendation` (tracker:write): Ignora uma sugestão da aqua por 1, 7 ou 30 dias, ou para sempre ("forever": não volta nas próximas revisões).
- `list_sentry_errors` (tracker:read): Lista os erros que o Sentry mandou para os projetos (o mesmo erro aparece uma vez, com eventos, pessoas afetadas e releases). state: pending (juntando avisos antes da triagem), suggested (a aqua já fez a triagem e espera uma decisão), linked (ligado a uma issue), regressed (voltou depois de a issue ser concluída), merged (igual a outro), dismissed ou muted. triage traz a issue que a aqua escreveu e, em candidate, a issue aberta que parece a mesma. Com project, traz também a integração (último aviso). waiting: true mostra só o que espera decisão, como na tela aqua.
- `decide_sentry_error` (tracker:write): Decide um erro do Sentry como na tela aqua: create_issue cria a issue já preenchida (título, severidade, passos, link do Sentry, alcance, release, ambiente, aparelho e stack resumido; title troca o título), link liga a uma issue do projeto (a candidata da aqua, ou issue) e comenta nela, reopen reabre a issue de um erro que voltou, dismiss ignora por snooze dias ou para sempre. Exige editar issues no projeto (create_issue, criar issue).
- `list_sentry_connections` (tracker:read): As conexões com o Sentry da empresa (Empresa → Integrações → Sentry; só admin e dono): o projeto que recebe o que sobrar, o webhook_url, se o segredo está salvo, a tabela dos projetos do Sentry (sentry_project_targets: prefixo do projeto do tracker, "rules" ou "ignore"), o que fazer com projeto novo do Sentry, as regras na ordem ("/v1/pedidos/* → API", "project=APP → APP"), ambientes, gravidade mínima, triagem pela aqua, o que os avisos já mostraram (seen) e o último aviso. Use antes de save_sentry_connection.
- `save_sentry_connection` (tracker:write): Conecta um Sentry (sem id: project, o projeto que recebe o que sobrar; a resposta traz o webhook_url para criar a Internal Integration no Sentry, e o client_secret entra depois) ou muda uma conexão (com id: só o que vier muda). sentry_project_targets e rules trocam a tabela e as regras inteiras. Só admin e dono.
- `test_sentry_connection` (tracker:read): Mostra para onde iriam os últimos erros (até 20) de uma conexão com o Sentry: com a configuração salva ou, sem gravar nada, com a tabela, as regras, os ambientes e a gravidade que vierem. Cada resultado: result (project, ignored ou outside_environment), project (prefixo), by (table, rule com o número da regra, ou leftover), below_min_level, a rota e as tags que as regras leram. Só admin e dono.
- `search_docs` (tracker:read): Busca na base de conhecimento da empresa (documentos publicados: manuais, regras de negócio, FAQs, processos) e devolve os trechos mais relevantes para a pergunta, com o documento e a seção de cada um. Use antes de responder dúvidas sobre o produto ou os processos da empresa e cite o documento (url). Para o texto inteiro, use get_doc com o slug.
- `list_docs` (tracker:read): Lista os documentos da base de conhecimento que a pessoa lê (título, slug, resumo, projeto e visibilidade), sem o texto. Filtre por projeto, ou "empresa" para os da empresa toda.
- `get_doc` (tracker:read): Abre um documento da base de conhecimento pelo slug (ou id), com o texto inteiro em markdown.
- `save_doc` (tracker:write): Cria ou atualiza um documento da base de conhecimento em nome da pessoa conectada (texto em markdown). Com o slug de um documento que já existe, atualiza: campo omitido fica como está. Documento de projeto: equipe do projeto (PO/PM, QA, dev) ou admin; da empresa toda: só admin. Cria como rascunho (draft) se a visibilidade não for informada; internal publica para a empresa e os agentes, public também na central de ajuda pública.
- `list_status` (tracker:read): Mostra as páginas de status da empresa (Empresa → Status; só admin e dono): os serviços que o cliente vê, cada um com o projeto dono, o status de agora (o pior entre o manual e os incidentes abertos) e a versão no ar; as páginas, com o endereço público (url), o slug, se estão publicadas e qual é a principal (primary, a que abre em /status); e os incidentes e manutenções recentes (phase active primeiro, depois upcoming, depois closed). Use antes de save_status_service, save_status_page e open_status_incident.
- `get_status_page` (tracker:read): Uma página de status com os blocos na ordem: o tipo, o título, os projetos ou serviços escolhidos, os escondidos e o que cada bloco mostra hoje (shows, com o status).
- `get_status_incident` (tracker:read): Um incidente ou manutenção da página de status com a linha do tempo que o cliente lê (status, texto, quem publicou e quando), os serviços afetados e a janela.
- `save_status_service` (tracker:write): Cria um serviço da página de status (sem id: name e project) ou edita um (com id: só o que vier muda). O serviço é o que o cliente reconhece (o app, a API, o portal); o status manual vale até mudar de novo, e os incidentes abertos pioram o que o cliente vê sem trocar o manual. Serviço novo entra sozinho nos blocos do projeto dele. Monitoramento automático: check_url (healthcheck a cada minuto) e sentry_alerts (erro novo do Sentry do projeto deixa Lento). Só admin e dono.
- `save_status_page` (tracker:write): Cria uma página de status (sem id: title) ou edita uma (com id: só o que vier muda). blocks traz todos os blocos na ordem e troca os que havia: {"kind": "projects", "projects": ["MOB"]} (um projeto, o título é o nome dele), {"kind": "projects", "title": "Plataforma", "projects": ["PLT", "API"], "hidden_services": ["Fila interna"]} (grupo de projetos) ou {"kind": "services", "title": "Destaques", "services": ["App do motorista"]} (avulsos, por id ou nome). published: true abre o endereço público (url), sem conta. slug: endereço legível /status/<slug> no endereço da empresa; primary: true faz a página abrir em /status. Aparência: brand_name (marca da página), accent_color (#rrggbb), links (até 4 botões no topo, {"label": "Suporte", "url": "https://..."}), show_history e show_past_incidents (false esconde); a logo se envia pela tela. Só admin e dono.
- `open_status_incident` (tracker:write): Abre um incidente (kind incident: impacto e status investigating → identified → monitoring → resolved) ou agenda uma manutenção (kind maintenance: starts_at e ends_at, status scheduled → in_progress → completed) nos serviços afetados (id ou nome), com a primeira atualização que o cliente lê em message. Enquanto está aberto (ou na janela da manutenção), os serviços afetados aparecem com o impacto nas páginas de status. Só admin e dono.
- `update_status_incident` (tracker:write): Publica uma atualização num incidente ou manutenção (message, com status e, no incidente, impact): resolved ou completed encerra, e ele vai para Incidentes anteriores. Também corrige os detalhes sem atualização nova (title, services, starts_at, ends_at; impact sem message). Só admin e dono.
- `delete_status_item` (tracker:write): Exclui um serviço (sai de todas as páginas e incidentes), uma página (o endereço público para de abrir) ou um incidente (some da página, inclusive de Incidentes anteriores; para encerrar, use update_status_incident com resolved). Só admin e dono.
- `list_idea_boards` (tracker:read): Mostra os quadros de ideias da empresa (Empresa → Ideias; só admin e dono), onde os clientes votam no que querem ver: título, se está publicado, o endereço público (url, que o cliente abre sem conta), quantas ideias tem e quantas sugestões de clientes esperam a equipe (pending_suggestions). Use antes de get_idea_board e save_idea.
- `get_idea_board` (tracker:read): Um quadro de ideias: projetos, quem pode ver e votar (access e allow_list), se aceita sugestões, as ideias publicadas (mais votadas primeiro, com status que o cliente vê, issue ligada, votos e quantos comentários) e as sugestões dos clientes esperando a equipe (pending_suggestions, com o e-mail de quem sugeriu).
- `get_idea` (tracker:read): Uma ideia com os votos e os comentários (de clientes, com o nome e o e-mail, e da equipe), do mais antigo para o mais novo.
- `save_idea_board` (tracker:write): Cria um quadro de ideias (sem id: title) ou edita um (com id: só o que vier muda). projects troca os projetos do quadro (prefixo, slug ou id). published: true abre o endereço público (url). access link deixa qualquer um com o link ver (votar pede o e-mail confirmado por código); restricted mostra as ideias só a quem confirmar um e-mail de allow_list (["@cliente.com.br", "ana@gmail.com"]). Só admin e dono.
- `save_idea` (tracker:write): Cria uma ideia num quadro (sem id: board e title, ou board e issue) ou edita uma (com id: só o que vier muda). Com issue (código de um projeto do quadro), o status que o cliente vê segue o da issue (a fazer: Planejado; em andamento: Em andamento; concluída: Lançado; cancelada: Não vamos fazer); sem issue, vale status. published: true publica a sugestão de um cliente; para recusar, delete_idea_item. Quando o status muda para planned, in_progress, released ou closed, quem votou recebe um e-mail. Só admin e dono.
- `reply_to_idea` (tracker:write): Responde numa ideia publicada como a equipe: no quadro, o cliente vê "Equipe <empresa>". Devolve a ideia com os comentários. Só admin e dono.
- `delete_idea_item` (tracker:write): Exclui um quadro (com as ideias e os votos; o endereço público para de abrir), uma ideia (inclusive a sugestão de um cliente, que é como se recusa) ou um comentário (o id vem em get_idea). Só admin e dono.
- `create_project` (tracker:write): Cria um projeto como o Novo projeto da tela (quem configura algum projeto, ou admin): nome, prefixo do código (MOB vira MOB-0001), tipo (software, design, admin ou support), modelo do fluxo (software_qa, software ou qa), início e fim previstos (start_date e target_date, AAAA-MM-DD) e, no mesmo pedido, a cor e um ícone pronto (library_icon, de list_project_icons). Quem cria entra como PO/PM; as outras pessoas entram pela tela. Devolve o projeto como em list_projects.
- `get_project` (tracker:read): O Resumo de um projeto, como a primeira aba dele na tela: o projeto como em list_projects, início e fim previstos com os dias que passaram e que faltam (time_progress: fração do tempo previsto que já passou), quantas issues há, abertas, concluídas e atrasadas, a sprint ativa, a próxima release, até 5 atrasadas, os 5 próximos prazos e quem participa. project: prefixo, slug ou id.
- `get_timeline` (tracker:read): O Cronograma de um projeto, como a aba da tela: as issues com início ou prazo (até 300, agrupadas por épico ou módulo, com responsável, sprint, horas e se estão atrasadas), as dependências "bloqueia" (conflict quando a que bloqueia termina depois que a outra começa), as sprints, as releases planejadas, o início e o fim previstos do projeto e as issues abertas ainda sem datas. Para mudar as datas de uma issue use plan_issue; do projeto, plan_project. project: prefixo, slug ou id.
- `plan_project` (tracker:write): Define o início e o fim previstos de um projeto (quem configura o projeto, ou admin), que aparecem no Resumo e na linha do projeto no Cronograma (get_timeline). Só o que vier muda; null tira a data. Datas em AAAA-MM-DD, e o início não pode vir depois do fim. Para as datas de uma issue use plan_issue.
- `set_organization_logo` (tracker:write): Troca ou tira um dos logos da empresa (Empresa → Geral; só admin e dono). kind square é o quadrado (ícone, seletor de empresa, menu recolhido) e wide o horizontal (topo do menu, login, convites, e-mails, portal). A imagem vai em image_base64 (PNG, JPG ou WebP até 2 MB); remove: true tira. Devolve os endereços públicos dos dois logos.
- `list_project_icons` (tracker:read): A biblioteca dos 108 ícones prontos para projetos (mobilidade, energia, comércio, tecnologia e outros grupos), com slug, nome e o desenho (url, em preto com fundo transparente). query filtra pelo nome, slug ou grupo, sem acento. Para usar: set_project_brand com library_icon, que pinta o desenho na cor do projeto.
- `set_project_brand` (tracker:write): Troca a cor e o ícone de um projeto (PO/PM ou admin no projeto); só o que vier muda. color: um nome da paleta (azul, violeta, rosa, vermelho, laranja, âmbar, verde, turquesa, grafite) ou #rrggbb; null volta à automática. O ícone é um de três: library_icon (slug de list_project_icons, pintado na cor; para repintar depois de trocar a cor, mande library_icon de novo), image_base64 (ícone próprio, quadrado, PNG, JPG ou WebP até 2 MB) ou remove_icon: true (volta ao prefixo na caixa da cor). Devolve a cor e o endereço do ícone.
- `list_beta_invites` (tracker:read): Lista os convites do beta do tracker (só a equipe da plataforma), os mais novos primeiro: status (active, used, expired, revoked), e-mail, anotação, usos (uses de max_uses), validade, quem gerou (created_by) e quem usou cada um com a empresa que criou (redemptions). O link não volta aqui: só ao criar ou reenviar.
- `create_beta_invite` (tracker:write): Gera um convite do beta (só a equipe da plataforma): quem abre o link entra ou cria a conta aquarela ID e cria a própria empresa, como dono. Para chamar alguém para uma empresa que já existe, não é isto. Com email, o link vai por e-mail e só vale para a conta desse e-mail (uma empresa só); sem email, max_uses diz quantas empresas o link cria. days é a validade (padrão 14). Devolve url (o link, que não aparece de novo), expires_at e emailed (sent, disabled ou failed).
- `resend_beta_invite` (tracker:write): Reenvia um convite do beta com e-mail (só a equipe da plataforma): gera um link novo (o anterior para de valer), recomeça a validade e manda de novo para o e-mail. Devolve url, expires_at e emailed.
- `revoke_beta_invite` (tracker:write): Revoga um convite do beta (só a equipe da plataforma): o link para de valer para quem ainda não criou a empresa. As empresas que ele já criou continuam.
- `get_platform_overview` (tracker:read): Números do tracker inteiro (só a equipe da plataforma, seção Visão geral): empresas ativas, suspensas e arquivadas, pessoas, projetos e issues, uso de IA nos últimos 30 dias (chamadas, custo em dólar e empresas que usaram), convites do beta e a versão.
- `list_platform_organizations` (tracker:read): Lista todas as empresas do tracker (só a equipe da plataforma, seção Empresas), por nome: status (active, suspended, archived), donos, membros, projetos, issues, chamadas de IA nos últimos 30 dias, última atividade e, na suspensa, quando e por quê. status e query filtram.
- `suspend_organization` (tracker:write): Suspende uma empresa (só a equipe da plataforma que gerencia Empresas): ninguém da empresa entra no app, na API, no MCP ou no Slack até reativar; os dados ficam. reason vai para o registro da plataforma. Confirme com a pessoa antes: a empresa inteira perde o acesso na hora.
- `reactivate_organization` (tracker:write): Reativa uma empresa suspensa (só a equipe da plataforma que gerencia Empresas): quem era membro volta a entrar.
- `prepare_demo_account` (tracker:write): Prepara a conta de demonstração das revisões da Apple e da OpenAI (só a equipe da plataforma que gerencia Empresas): cria a Empresa Demo (empresa-demo) com dois projetos, 16 issues em vários status, releases, um ciclo de teste e um documento, com a conta do email como dona e três colegas fictícios. O revisor entra com a conta aquarela ID desse e-mail, criada lá com senha. Se a Empresa Demo já existe, só garante a conta ativa e dona dela (created false). Recusa e-mail da equipe da plataforma e conta que já participa de outra empresa. Confirme com a pessoa antes de rodar em produção.
- `list_platform_team` (tracker:read): Lista a equipe da plataforma (só quem é da equipe): o dono (role owner, pode tudo) e os demais (role staff) com o nível de cada seção em sections (view ou manage; ausente = não vê). Seções: overview, organizations, support (entrar nas empresas como suporte), invites, ai, audit. Mudar a equipe é só na tela, pelo dono.
- `list_platform_audit` (tracker:read): O que a equipe fez na plataforma (só a equipe, seção Registro), mais novo primeiro: mudanças na equipe, empresas criadas, suspensas, reativadas, arquivadas e excluídas, convites do beta e cada entrada como suporte numa empresa de cliente. Filtros: action, organization_id, actor_id; before (a created_at da última linha) pagina.

## Já aconteceu antes? (antes de criar uma issue)

O tracker guarda uma ficha de contexto de cada issue, escrita pela aqua (o problema em palavras neutras, onde acontece e os termos que alguém usaria para contar o mesmo problema de outro jeito). O "Já aconteceu antes?" cruza essas fichas e a aqua diz, de cada parecida, se é o mesmo problema ou só relacionado, com o motivo numa frase. Agentes usam o mesmo caminho para não abrir duplicatas:

1. Antes de criar, pergunte: `search_similar` no MCP (ou `GET /search`) com `query` = título e descrição do problema (a mensagem de erro, o relato do cliente). Para ver também os chamados do Atendimento, `kinds: ["issue", "ticket"]`.
2. `relation: "same"` (o mesmo problema): não crie outra. Comente na issue que já existe (`add_comment`) com o que há de novo (outro cliente, outro ambiente, a evidência) e conte à pessoa qual é. Se a que existe já foi encerrada e o problema voltou, crie a nova e vincule com `link_issues` (`duplicates`), dizendo que voltou.
3. `relation: "related"`: crie e vincule com `link_issues` (`relates_to`); o `reason` explica a ligação e cabe no comentário.
4. Depois de criar, `create_issue` devolve `similar` com as parecidas da issue nova que a aqua confirmou (na API, `POST /issues?similar=true`): vincule as que fizerem sentido.

Sem a aqua ligada na empresa, `explained` volta `false` e vale o `likely_duplicate` da busca. Para um lote (importação, CI), use `external_id`, que já evita repetir a mesma issue.

## API REST

Para CI, scripts e importação de outras ferramentas. JSON nos dois sentidos.

- Base: https://tracker.aquarela.app/api/v1
- Autenticação: token pessoal no cabeçalho `Authorization: Bearer <token>`. A pessoa cria o token em https://tracker.aquarela.app/account/tokens, escolhe a validade (30, 90, 180, 365 dias) e se ele pode criar issues; o token vale para a organização em que foi criado, aparece uma vez só e pode ser revogado na mesma tela (até 20 ativos por pessoa). Os tokens OAuth do MCP não valem na API.
- Mesmas regras da interface: o token vê só os projetos da pessoa e cria issues só onde o perfil dela permite. Pessoa desativada ou removida da organização desliga o token na hora.
- Links: o `url` de uma issue é o link canônico pelo código, `https://tracker.aquarela.app/issues/MOB-0012?org=<slug da empresa>`, que se lê, se digita e continua valendo depois de mover a issue de projeto (o código antigo também abre). O prefixo é único só dentro da empresa, então `org` diz de qual: o app troca para ela quando a pessoa participa. Sem `org`, `/issues/MOB-0012` procura primeiro na empresa selecionada e depois nas outras da pessoa (se o código existir em mais de uma, pergunta em qual abrir); `/issues/<id>` também funciona, em qualquer empresa da pessoa.
- Limite: 120 chamadas por minuto por token (429 com Retry-After).
- Erros: `{"error": "<código>", "message": "<texto>"}`, com 400 (dados inválidos, e `details` por campo), 401 (sem token ou token inválido), 403 (perfil ou token sem permissão), 404 (também para projeto na lixeira e as issues dele: excluir e restaurar projeto fica no app, só admin), 409 (já existe), 413, 415, 422 (recusado pelas regras do projeto), 429.
- `GET /version` (público, sem token): a versão do tracker no ar, `{"version": "0.2.0", "commit": "5f83c7b"}` (`commit` é o deploy, `null` fora dele). A tag `v<version>` no GitHub marca cada versão. `GET /me` e whoami trazem o mesmo em `server`.

Markdown: todo texto longo é markdown. Na issue, `description` e os outros textos longos (`preconditions`, `steps_to_reproduce`, `actual_result`, `expected_result`, `impact`, `suggested_solution`, `root_cause`, `fix_notes`) e o texto dos comentários; fora dela, as notas da release, a pré-condição, os dados, os passos e o resultado esperado dos casos de teste, o comentário de cada resultado de teste, a descrição e as respostas das ideias, as atualizações de incidente da página de status, o comentário das horas e o da decisão de aprovação. Vale `**negrito**`, `*itálico*`, `~~riscado~~`, listas com `-` ou `1.` (sublista com dois espaços de recuo), código entre crases (uma para trecho, três para bloco), `[link](https://...)`, `> citação` e títulos com `##`. A API devolve o texto como foi escrito (markdown cru); as telas do tracker (web e app) e os e-mails mostram formatado. HTML não é interpretado.

### Conta, pessoas e marca

- `GET /me` (tracker:read): pessoa (`user`, com `id`, `name`, `email`, `locale` e `avatar_url`), organização, projetos com o perfil em cada um, o token e a versão do tracker (`server`). Cada empresa de `organizations` traz `slug`, `public_url` (o endereço público da empresa, como `https://suaempresa.centraldeajuda.ia.br`: a raiz é a central de ajuda, `/status` a página de status publicada e `/suporte/...` e `/ideias/...` o portal e os quadros de ideias; `null` com o endereço público desligado), `app_url` (a empresa no tracker, `null` sem subdomínio por empresa) e `brand` com `square_logo_url` e `wide_logo_url` (públicos, `null` sem o logo). whoami traz `public_url` também.
- Idioma: `user.locale` (em `GET /me` e no whoami) é o idioma que a pessoa escolheu em Sua conta: `pt-BR`, `en` ou `es`; `null` é o automático, pelo idioma do navegador ou do aparelho (sem nenhum dos três, português). `PATCH /me` (tracker:write) com `{"locale": "en"}` troca (`null` volta ao automático) e devolve `{"locale": ...}`. Vale para as telas, os e-mails e os apps, em todas as empresas da pessoa; não traduz o que já foi escrito em tarefas e conversas. Um app que mostra a interface no idioma do aparelho usa `user.locale` quando não for `null`. As frases prontas que a API devolve (o `text` de `GET /notifications` e de `GET /inbox`, também no `list_inbox`) vêm nesse idioma; no automático, pelo `Accept-Language` do pedido. No MCP: `set_language`.
- `GET /me/deletion` (tracker:read): o que excluir a conta faria agora: `email`, `can_delete` (com `blocker`, o motivo, quando não pode: o dono da plataforma passa o papel antes) e `organizations`, cada uma com `outcome` (`deleted`: só a pessoa participa e a empresa sai inteira; `owner_transferred`: ela é a única dona e `new_owner` vira dono; `left`: ela só sai). `DELETE /me` (tracker:write) com `{"confirm_email": "<e-mail da conta>"}` exclui, sem volta: apaga nome, e-mail, foto, login, tokens, conexões e preferências e a conta aquarela ID (`aquarela_id`: `deleted`, ou `pending` quando o suporte termina lá); o que a pessoa escreveu fica com cada empresa como "Conta excluída". O token para de valer na hora. Não existe no MCP: excluir a conta é só da própria pessoa, no site, no app ou na API.
- `GET /people/{me, id, e-mail ou nome}` (tracker:read): o perfil de uma pessoa da empresa, como na tela /people/<id>. `person` (`id`, `name`, `email`, `active`, `organization_role` e `organization_role_label`, `member_since`, `url`, o perfil na tela, e `avatar_url`), `all_projects` (`true` para admin e dono da empresa, que valem em todos os projetos), `projects` (`name`, `prefix`, `slug`, `role`, `role_label`), `counts` (`open_assigned`, `open_qa`, `done_last_30_days`), `open_issues` (as mais recentes em aberto com ela como responsável: `code`, `title`, `status`, `severity`, `project`, `updated_at`, `url`) e `activity` (até 20 comentários e mudanças, mais recentes primeiro: `kind` `comment` ou `history`, `at`, `issue`, `text` e, quando um valor mudou, `from` e `to`). Só entram os projetos e as issues que o token vê; os apontamentos de horas, só para quem vê horas. Quem só acompanha os projetos (parte interessada) vê só quem participa deles, com `email` `null`. No MCP: `get_person`.
- Foto da pessoa: `avatar_url` (em `GET /me`, `GET /people/{ref}` e `author_avatar_url` nas mensagens da conversa) é `GET /people/{id}/avatar` (tracker:read, a imagem, com o token; 404 sem foto), `null` sem foto. O endereço muda (`?v=`) a cada troca, então pode ficar em cache pelo endereço: com a foto trocada na tela, o `avatar_url` novo chega na próxima leitura. `PUT /me/avatar` (tracker:write) troca a própria foto: `multipart/form-data` com a imagem no campo `avatar`, ou JSON `{"image_base64": "...", "file_name": "foto.jpg"}` (imagem acima de 1,5 MB vai em multipart). PNG, JPG ou WebP até 2 MB; a tela e os apps recortam no quadrado e mandam JPG de até 512 px, e vale fazer o mesmo (a foto aparece em círculo). `DELETE /me/avatar` tira (ficam as iniciais). A resposta traz `id`, `name` e `avatar_url`. Quem divide uma empresa com a pessoa vê a foto. No MCP: `set_avatar`.
- `GET /brand` (tracker:read): as marcas para os apps: a empresa (`organization`, com `slug`, `public_url` e `app_url` como em `GET /me`) e os logos dela (`organization.square_logo_url` e `wide_logo_url`), a assinatura "tracker by aquarela" com os arquivos (`product`; `product.by_url` é para onde o "by aquarela" leva, o site da Aquarela, numa aba ou no navegador), as regras e `placements`, onde entra cada uma (`place`, `organization`: `square`, `wide` ou `null`; `product`: `icon`, `signature`, `signature_large`, `tab_title`, `header` ou `null`). O tracker by aquarela nunca some: onde a empresa ocupa o topo, a assinatura vai para o rodapé.
- `PUT /brand/logos/{square|wide}` (tracker:write, admin e dono): troca o logo quadrado (ícone, seletor de empresa, menu recolhido) ou o horizontal (topo do menu, login, convites, e-mails, portal). `multipart/form-data` com a imagem no campo `logo`, ou JSON `{"image_base64": "...", "file_name": "logo.png"}` (o corpo JSON vai até 2 MB, então imagem acima de 1,5 MB vai em multipart). PNG, JPG ou WebP até 2 MB; o quadrado com largura e altura parecidas (pelo menos 64 px), o horizontal mais largo que alto. `DELETE /brand/logos/{square|wide}` tira. A resposta traz a empresa e os dois endereços. No MCP: `set_organization_logo`.

### Projetos

- `GET /projects` (tracker:read): projetos com o tipo do projeto (`kind`: `software`, `design`, `admin` ou `support`, e o nome em `kind_label`), tipos de issue (o nível de cada um e, quando houver, o `template`, modelo dos campos de texto), fluxo de status, campos personalizados, labels, módulos, a cor do projeto (`color`, `#rrggbb`) e o ícone (`icon_url`, com o mesmo token, ou `null` sem ícone: mostre o prefixo numa caixa na cor) e o início e o fim previstos (`start_date`, `target_date`, AAAA-MM-DD ou `null`). Use antes de criar issues.
- `GET /projects/{prefixo, slug ou id}` (tracker:read): o Resumo do projeto, a primeira aba dele na tela. `project` (como em `GET /projects`), `url`, `dates` (`start_date`, `target_date`, `days_elapsed` desde o início, `days_remaining` até o fim, negativo quando passou, e `time_progress`, a fração do tempo previsto que já passou, de 0 a 1, com as duas datas), `issues` (`total`, `open`, `done`, `late`), `active_sprint` (ou `null`, com `days_left`), `next_release` (a de data planejada mais perto que ainda não saiu, ou `null`), `late` e `upcoming` (até 5 issues abertas com prazo vencido e com prazo pela frente: `code`, `title`, `due_date`, `assignee`, `url`) e `people` (`name`, `role`). No MCP: `get_project`.
- `POST /projects` (tracker:write; quem configura algum projeto, ou admin): cria um projeto, `{"name": "App do motorista", "prefix": "MOB", "kind": "software", "workflow": "software_qa", "description": "...", "color": "verde", "library_icon": "carro", "start_date": "2026-11-03", "target_date": "2027-02-26"}` (`start_date` e `target_date`, início e fim previstos, opcionais). `kind`: `software` (padrão), `design`, `admin` ou `support`; `workflow` (software): `software_qa` (padrão), `software` ou `qa`. Nome e prefixo únicos na empresa (422 quando já existem, inclusive na lixeira). Quem cria entra como PO/PM. Devolve `project` como em `GET /projects` (e `warning` se a cor ou o ícone não puderam ser salvos; tente de novo em `PATCH /projects/{ref}/brand`). Criar a partir de outro projeto fica no app. No MCP: `create_project`.
- `PATCH /projects/{prefixo, slug ou id}` (tracker:write; PO/PM ou admin no projeto): início e fim previstos, `{"start_date": "2026-11-03", "target_date": "2027-02-26"}`; só o que vier muda e `null` tira. O início não pode vir depois do fim (422). Devolve `project`, `start_date` e `target_date`. No MCP: `plan_project`.
- `PATCH /projects/{prefixo, slug ou id}/brand` (tracker:write, PO/PM ou admin no projeto): cor e ícone; só o que vier muda. JSON `{"color": "verde", "library_icon": "carro-eletrico"}`: `color` é um nome da paleta (azul, violeta, rosa, vermelho, laranja, âmbar, verde, turquesa, grafite) ou `#rrggbb`, e `null` volta à cor automática; o ícone é um de três: `library_icon` (ícone pronto, pintado na cor do projeto), `image_base64` (ícone próprio, quadrado, PNG, JPG ou WebP até 2 MB; ou `multipart/form-data` com a imagem no campo `icon` e os outros campos em texto) ou `"remove_icon": true` (volta ao prefixo na caixa da cor). O ícone pronto é pintado na hora: trocar só a cor não repinta o ícone, então mande `library_icon` de novo junto com a cor nova. No multipart, `color` vazio volta à automática. Devolve `color`, `color_chosen` e `icon_url`. No MCP: `set_project_brand`.
- `GET /project-icons` (tracker:read): a biblioteca dos 108 ícones prontos, por grupo, com `slug`, `name` e `url` (o desenho em preto, fundo transparente); `?query=eletrico` filtra pelo nome, slug ou grupo, sem acento. No MCP: `list_project_icons`.
- `GET /projects/{prefixo, slug ou id}/people` (tracker:read): pessoas ativas do projeto, com id e perfil. Use para escolher o responsável.
- `GET /projects/{prefixo, slug ou id}/sprints` (tracker:read): o planejamento do projeto: sprints abertas com as issues e os pontos, o começo do backlog (`backlog.total` e as primeiras issues, na ordem de prioridade) e a velocidade das últimas sprints.
- `GET /projects/{prefixo, slug ou id}/timeline` (tracker:read): o Cronograma do projeto. `project` (com `start_date` e `target_date`), `url`, `can_plan` (se a pessoa muda as datas das issues), `items` (as issues com início ou prazo, até 300, as abertas e de data mais perto de hoje primeiro: `code`, `title`, `status`, `category`, `closed`, `group` e `group_kind`, o épico ou o módulo da linha, `is_epic`, `sprint`, `assignee`, `start_date`, `due_date`, `first_day` e `last_day` da barra, `late`, `estimate_minutes`, `spent_minutes`, `url`), `truncated`, `dependencies` (`blocker`, `blocked` e `conflict`, quando a que bloqueia termina no dia ou depois do início da bloqueada), `sprints`, `releases` (com data planejada) e `unscheduled` (`total` e até 20 abertas sem início nem prazo). Para mudar datas: `PATCH /issues/{ref}/plan` (a issue) e `PATCH /projects/{ref}` (o projeto). No MCP: `get_timeline`.
- `GET /projects/{prefixo, slug ou id}/repositories` (tracker:read): repositórios do GitHub e projetos do GitLab conectados, com o status que cada evento aplica, o último evento recebido e `connection`: `github_app` (o app do GitHub da empresa), `gitlab_token` (o tracker criou e cuida do webhook no GitLab) ou `webhook` (configurado à mão). Conectar e desconectar fica no app.
- `GET /panel?project=` (tracker:read): o painel de parede de um projeto numa chamada (quadro, atendimento, releases, a semana, gráficos e `aqua.topics`, as perguntas prontas da aqua, ou `null` sem IA). `GET /panel/aqua?project=&topic=` (tracker:read): a resposta da aqua a uma dessas perguntas (`overview`, o padrão, `attention`, `week`, `releases` e `support`, este só em projeto com atendimento), em tópicos, com `generated_at`; a mesma pergunta repete a resposta por 30 minutos.

### Issues

- `GET /issues` (tracker:read): busca. Query: `project`, `status` (chaves do fluxo do projeto), `category` (`todo`, `in_progress`, `done`), `severity`, `priority`, `type`, `nature` (`problem`, `improvement`, `task`: a natureza do tipo, que vale em qualquer projeto) (listas separadas por vírgula), `label`, `assignee` (`me`, `none` ou id), `open_only` (true), `blocked_only` (true: só as com a marca de bloqueio), `q` (texto livre: código, título, descrição e comentários), `query` (consulta avançada, ex.: `projeto = MOB e status = Aberto e responsavel = eu`), `saved_filter` (nome de um filtro salvo), `created_from` e `created_to` (AAAA-MM-DD), `limit` (até 50), `offset`, `sort` (`code`, `title`, `status`, `severity`, `assignee` ou `updated`), `order` (`asc` ou `desc`) e `done_last` (true: concluídas, grupo `done`, no fim, antes da ordem pedida). Sem `sort`, mais recentes primeiro. A API não esconde nada por padrão: sem filtro de status, vêm também as concluídas. A lista de tarefas da tela esconde as concluídas até a pessoa pedir "Mostrar concluídas" (e aí as mostra no fim); para reproduzir, use `open_only=true` ou `done_last=true`. No MCP, os mesmos `open_only` e `done_last` de `search_issues`. Cada issue vem com `close_reason` (em Fechado), `blocked` e `blocked_reason` (a marca de bloqueio), `retest_failed` (reprovada no último reteste e ainda não aprovada), `assignee`, `qa_owner`, `sprint`, `release`, `releases` (todas as entregas como `"GOP 1.4.8-ota002"`, a principal primeiro), `module`, `parent` e `epic` (códigos), `labels`, `start_date`, `due_date`, `external_id` e `edit_version` (para `PATCH` e o lote, sem abrir cada issue); `include=description,custom_fields` acrescenta a descrição e os campos personalizados.
- `GET /search?q=<texto>` (tracker:read): "isto já aconteceu?". Busca híbrida, pelo sentido e pelas palavras, em issues (com os comentários) e, com `kinds=issue,ticket`, nos chamados do Atendimento (só de quem atende). `issue=<código>` no lugar de `q` busca as parecidas com aquela issue, sem ela. `project`, `open_only` (true) e `limit` (até 30, padrão 8). Cada resultado traz `kind`, `code`, `title`, `status_label`, `open`, `project`, `score` (0 a 1), `similarity` (do vetor, quando achou pelo sentido), `matched_by` (`text`, `meaning`), `likely_duplicate` e `url`; `mode` é `hybrid` ou `text` (só pelas palavras); `semantic` diz se a busca por significado está ligada na empresa: `on`, `indexed` (quantos itens já estão no índice; cresce a cada minuto enquanto o índice se monta) e, desligada, `reason` (`no_vector`: a busca pelo sentido não está disponível neste servidor; `no_key`: aqua desligada, chave própria da empresa ou sem créditos de IA). Com `on` true e `mode` `text`, a busca pelo sentido não respondeu a tempo ou a pessoa passou do limite de buscas pelo sentido. Com `issue`, a busca parte da ficha de contexto que a aqua escreve de cada issue (`aqua_context` de `GET /issues/{ref}`). `explain` (padrão true; `false` devolve só a lista da busca, mais rápida) faz a aqua conferir cada achado contra a referência: tira o que só divide palavras e preenche `relation` (`same`: o mesmo problema; `related`: relacionado) e `reason` (a ligação numa frase); `explained` diz se ela conferiu (sem a aqua ligada, `false` e a lista da busca). Antes de criar uma issue, procure aqui para não duplicar (veja "Já aconteceu antes?" acima). No MCP: `search_similar`.
- `GET /issues/{código ou id}` (tracker:read): a issue com `status` (`key`, `label`, `category`, `close_reason` em Fechado com `key` e `label`, e `retest_failed_at` quando foi reprovada no último reteste), `blocked` (`since` e `reason`, ou `null`), `releases` (todas as entregas, a principal primeiro com `primary: true`), pai e `epic` (o pai, ou o pai do pai numa subtarefa), filhas, sprint, pontos, estimativa, datas, campos personalizados, labels, vínculos, quem acompanha, comentários, histórico (`from`/`to` com os valores gravados e `text`, como na tela: nomes de releases, pessoas e sprints; `from_label`/`to_label` quando a tela mostra de/para), `aqua_summary` (o último resumo da conversa feito pela aqua na tela: `happened`, `pending`, `ball` com quem está com a bola e `outdated` quando houve comentários ou mudanças depois; `null` sem resumo), `aqua_context` (a ficha de contexto que a aqua escreve sozinha, em segundo plano, para o "Já aconteceu antes?": `summary` com o problema em palavras neutras, `area`, `terms`, `generated_at` e `outdated` quando a issue mudou e a ficha ainda vai ser refeita; `null` com a aqua desligada ou antes da primeira ficha) e `edit_version` (para `PATCH`). `?fields=status,releases` traz só essas partes (`id`, `code`, `url` e `edit_version` sempre): bom para conferir muitas issues sem trazer comentários e histórico.
- `GET /issues/{código ou id}/comments` (tracker:read): todos os comentários, cada um com `id`, `author`, `text`, `at`, `edited_at`, `deleted` (quem excluiu e quando; o texto vem vazio), `mentions` e as respostas (`replies`).
- `POST /issues/{código ou id}/comments` (tracker:write): comenta, `{"text": "...", "parent_id": "<id do comentário respondido>"}`. `@Nome` menciona alguém do projeto. `"attachments": [{"file_name": "relatorio.md", "content_base64": "..."}, {"url": "https://..."}]` anexa até 5 arquivos ao comentário (14 MB somados), com as regras dos anexos abaixo; um anexo com problema recusa o comentário inteiro. 201 com o `id` e os `attachments`. No `GET`, cada comentário traz os seus `attachments` (`id`, `name`, `type`, `size_bytes`, `download_url`).
- `GET /issues/{código ou id}/evidences` (tracker:read): os anexos (evidências) da issue, do mais antigo ao mais novo, cada um com `id`, `name`, `type`, `size_bytes`, `description`, `comment_id` (quando veio num comentário) e `download_url`. `GET /evidences/{id}` (tracker:read) baixa o arquivo, com o mesmo token (aceita `Range`). Pelo MCP, cujo token não vale aqui, `get_attachment` lê o conteúdo: texto (md, csv, txt, log, json) e imagem (png, jpg, webp até 5 MB).
- `POST /issues/{código ou id}/evidences` (tracker:write): anexa um arquivo, de três jeitos: `multipart/form-data` com o arquivo no campo `file` (e `description` e `comment_id` opcionais, em texto); JSON `{"file_name": "avaliacao.md", "content_base64": "...", "description": "..."}` (aceita o prefixo `data:...;base64,`); ou JSON `{"url": "https://exemplo.com/print.png"}`, que o tracker baixa (só https e endereço público, até 3 redirecionamentos e 20 s; a URL não fica guardada; `file_name` opcional troca o nome). Formatos pela extensão do nome: png, jpg, jpeg, webp, mp4, mov, pdf, json, txt, log, md, csv; até 15 MB por arquivo e 60 arquivos por hora por pessoa. `comment_id` põe o arquivo embaixo de um comentário seu da issue. PO/PM, QA, dev ou admin (403 para os outros). 201 com `attachment` (como no `GET`). Não há URL pré-assinada: o bucket é privado e todo arquivo passa pelo tracker, que confere o formato e o tamanho. `DELETE /issues/{código ou id}/evidences/{id}` remove (quem enviou ou admin do projeto; o arquivo de uma versão de aprovação fica). No MCP: `attach_file`, `remove_attachment` e `attachments` em `add_comment`; os anexos aparecem em `get_issue` (`evidences`).
- `PATCH /issues/{código ou id}/comments/{id}` (tracker:write): corrige o texto, `{"text": "..."}`. Só quem escreveu (403 para os outros); o texto anterior fica guardado para o admin. `DELETE` no mesmo endereço exclui: o comentário fica no lugar, sem o texto (quem escreveu ou admin da empresa).
- `GET /issues/{código ou id}/history` (tracker:read): histórico completo, mais recente primeiro (`limit` até 200, `offset`), com `total` e cada evento com `at`, `by`, `action`, `field`, `text` e, quando houver, `from` e `to` já com nome.
- `POST /issues/{código ou id}/move` (tracker:write): leva a issue para outro projeto da mesma organização, `{"project": "CHG", "confirm": true}`. Sem `confirm`, só devolve a prévia (`moved: false`, avisos do que não tem equivalente no destino, subtarefas que vão junto); com `confirm: true`, move e devolve o código novo (`code`) e o antigo (`previous_code`), que continua achando a issue. 409 se a issue mudou no meio: leia de novo e repita. Exige editar a issue e criar issue no destino.
- `POST /issues/{código ou id}/links` (tracker:write): vincula a outra issue, `{"target": "MOB-0007", "type": "blocks"}` (`blocks`, `relates_to`, o padrão, ou `duplicates`). Exige editar a issue. 201 com os vínculos da issue (`links`, cada um com `id`). `DELETE /issues/{ref}/links/{id}` remove um vínculo.
- `GET /issues/{código ou id}/proofs` (tracker:read): aprovação de peças (Design). As versões enviadas, da mais nova para a mais antiga, com `status` (`pending`, `approved`, `changes_requested`, `superseded`), nota, decisão com comentário e o arquivo (`download_url`). `pending` é o id da versão que espera decisão.
- `POST /issues/{código ou id}/proofs` (tracker:write): envia a versão seguinte, em multipart/form-data com `file` e `note` opcional (mesmos formatos e tamanho das evidências). A que esperava decisão fica substituída. PO/PM, QA, dev ou admin. 201 com `version` e as versões.
- `POST /issues/{código ou id}/proofs/{id}/decision` (tracker:write): `{"decision": "approve"}` ou `{"decision": "changes", "feedback": "o que mudar"}`. PO/PM, QA, admin ou o cliente do projeto (stakeholder). Com o fluxo de Design, enviar leva a issue para Em aprovação, aprovar para Aprovado e pedir ajustes para Ajustes. 422 quando a versão já foi decidida ou substituída.
- `GET /issues/{código ou id}/watchers` (tracker:read): quem acompanha a issue (recebe os avisos de status e de comentário novo), com `watching` para a pessoa do token. `POST` põe e `DELETE` tira (tracker:write): sem nada, a própria pessoa; `{"person": "ana@empresa.com"}` no POST ou `?person=...` no DELETE para outra pessoa do projeto, o que exige editar a issue. A resposta traz `person` (quem foi posto ou tirado), `watching` e `watchers`. `GET /issues/{ref}` também traz `watchers`.
- `POST /issues/{código ou id}/status` (tracker:write): move a issue de status, `{"status": "<chave>"}`. Vale o fluxo do projeto e o perfil da pessoa nele (422 quando a transição não é permitida). Para `closed` (Fechado, modelo QA), mande também `close_reason`: `duplicated`, `cancelled`, `not_reproduced` ou `wont_fix`; com a issue já em `closed`, o mesmo pedido troca só o motivo.
- `POST /issues/{código ou id}/block` (tracker:write): marca a issue como bloqueada, `{"reason": "o que impede"}` (opcional; de novo troca o motivo). A marca vale em qualquer status e sai sozinha quando a issue conclui. `DELETE` no mesmo endereço tira. Todo perfil do projeto menos stakeholder; issue concluída não fica bloqueada (422). Devolve `blocked` (`since`, `reason`) ou `null`. No MCP: `block_issue`.
- `DELETE /issues/{código ou id}` (tracker:write): exclui a issue (admin ou PO/PM do projeto; 403 para os outros perfis). Ela some de listas, busca e API e pode ser restaurada por 30 dias (na tela, em Issues → Excluídas, ou por `POST /issues/{ref}/restore`). Issue com issues dentro dela (épico, subtarefas) não é excluída (422).
- `POST /issues/{código ou id}/restore` (tracker:write): restaura uma issue excluída nos últimos 30 dias, com comentários, evidências e histórico. Admin ou PO/PM do projeto. `GET /issues/deleted` (tracker:read, `project` opcional) lista as que a pessoa pode restaurar (as 200 mais recentes), com `restore_until`. Depois de 30 dias a restauração devolve 422.
- `POST /issues/{código ou id}/duplicate` (tracker:write): cria uma cópia no mesmo projeto, como o Duplicar da tela (conteúdo, classificação, pai, pontos, campos e labels; sem comentários, evidências, vínculos, pessoas, sprint, release e registro técnico). 201 com o `code` da cópia. Exige criar issue no projeto.
- `POST /issues` (tracker:write): cria uma issue. 201 quando cria; 200 quando já existia uma com o mesmo `external_id` no projeto. `assignee` e `qa_owner` (`me`, id, e-mail ou nome de quem participa do projeto) já atribuem na criação: PO/PM e admin atribuem qualquer pessoa, dev assume como responsável e QA como QA responsável (403 fora disso; 422 quando a pessoa não é do projeto, sem criar a issue). Dev cria só tipos de nível subtarefa, com o pai. Com `?similar=true`, a resposta da issue criada traz também `similar`: as parecidas que a aqua confirmou (`code`, `title`, `status_label`, `open`, `relation`, `reason`, `likely_duplicate`, `url`), para vincular.
- `PATCH /issues/{código ou id}` (tracker:write): edita a issue. Só os campos enviados mudam; `null` tira o valor. Aceita os campos de texto, `title`, `type`, `severity`, `priority`, `module`, `custom_fields` (só as chaves enviadas mudam; chave que não existe no projeto é recusada), `assignee` e `qa_owner` (`me`, id, e-mail ou nome de quem participa do projeto), o registro técnico (`root_cause`, `fix_notes`, `fixed_version`, `fixed_build`), `parent`, `story_points`, `sprint` (nome ou id de sprint aberta; `null` volta ao backlog), `release` (a principal: versão ou id; de outro projeto da empresa, `"PLT backend-1a2b3c"`, quando a correção sai só lá), `add_releases`/`remove_releases` (outras entregas da mesma correção, inclusive de outro projeto: id, versão no projeto da issue, `"GOP 1.4.8-ota002"` ou `{"project": "GOP", "version": "1.4.8-ota002"}`, em lista ou num texto separado por vírgula; exige vincular releases nos dois projetos) e `add_labels`/`remove_labels`. Cada grupo exige o perfil certo no projeto (403 quando não pode). Os grupos são gravados em sequência: se um falha, a resposta traz `applied` com os que já foram gravados. Para não sobrescrever a edição de outra pessoa, mande `edit_version` (o valor lido em `GET /issues/{ref}`): se alguém mudou a issue depois (campos, pessoas, registro técnico, pai, pontos, sprint, release, labels, estimativa ou datas; status, comentários e horas não contam), nada é gravado e a resposta é 409 (`conflict`); leia de novo e reaplique. A resposta de sucesso traz a `edit_version` nova.
- `GET /issues/{código ou id}/time` (tracker:read): estimativa, início, prazo, repetição (`recurrence` e `next_occurrence`), total registrado, restante e os registros de horas.
- `POST /issues/{código ou id}/time` (tracker:write): registra horas trabalhadas, `{"duration": "1h30", "work_date": "AAAA-MM-DD", "comment": "..."}` (ou `minutes` no lugar de `duration`; sem `work_date`, hoje). Perfis PO/PM, QA, dev e admin.
- `PATCH /issues/{código ou id}/plan` (tracker:write): `{"estimate": "8h", "start_date": "AAAA-MM-DD", "due_date": "AAAA-MM-DD", "recurrence": "monthly"}`. Campo omitido fica como está; `null` tira o valor. `recurrence` (`weekly`, `monthly`, `quarterly`, `yearly`) faz a issue repetir: ao concluir, nasce a próxima ocorrência com início e prazo avançados, os mesmos responsáveis e labels; `time.next_occurrence` aponta para ela. Também vale em `POST /issues` e em cada item de `POST /issues/import`; `null`, `""` ou `"none"` tira a repetição.
- `GET /issues/{código ou id}/code` (tracker:read): PRs (GitHub), MRs (GitLab) e commits ligados à issue, com `id`, repositório, estado (`open`, `draft`, `merged`, `closed`), branch, autor e link.
- `POST /issues/{código ou id}/code` (tracker:write): liga um PR ou commit pelo link, `{"url": "https://github.com/dono/repo/pull/12", "title": "..."}` (MR ou commit do GitLab também, inclusive self-hosted). Não muda o status. 409 quando já está ligado (commit pelo sha curto ou inteiro). Em repositório conectado, o webhook depois atualiza título e estado. Perfis PO/PM, QA, dev e admin.
- `DELETE /issues/{código ou id}/code?link_id=<id>` (ou `?url=<link>`, ou o mesmo no corpo JSON) (tracker:write): desliga. 404 quando não estava ligado.
- `GET /time` (tracker:read): relatório de horas. Query: `from` e `to` (AAAA-MM-DD; padrão, o mês corrente), `project` (prefixo, slug ou id) e `person` (`me` ou id); filtro que não confere é erro. Totais por pessoa, por projeto e por issue, e os registros.
- `POST /issues/bulk` (tracker:write): a mesma ação em até 100 issues, `{"issues": ["MOB-0012", "MOB-0013"], "action": "status", "value": "done"}`. `action`: `status`, `assignee` (só PO/PM ou admin; `me`, id, e-mail ou nome; `none` tira), `priority`, `severity`, `label`, `unlabel`, `release` (versão ou id; `none` tira), `watch`, `unwatch` e `delete` (as três últimas sem `value`). Cada issue segue a regra da ação individual; a resposta traz `requested` (issues distintas pedidas), `updated` e `failed` (`code` e `error` de cada uma que não mudou). Sem `value` numa ação que pede valor: 422.
- `POST /issues/batch` (tracker:write): lote por issue, até 50, para fechar uma entrega numa chamada: `{"items": [{"issue": "MOB-0045", "fixed_version": "backend 4e8998ac", "fix_notes": "...", "code_links": ["https://github.com/org/repo/pull/251"], "status": "ready_for_qa"}]}`. Cada item aceita os campos do `PATCH /issues/{ref}` (inclusive `edit_version`), `code_links` (links, ou `{url, title}`; um link já ligado não é erro) e `status`, aplicados nessa ordem com as regras das chamadas individuais. Um item que falha não para os outros; a resposta traz `requested`, `succeeded`, `failed` e `results` (por item: `ok`, `code`, `updated`, `linked`, `status` e, se falhou, `failed_at` com `issue` (não achada, ou mudou depois da `edit_version`), `fields`, `code_links` ou `status`, e `error`; os passos anteriores ficam gravados). Sem outros campos, a `edit_version` protege os links e o status.
- `POST /issues/import` (tracker:write): até 100 issues por pedido, `{"project": "MOB", "issues": [...]}` (cada item pode trazer o próprio `project`). Item a item: um recusado não desfaz os outros. A resposta traz `created`, `existing`, `failed` e `results` (`index`, `ok`, `code`, `url` ou `error`).

Campos de uma issue: `project` (prefixo, slug ou id), `title` (obrigatório), `type` (chave do tipo), `severity` (S1 a S4, padrão S3), `priority` (urgent, high, medium, low; só PO/PM e admin, os demais ficam com medium), `module` (nome), `description`, `environment`, `app_version`, `build`, `device`, `operating_system`, `preconditions`, `steps_to_reproduce`, `actual_result`, `expected_result`, `impact`, `suggested_solution`, `parent` (código ou id da issue pai: o épico de uma issue comum, ou a issue de uma subtarefa; o nível vem do tipo), `story_points` (número de 0 a 1000), `start_date` e `due_date` (início e prazo, AAAA-MM-DD; o início não vem depois do prazo), `custom_fields` (objeto pela chave do campo), `labels` (até 10 nomes; a que não existe é criada) e `external_id` (id na origem, até 200 caracteres).

Modelos por tipo: `description`, `preconditions`, `steps_to_reproduce`, `actual_result`, `expected_result`, `impact` e `suggested_solution` omitidos vêm preenchidos com o modelo do tipo (o `template` em `GET /projects`). Mande `""` para deixar um desses campos vazio.

Use `external_id` no CI: com o nome do teste que falhou, por exemplo, rodar o pipeline de novo não duplica a issue.

### Exemplos no CI

Exemplo (o token fica num segredo do CI):

```sh
curl -sS -X POST https://tracker.aquarela.app/api/v1/issues/import \
  -H "Authorization: Bearer $TRACKER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"project": "MOB", "issues": [{"title": "Login falha no Android 15", "severity": "S2", "external_id": "e2e/login.spec.ts", "labels": ["CI"]}]}'
```

Resultados de uma suíte automatizada num ciclo (o id sai de `POST /test-cycles` ou de `GET /test-cycles`):

```sh
curl -sS -X POST https://tracker.aquarela.app/api/v1/test-cycles/$CYCLE_ID/results \
  -H "Authorization: Bearer $TRACKER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"results": [{"test_case": "TC-MOB-0001", "status": "pass"}, {"test_case": "TC-MOB-0002", "status": "fail", "comment": "Timeout no login", "open_issue": true}]}'
```

### Conversas

- Conversas (`/chat`, um canal por projeto, como no Slack): de quem trabalha no projeto (admin, PO/PM, QA e dev; o stakeholder não vê, 403). `GET /chat` (tracker:read) lista os canais da pessoa do token (os projetos ativos): `unread` e `mentions` somados e `channels`, cada um com `project` (`id`, `slug`, `name`), `unread` (mensagens novas na conversa principal), `mentions` (menções e respostas nas threads dela ainda não lidas), `last_message_at` e `url`. `GET /projects/{prefixo, slug ou id}/chat` (tracker:read) traz `project`, `url`, `people` (quem pode ser mencionado com @Nome: `id`, `name` e `me`, a pessoa do token; vem também com `?thread_id`), `unread` (as não lidas da pessoa do token), `last_read_at`, `has_more` e `messages`, da conversa principal na ordem em que foram escritas (sem cursor, as últimas 50; `?before=<id>` as anteriores, `?after=<id>` as que chegaram depois, `?limit=` até 200, `?mark_read=1` marca como lida até a última devolvida). Com `?thread_id=<id>` (a primeira mensagem de uma thread) traz `thread` (essa mensagem) e `replies` (as respostas, até 500; `?after=<id>` só as novas; `?mark_read=1` marca as menções e respostas da thread como lidas). Cada mensagem: `id`, `thread_id` (a thread em que é resposta, ou `null`), `in_channel` e `thread_root` (`author`, `text`: a resposta da thread que também foi para a conversa principal e o começo da mensagem que ela responde), `author`, `app` (a mensagem escrita por um app, com `key` e `name`; `null` na de uma pessoa), `author_id`, `author_avatar_url` (a foto, `null` sem foto), `text` (markdown; vazio na excluída), `at`, `edited_at`, `deleted` (`by`, `at`), `mine` (escrita pela pessoa do token), `can_edit` e `can_delete` (o que ela pode fazer com a mensagem), `mentions`, `mentions_me`, `issues` (as tarefas citadas pelo código que a pessoa vê: `code`, `title`, `open`, `url`), `reactions` (`emoji`, `count`, `mine`, `people`), `thread` (na conversa principal: `replies`, `last_reply_at` e `people`, quem respondeu; `null` sem respostas) e `url`. `POST /projects/{ref}/chat` (tracker:write) envia `{"text": "..."}` na conversa principal ou `{"text": "...", "thread_id": "<id>"}` na thread daquela mensagem (com o id de uma resposta, entra na mesma thread; `"also_in_channel": true` também põe a resposta na conversa principal, como o "Também enviar para o canal" da tela; `reply_to_id` é o nome antigo; até 10.000 caracteres; @Nome menciona alguém do canal, e quem está na thread recebe a resposta, na Caixa de entrada, no sino e no aparelho) e devolve `message` (`id`, `thread_id`, `url`), 201. `POST /projects/{ref}/chat/{id}/reactions` (tracker:write) com `{"emoji": "👍"}` marca a reação da pessoa do token e `DELETE` com o mesmo corpo tira (cada pessoa, cada emoji uma vez; até 20 emojis diferentes por mensagem); devolve `id`, `emoji` e `reacted`. `PATCH /projects/{ref}/chat/{id}` (tracker:write, só quem escreveu) corrige com `{"text": "..."}`; `DELETE /projects/{ref}/chat/{id}` (tracker:write, quem escreveu ou admin) exclui (fica no lugar como excluída; o texto de antes vai para o histórico da empresa). `POST /projects/{ref}/chat/read` (tracker:read) com `{"message_id": "<id>"}` (ou `{}`, até agora) marca a conversa principal como lida e devolve `unread`. `GET /projects/{ref}/chat/issues?q=` (tracker:read) traz `issues`, as tarefas para citar numa mensagem, como a lista que abre ao escrever `#` no campo da tela (até 8; só as que a pessoa do token vê): sem `q`, pelo contexto, primeiro as citadas por último na conversa (`reason` `cited`), depois as abertas com a pessoa do token (`mine`) e as abertas do projeto mexidas por último (`project`); com o começo de um código (`MOB-` ou `MOB-12`, que acha MOB-0012), completa pelo código, primeiro as do projeto; com palavras, a busca por texto e sentido do `/search` (`reason` `null`). Cada uma: `id`, `code`, `title`, `open`, `project` (o nome), `reason` e `url`; o `code` escrito no `text` vira link e cartão. Projeto arquivado: só leitura (422 ao escrever). No MCP: `list_chat_channels`, `list_chat_messages`, `send_chat_message`, `react_to_chat_message`, `edit_chat_message`, `delete_chat_message` e `suggest_chat_issues`.
- Mensagens diretas (`/chat/direct/<id da pessoa>`): a conversa particular entre a pessoa do token e outra pessoa da equipe da mesma empresa (quem trabalha em algum projeto dela, menos o stakeholder, e os admins e donos). Só as duas leem; nem o admin vê. `GET /chat` também traz `directs` (as conversas com mensagem, a mais recente primeiro: `id`, `person` (`id`, `name`), `unread`, `last_message_at`, `url`) e `people` (com quem ela pode abrir uma: `id`, `name`, `url`); o `unread` do topo soma os canais e as conversas diretas. `GET /chat/direct/{pessoa}` (tracker:read; a pessoa pelo id ou e-mail; abre a conversa na primeira vez) traz `person`, `url`, `people` (vazio: não há @menção), `unread`, `last_read_at`, `has_more` e `messages`, com os mesmos parâmetros e campos da conversa do projeto, sem thread. `POST /chat/direct/{pessoa}` (tracker:write) envia `{"text": "..."}` (a outra pessoa é avisada no aparelho; `thread_id` dá 422); `PATCH`/`DELETE /chat/direct/{pessoa}/{id}` corrige e exclui (só quem escreveu; fora do histórico da empresa), `POST`/`DELETE /chat/direct/{pessoa}/{id}/reactions` reage e `POST /chat/direct/{pessoa}/read` marca como lida e `GET /chat/direct/{pessoa}/issues?q=` sugere as tarefas para citar (sem projeto do canal: as citadas na conversa e as abertas com a pessoa do token). Pessoa fora da equipe: 404; quem saiu da equipe depois deixa a conversa só para leitura (422 ao escrever). No MCP, as mesmas tools da conversa com `person` no lugar de `project`.
- Apps das Conversas: quem escreve no canal sem ser uma pessoa (a mensagem vem com `app` e `author_id` `null`; ninguém corrige, o admin exclui). Cada app tem um manifesto: nome, o que pede (`permissions`), os eventos que escuta e o que cada canal escolhe. Os oficiais: `task_updates` (Avisos de tarefas: posta no canal quando uma tarefa do projeto é criada, muda de status, muda de responsável ou recebe comentário, com o cartão dela; cada canal escolhe os eventos) e `automations` (Automações: vem com o tracker e escreve quando uma regra de automação tem a ação "Enviar mensagem no canal"). A empresa instala (só admin e dono) e o PO/PM do projeto ou um admin liga em cada canal; a conversa direta fica fora dos apps. `GET /apps` (tracker:read) traz `apps`, o catálogo da empresa: `key`, `name`, `summary`, `description`, `official`, `built_in`, `permissions` (`key`, `description`), `events`, `installed`, `installed_at` e `channels` (em quantos canais está ligado). `POST /apps/{key}` (tracker:write) instala e `DELETE /apps/{key}` desinstala (desliga em todos os canais; as mensagens ficam); devolve `key` e `installed`. `GET /projects/{ref}/chat/apps` (tracker:read, quem participa da conversa) traz `project`, `can_manage` (pode ligar e desligar), `can_install` e `apps` (`key`, `name`, `summary`, `built_in`, `installed`, `enabled` e, no `task_updates`, `events`). `PATCH /projects/{ref}/chat/apps/{key}` (tracker:write, PO/PM ou admin) com `{"enabled": true, "events": ["issue.created", "issue.status_changed", "issue.assigned", "comment.created"]}` liga e escolhe os avisos (sem `events`, fica o que estava ou o padrão: tarefa criada e status mudou) e `{"enabled": false}` desliga; app não instalado dá 422. No MCP: `list_chat_apps` (com `project`, os do canal), `install_chat_app` e `set_chat_app`.
- Google Meet (`google_meet`, app oficial): cria a reunião no canal, na conta Google de quem chama, e posta o cartão com o link de entrar. Cada pessoa conecta a própria conta Google uma vez, pelo navegador (a tela do Google não abre pela API). No canal, o app vem com `account` (`configured`, `connected` e `email`, a conta da pessoa do token). `GET /apps/google_meet/account` (tracker:read) traz `configured`, `connected`, `email` e `connect_url` (abra no navegador, logado no tracker); `DELETE /apps/google_meet/account` (tracker:write) desconecta e tira o acesso no Google. `POST /projects/{ref}/chat/meet` (tracker:write, quem participa da conversa) com `{"title": "Planejamento da sprint"}` (opcional) e `"thread_id"` (opcional: cria dentro da thread daquela mensagem) cria a sala e devolve `project`, `message` (`id`, `thread_id`, `url`) e `meeting` (`url` para entrar, `code` e `title`), 201. App desligado no canal: 403; sem a conta conectada: 422, com o link para conectar. A mensagem traz `card`: `type` `meeting`, `provider` `google_meet`, `url`, `code`, `title` e `started_by` (o nome de quem chamou). Na tela, o botão da câmera ao lado do campo ou `/meet assunto`. No MCP: `start_meeting`.

### aqua e Caixa de entrada

- `GET /aqua` (tracker:read): se a aqua (assistente de IA) está ligada na empresa, `{"available": true, "reason": null, "can_review": true}` (`reason`: `disabled` ou `no_key`; `can_review`: a pessoa edita issues em algum projeto e vê a tela aqua, `GET /aqua/recommendations`). `POST /aqua` (tracker:read): a conversa de ajuda do app, `{"messages": [{"role": "user", "content": "Como crio uma issue?"}], "path": "/issues", "app": "ios"}` (até 20 mensagens, começando e terminando com `user` e alternando; `app`: `ios` ou `mac`, opcional). Devolve `{"answer": "..."}`; 422 quando a IA recusa ou está desligada, sem chave ou no limite.
- `GET /aqua/credits` (tracker:read): os créditos de IA da empresa. Sem chave própria, a aqua usa a chave do tracker e gasta créditos de um pacote por ciclo de 30 dias, que renova sozinho; com a chave própria da empresa, não gasta. Devolve `available`, `reason`, `key_source` (`server`: créditos; `organization`: chave própria; `null` sem IA), `credits` (`null` com a chave própria): `state` (`ok`, `low` com 20% ou menos, `empty` quando acabou e a aqua pausa até renovar, `expired`), `remaining`, `used`, `total` (`per_cycle` mais `granted`, os créditos lançados pela equipe da plataforma no ciclo), `cycle_days`, `cycle_start`, `cycle_end`, `auto_renew` e `renews_at`; e `usage` (só admin e dono, `null` para os demais): `since` (o início do ciclo; com a chave própria, 30 dias atrás) e `by_action`, das ações mais usadas para as menos (`action`, `label`, `calls`, `failures`, `credits`). Sempre em créditos, nunca em dinheiro. Quando uma chamada de IA volta 422 por falta de créditos, a mensagem diz quando renova. No MCP: `get_ai_credits`. A chave própria da empresa (só da Claude) se põe, troca e tira só na tela, em Empresa → Integrações → Assistente de IA (admin e dono): nem a API nem o MCP leem ou gravam a chave.
- Caixa de entrada (a da tela /inbox): `GET /inbox` (tracker:read, `?view=unread` só as não lidas ou `?view=hidden` as ocultadas; sem ele, as não ocultadas; `?before=<id>` pagina, `?limit=` até 100) traz `unread` e `items`, os comentários que chegaram para a pessoa do token, os mais recentes primeiro: `kind` (`mention`: alguém escreveu @o nome dela; `reply`: resposta numa conversa em que ela escreveu), `own_thread` (a conversa começou com um comentário dela), `id` (do comentário), `text`, `author`, `excerpt`, `issue` (`id`, `code`, `title`, `project`), `url`, `at`, `read` e `hidden`. Escrever na tarefa depois do comentário, abrir a tarefa ou ler a notificação dele também contam como lida. As menções e as respostas nas threads das Conversas vêm à parte, em `chat_items` (com `chat_unread`): `id` (da notificação), `kind` (`mention` ou `reply`, resposta numa thread em que ela está), `own_thread` (a thread começou com uma mensagem dela), `thread` (veio de uma thread), `text`, `author`, `excerpt` (o trecho da mensagem), `project`, `url` (direto à mensagem), `at`, `read` e `hidden`; abrir a thread ou ler o canal conta como lida. `POST /inbox` (tracker:read) muda o estado (dos ids de `items` e de `chat_items`): `{"action": "read", "ids": [...]}` ou `{"action": "read", "all": true}`, `{"action": "hide", "ids": [...]}` ou `{"action": "hide", "older_than_days": 30}` (ocultar conta como lida) e `{"action": "unhide", "ids": [...]}`; devolve `updated`, `unread` e `chat_unread`. Resumo da aqua do dia e do mês (o do topo da caixa): `GET /aqua/summary` (tracker:read, `?period=day`, o padrão, ou `month`, no fuso de Brasília) devolve `available`, `reason`, `period` e `summary` (`null` antes de pedir): `headline`, `highlights` (o que aconteceu nas tarefas da pessoa e nas que ela acompanha), `attention` (o que pede a atenção dela), `issues` (as citadas, com `code`, `id` e `url`), `generated_at` e `outdated` (chegou novidade depois). `POST /aqua/summary` (tracker:read) com `{"period": "month"}` pede um novo (gasta créditos de IA; período sem nada não gasta); 422 com a IA desligada, sem chave ou sem créditos. No MCP: `list_inbox`, `update_inbox` e `get_aqua_summary`.
- aqua nas issues (a mesma da tela): `GET /issues/{ref}/aqua` (tracker:read) traz `available`, `can_review` (se a pessoa pode pedir a revisão), `summary` (como `aqua_summary` de `GET /issues/{ref}`), `review` (`summary`, `reviewed_at`, `outdated`), as `recommendations` abertas (`id`, `kind`: `comment`, `status`, `field`, `custom_field`, `label`, `duplicate` ou `move`; `title`, `before`, `after`, `reason` e `comment`, o texto do pedido de informações) e `snooze_options`. `POST /issues/{ref}/aqua/summary` (tracker:read) resume a conversa (a partir de `summary_min_comments` comentários) e devolve `{"summary": ...}`. `POST /issues/{ref}/aqua/review` (tracker:write, quem edita a issue) revisa e devolve o mesmo que o `GET`. `POST /aqua/recommendations/{id}/apply` (tracker:write) aplica a sugestão (`{"comment": "..."}` opcional troca o texto do pedido de informações); `POST /aqua/recommendations/{id}/dismiss` (tracker:write) com `{"for": "7"}` (`1`, `7`, `30` dias ou `forever`) ignora. A tela aqua inteira: `GET /aqua/recommendations` (tracker:read, `?project=MOB` opcional) traz `available`, `reason`, `can_review`, `daily_review` (`enabled`, `hour`, `limit`, `last_on`, `last_count`, `last_error`), `sentry_waiting` (erros do Sentry esperando decisão, em `GET /sentry/errors?waiting=true`), `total` e `issues`, as issues com sugestões abertas (das paradas há mais tempo para as recentes), cada uma com `id`, `code`, `title`, `project`, `status` (`name`, `color`, `category`), `summary`, `reviewed_at`, `outdated` e `recommendations` (como acima), e `snooze_options`. "Revisar issues abertas" roda no servidor: `POST /aqua/review-runs` (tracker:write, `{"project": "MOB"}` opcional) começa a revisão de todas as issues abertas que a aqua ainda não viu ou que mudaram desde a revisão (até 500, uma de cada vez; uma revisão por vez na empresa, e pedir de novo devolve a que já roda) e devolve `{"run": ...}` (`null` sem nada pendente); `GET /aqua/review-runs` (tracker:read) traz a que roda ou a última, `GET /aqua/review-runs/{id}` o andamento (`status`: `running`, `done`, `stopped` ou `failed`; `total`, `reviewed`, `failed`, `suggestions`, `error`, `created_at`, `finished_at` e `issues`, cada uma com `id`, `code`, `title`, `state` — `waiting`, `running`, `done` ou `failed` —, `suggestions` e `error`) e `POST /aqua/review-runs/{id}/stop` (tracker:write) para. `GET /aqua/review-queue` (tracker:read, `?project=` e `?limit=` até 25) continua devolvendo a fila (`id`, `code`, `title`) para revisar uma a uma com `POST /issues/{ref}/aqua/review` e `{"batch": true}` (o modelo da revisão em lote). No MCP: `list_aqua_recommendations`, `start_aqua_review`, `get_aqua_review`, `stop_aqua_review`, `list_issues_to_review`, `review_issue_with_aqua`, `apply_aqua_recommendation` e `dismiss_aqua_recommendation`. `POST /aqua/draft` (tracker:read) com `{"text": "relato livre", "project": "MOB"}` (`project` opcional) devolve os campos de `POST /issues` preenchidos e `missing` (o que o relato não diz), sem criar nada. `POST /aqua/improve` (tracker:read) com `{"project": "MOB", "type": "bug", "title": "...", "description": "..."}` (e os outros textos do formulário) devolve título e textos reescritos e `notes`, sem gravar. 422 quando a IA está desligada, sem chave ou no limite.

### Releases e testes

- `GET /releases` (tracker:read): releases com status, `kind` (`version` ou `ota`), `stage` (`current` é a que está no ar, uma por trilho: a versão e a OTA do projeto têm cada uma a sua; `previous`, `approved`, `testing`, `development`, `planned`, `cancelled`), `stage_label` (o nome na tela), `is_next` (a próxima a ir ao ar), datas, issues em aberto e a última decisão do Release Gate. Query: `project` e `status` (lista separada por vírgula).
- `GET /releases/{id}` (tracker:read): a release com `kind`, `stage`, `stage_label`, `is_next`, o resumo da tela (`summary`: `headline`, `context` e `next_step`), as métricas e a sugestão do gate (`gate.applies`; em OTA sem BLOCKED registrado, `gate.suggestion.decision` é `not_applicable` e no lugar das métricas vem `gate.validation`, a contagem das issues: `ready_for_qa`, `testing`, `approved`, `failed`), a última decisão, as issues, os ciclos de teste e as notas da versão.
- `POST /releases` (tracker:write): cria uma release, `{"project": "MOB", "version": "2.7.0", "build": "...", "environment": "...", "planned_date": "AAAA-MM-DD", "notes": "...", "kind": "version"}`; `kind` é `version` (o padrão) ou `ota`. Release que já foi ao ar (OTA enviada, deploy do backend, versão publicada fora do tracker) pode nascer em produção, sem o gate: `"status": "production"` e `released_date` (padrão: hoje). PO/PM ou admin. A versão é única no projeto: repetir o pedido devolve a release que já existe (200, `already_existed: true`), sem mudar nada nela. Para o CI registrar uma entrega: `POST /releases`, depois `POST /issues/bulk` com `"action": "release"` e as issues, e `POST /releases/{id}/status`.
- `POST /releases/{id}/status` (tracker:write): `{"status": "in_development"}`. O caminho é planned → in_development → staging (em teste), e de approved para production; cancelled sai do caminho. OTA (`kind: "ota"`) vai a `production` direto, de planned, in_development, staging ou approved, sem a decisão do gate, a não ser que a última decisão seja BLOCKED; a validação segue depois pelas issues vinculadas (o `summary.next_step` de `GET /releases/{id}` diz quantas estão em Pronto para QA, em teste, aprovadas e reprovadas). As outras releases chegam a approved pela decisão APPROVED do gate, registrada por uma pessoa na tela, e produção exige essa decisão. Fora desse caminho (approved direto, inclusive) só admin, com `override_note`.
- `POST /releases/{id}/move` (tracker:write): `{"to_project": "PLT"}` move a release para outro projeto da empresa (ex.: os deploys do backend que nasceram no app vão para o projeto da plataforma). Leva histórico, decisões do gate e notas; as issues continuam vinculadas, mesmo as de outros projetos. PO/PM ou admin nos dois projetos; a versão não pode existir no destino e release com ciclo de teste não se move. MCP: `move_release`.
- `PUT /releases/{id}/notes` (tracker:write): grava as notas da versão, o texto para o cliente que a tela copia e manda por e-mail: `{"release_notes": "# App 2.7.0\n\n## Novidades\n\n- Agora dá para..."}`. Markdown simples (`# ` título, `## ` seção, `- ` item; sem negrito nem links). Substitui o texto inteiro; vazio ou `null` volta ao rascunho gerado das issues resolvidas. PO/PM ou admin. A resposta traz `release_notes` e `release_notes_saved`. Não envia o e-mail.
- `GET /test-cases` (tracker:read): casos de teste ativos. Query: `project`, `q` (parte do código ou do título) e `include_archived`.
- `POST /test-cases` (tracker:write): cria um caso, `{"project": "MOB", "title": "...", "module": "...", "priority": "high", "steps": [{"action": "...", "expected": "..."}]}`. QA ou admin. O código (TC-MOB-0001) é gerado.
- `GET /test-cycles` (tracker:read): ciclos mais recentes com o progresso. Query: `project` e `status`.
- `GET /test-cycles/{id}` (tracker:read): o ciclo com cada caso e o resultado (`pass`, `fail`, `blocked`, `in_progress`, `not_started`), o comentário, quem testou e a issue aberta a partir do fail.
- `POST /test-cycles` (tracker:write): cria um ciclo, `{"project": "MOB", "name": "Regressão 2.7.0", "release": "2.7.0", "environment": "...", "cases": ["TC-MOB-0001"]}`. Sem `cases`, entram todos os casos ativos do projeto. QA ou admin.
- `POST /test-cycles/{id}/results` (tracker:write): resultados do CI, até 200 por pedido, `{"results": [{"test_case": "TC-MOB-0001", "status": "fail", "comment": "...", "open_issue": true}]}`. `status`: `pass`, `fail`, `blocked` ou `in_progress`; comentário obrigatório para fail e blocked. Com `open_issue`, o fail abre a issue já preenchida com o caso (ou devolve a que já existe); se a issue não abrir, o resultado fica gravado e o item volta com `warning`. Item a item, com `recorded`, `failed` e `results`. QA ou admin.
- `POST /test-cycles/{id}/status` (tracker:write): `{"action": "start" | "finish" | "cancel" | "reopen"}`. Ciclo encerrado não aceita resultados até ser reaberto.

### Documentos

- `GET /docs` (tracker:read): documentos da base de conhecimento que a pessoa lê, sem o texto (título, `slug`, resumo, projeto, visibilidade). Query: `project` (prefixo, slug ou id, ou `empresa` para os da empresa toda).
- `GET /docs/search?q=<pergunta>` (tracker:read): busca para RAG nos documentos publicados. Devolve os trechos mais relevantes (até 20, padrão 5; `limit`), cada um com o documento, a seção e o texto. `project` restringe a um projeto (os da empresa toda entram junto).
- `GET /docs/{slug ou id}` (tracker:read): o documento com o texto em markdown (`body`). Com `?format=markdown` (ou `Accept: text/markdown`), só o markdown.
- `POST /docs` (tracker:write): cria um documento, ou atualiza o que tem o mesmo `slug` (201 quando cria, 200 quando atualiza). `{"title": "...", "body": "<markdown>", "summary": "...", "project": "MOB", "slug": "...", "visibility": "draft|internal|public"}`. Sem `project`, o documento é da empresa toda (só admin). Bom para publicar a documentação de um repositório pelo CI.

### Sentry

- `GET /sentry/errors` (tracker:read): erros que o Sentry mandou (`?project=MOB` para um projeto, com a integração e o último aviso; `?waiting=true` só os que esperam decisão, como na tela aqua). O mesmo erro aparece uma vez, com `events`, `users`, releases e `state`: `pending` (juntando avisos antes da triagem), `suggested` (a aqua fez a triagem), `linked`, `regressed` (voltou depois de a issue ser concluída; o tracker já comentou na issue), `merged`, `dismissed` ou `muted`. `triage.issue` é a issue que a aqua escreveu e `candidate`, a issue aberta que parece a mesma.
- `POST /sentry/errors/{id}` (tracker:write): decide como na tela aqua, `{"action": "create_issue", "title": "..."}` (cria a issue preenchida, com link, alcance, release, ambiente e stack resumido), `{"action": "link", "issue": "MOB-0012"}` (sem `issue`, a candidata da aqua; comenta na issue), `{"action": "reopen"}` (erro que voltou) ou `{"action": "dismiss", "snooze": "7"}` (`"1"`, `"7"`, `"30"` ou `"forever"`). Exige editar issues no projeto.
- `GET /sentry/connections` (tracker:read, admin e dono): as conexões com o Sentry da empresa, cada uma com `project` (o projeto que recebe o que sobrar), `webhook_url`, `secret_saved`, `sentry_project_targets` (a tabela: `{"sentry_project": "meu-backend", "target": "MOB"}`, com `target` o prefixo do projeto, `rules` ou `ignore`), `new_sentry_projects` (`rules` ou `ignore`), `rules` (na ordem, `"/v1/pedidos/* → API"` ou `"project=APP → APP"`), `environments`, `min_level`, `start_after`, `ai_triage`, `seen` (projetos do Sentry e ambientes que os avisos já mostraram), o último aviso e `waiting`. `GET /sentry/connections/{id}` traz uma.
- `POST /sentry/connections` (tracker:write, admin e dono): conecta um Sentry, `{"project": "MOB"}`; a resposta traz `webhook_url` para criar a Internal Integration no Sentry (Settings → Custom Integrations), e o `client_secret` que o Sentry mostrar entra depois. `PATCH /sentry/connections/{id}`: só o que vier muda, `{"client_secret": "...", "sentry_project_targets": [...], "new_sentry_projects": "ignore", "rules": ["/v1/pedidos/* → API", "project=APP → APP"], "environments": ["prod"], "min_level": "error", "ai_triage": true, "active": true, "start_now": true}` (a tabela e as regras vêm inteiras; `project` troca quem recebe o que sobrar). Na rota, `*` no fim é prefixo; sem `*` vale a rota e o que vem abaixo dela. `DELETE /sentry/connections/{id}` desconecta (os erros recebidos saem, as issues criadas ficam).
- `POST /sentry/connections/{id}/test` (tracker:read, admin e dono): para onde iriam os últimos erros da conexão (até 20), com a configuração salva ou com `sentry_project_targets`, `new_sentry_projects`, `rules`, `environments` e `min_level` do corpo, sem gravar. Cada item traz `result` (`project`, `ignored` ou `outside_environment`), `project` (prefixo), `by` (`table`, `rule` com `rule`, o número da regra, ou `leftover`), `below_min_level`, `now_in`, `route` e `tags`. No MCP: `list_sentry_connections`, `save_sentry_connection` e `test_sentry_connection`.

### Páginas de status

- `GET /status` (tracker:read, admin ou dono da empresa): páginas de status. Serviços (`status` é o que o cliente vê agora, o pior entre `manual_status` e os incidentes abertos; `version`, a versão em produção do projeto), páginas (`url` pública, `slug`, `published`, `primary`) e incidentes e manutenções recentes (`phase`: active, upcoming ou closed).
- `POST /status/services` e `PATCH`/`DELETE /status/services/{id}` (tracker:write): `{"name": "App do motorista", "project": "MOB", "description": "...", "status": "operational|degraded|partial_outage|major_outage|maintenance", "show_version": true, "check_url": "https://api.exemplo.com/health", "sentry_alerts": true}`. No PATCH, só o que vier muda. `check_url`: healthcheck a cada minuto (mais de 3 s é Lento; duas falhas seguidas, Fora do ar); `sentry_alerts`: erro novo no Sentry do projeto deixa Lento por 30 minutos. A resposta traz `monitor` com o último resultado.
- `GET /status/pages/{id}`, `POST /status/pages` e `PATCH`/`DELETE /status/pages/{id}` (tracker:write): `{"title": "Status", "intro": "...", "published": true, "blocks": [{"kind": "projects", "projects": ["MOB"]}, {"kind": "projects", "title": "Plataforma", "projects": ["PLT", "API"], "hidden_services": ["Fila interna"]}, {"kind": "services", "title": "Destaques", "services": ["App do motorista"]}]}`. `blocks` troca todos os blocos, na ordem; sem ele, ficam como estão. Serviço por id ou nome; projeto por prefixo, slug ou id. `slug`: endereço legível no endereço da empresa (`/status/<slug>`; sem ele, sai do título); `primary: true`: a página que abre em `/status` (uma por empresa). A chave da página continua abrindo em qualquer endereço. Aparência (o que não vier fica como está): `brand_name` (marca da página; `null` volta ao nome da empresa), `accent_color` (`#rrggbb`; `null` volta à cor padrão), `links` (até 4 botões no topo, `[{"label": "Suporte", "url": "https://..."}]`, `https:` ou `mailto:`; troca os que havia), `show_history` e `show_past_incidents` (`false` esconde as barras de 90 dias e os incidentes encerrados) e `remove_logo: true`; a logo se envia pela tela e volta em `logo_url`.
- `POST /status/incidents` (tracker:write): abre um incidente ou agenda uma manutenção. `{"kind": "incident|maintenance", "title": "...", "services": ["App do motorista"], "message": "<o que o cliente lê>", "impact": "degraded|partial_outage|major_outage", "status": "...", "starts_at": "2026-10-18T23:00:00-03:00", "ends_at": "..."}` (manutenção exige `starts_at` e `ends_at`).
- `GET /status/incidents/{id}` (com a linha do tempo), `POST /status/incidents/{id}/updates` (`{"message": "...", "status": "monitoring", "impact": "degraded"}`; `resolved` ou `completed` encerra), `PATCH /status/incidents/{id}` (corrige `title`, `services`, `starts_at`, `ends_at` e `impact`, e com `message` também publica uma atualização) e `DELETE /status/incidents/{id}` (tracker:write).

### Quadros de ideias

- `GET /ideas/boards` (tracker:read, admin ou dono da empresa): quadros de ideias, onde os clientes votam no que querem ver. Cada um com `url` (o endereço público, que o cliente abre sem conta), `published`, `ideas` e `pending_suggestions` (sugestões de clientes esperando a equipe).
- `GET /ideas/boards/{id}` (tracker:read), `POST /ideas/boards` e `PATCH`/`DELETE /ideas/boards/{id}` (tracker:write): `{"title": "Ideias para o app", "intro": "...", "projects": ["MOB"], "published": true, "access": "link|restricted", "allow_list": ["@cliente.com.br", "ana@gmail.com"], "allow_suggestions": true}`. No PATCH, só o que vier muda; `projects` e `allow_list` trocam a lista toda. `link`: qualquer um com o link vê, e votar pede o e-mail confirmado por código; `restricted`: só quem confirmar um e-mail da lista vê as ideias. O GET traz `ideas` (publicadas, mais votadas primeiro, com `status` que o cliente vê, `issue`, `votes` e `comments`) e `pending_suggestions` (com `suggested_by`, o e-mail do cliente). Ideia de projeto que saiu do quadro some só da página pública.
- `POST /ideas/boards/{id}/ideas` (tracker:write): cria uma ideia publicada, `{"title": "Exportar em PDF", "description": "...", "project": "MOB", "issue": "MOB-0012", "status": "under_review|planned|in_progress|released|closed"}`. Com `issue` (de um projeto do quadro; sem `title`, usa o da issue), o status segue o da issue; sem ela, vale `status`. Quando o status muda para planned, in_progress, released ou closed, quem votou recebe um e-mail.
- `GET /ideas/{id}` (tracker:read; a ideia com os votos e os comentários, com o e-mail de quem escreveu), `PATCH /ideas/{id}` (os campos da criação, só o que vier muda; `"issue": null` desliga a issue; `{"published": true}` publica a sugestão de um cliente) e `DELETE /ideas/{id}` (exclui; é como se recusa uma sugestão) (tracker:write). `POST /ideas/{id}/comments` com `{"body": "..."}` responde como a equipe (o cliente vê "Equipe <empresa>"); `DELETE /ideas/comments/{id}` apaga um comentário.

### Convites do beta

- Convites do beta (só a equipe da plataforma com a seção Convites beta: ver para listar, gerenciar para gerar, reenviar e revogar; para os outros, 403): o tracker está em beta com acesso por convite, e o convite do beta deixa uma pessoa de fora criar a conta aquarela ID e a própria empresa, como dono (é diferente do convite para uma empresa que já existe, que fica em Empresa → Pessoas). `GET /beta-invites` (tracker:read) lista os convites, os mais novos primeiro, com `status` (`active`, `used`, `expired`, `revoked`), `email`, `note`, `uses` de `max_uses`, validade, `created_by` (quem gerou) e `redemptions` (quem usou, com a empresa que criou). `POST /beta-invites` (tracker:write) gera um, `{"email": "pessoa@empresa.com", "note": "Ana, da Construtora Sul", "days": 14}`: com `email`, o link vai por e-mail e só vale para a conta desse e-mail (uma empresa); sem ele, `max_uses` diz quantas empresas o link cria (padrão 1). 201 com `url` (o link, que não aparece de novo), `expires_at` e `emailed` (`sent`, `disabled` ou `failed`; `null` sem e-mail). `POST /beta-invites/{id}/resend` (tracker:write) manda de novo com um link novo (o anterior para de valer) e `DELETE /beta-invites/{id}` revoga; as empresas já criadas continuam.

### Plataforma

- Plataforma (só a equipe da plataforma, que administra o tracker; para os outros, 403): o dono da plataforma escolhe, seção por seção, o que cada pessoa da equipe vê (`view`) ou gerencia (`manage`): `overview` (visão geral), `organizations` (empresas), `support` (entrar como suporte), `invites` (convites do beta), `ai` (uso de IA) e `audit` (registro). `GET /me` e whoami trazem `platform` (`{"role": "owner|staff", "sections": {"organizations": "manage", ...}}`) para quem é da equipe e vê ao menos uma seção, e as tools de plataforma só aparecem com a seção. Mudar a equipe e entrar como suporte ficam só no app, em Plataforma.
- `GET /platform/overview` (tracker:read, seção overview): os números do tracker: empresas (`active`, `suspended`, `archived`, `created_last_30_days`), pessoas, projetos e issues, uso de IA nos últimos 30 dias (chamadas, custo em USD, empresas que usaram), convites do beta e a versão no ar.
- `GET /platform/organizations` (tracker:read, seção organizations): todas as empresas, com `status` (`active`, `suspended`, `archived`), donos, membros, projetos, issues, chamadas de IA em 30 dias, última atividade e o motivo da suspensão. Filtros `?status=suspended` e `?query=` (nome ou slug).
- `POST /platform/organizations/{id}/suspend` (tracker:write, organizations para gerenciar), com `{"reason": "..."}` opcional: a empresa fica suspensa, e os membros param de entrar no app, na API, no MCP e no Slack até alguém reativar (`POST /platform/organizations/{id}/reactivate`). Nada é apagado; a equipe com a seção de suporte continua entrando.
- `POST /platform/demo-account` (tracker:write, organizations para gerenciar), com `{"email": "revisao@exemplo.com", "name": "Conta de demonstração"}`: prepara a conta que os revisores da App Store e do ChatGPT usam. Cria a Empresa Demo (`empresa-demo`) com dois projetos, 16 issues em vários status, releases, um ciclo de teste e um documento, com a conta do `email` como dona e três colegas fictícios (@example.com, sem e-mail nem push). O revisor entra com a conta aquarela ID desse e-mail, criada lá com senha. Rodar de novo só garante a conta ativa e dona (`created: false`). Recusa (422) e-mail de alguém da equipe da plataforma e conta que já participa de outra empresa.
- `GET /platform/team` (tracker:read, quem é da equipe e vê ao menos uma seção): a equipe da plataforma, com o papel e as seções de cada um.
- `GET /platform/audit` (tracker:read, seção audit): o registro da plataforma, os mais novos primeiro: quem entrou como suporte em qual empresa, empresas criadas, suspensas, reativadas, arquivadas e excluídas, mudanças na equipe e nos convites do beta. Filtros `?action=support_access`, `?organization_id=`, `?actor_id=`, `?limit=` (até 200) e `?before=` (a `created_at` da última linha, para a próxima página). No MCP: get_platform_overview, list_platform_organizations, suspend_organization, reactivate_organization, prepare_demo_account, list_platform_team e list_platform_audit.

## Webhooks de saída

O tracker avisa outro sistema quando algo muda numa issue: um POST em JSON, assinado, para o endereço que a empresa cadastrar. Admin e dono da empresa criam os webhooks no app, em Empresa → Integrações → Webhooks (até 20 por empresa), escolhendo os eventos e se o webhook vale para todos os projetos ou só para um. A mesma tela mostra o segredo, as últimas entregas com a resposta do receptor, o botão de reenviar e o envio de teste (`ping`). Criar e mudar webhooks não existe na API nem no MCP.

Eventos:

- `issue.created`: Issue criada. Pela tela, por e-mail ou pelo MCP.
- `issue.updated`: Issue editada. Campos, registro técnico, release, etiquetas, épico, sprint, estimativa e prazo. Vem com o que mudou.
- `issue.status_changed`: Status mudou. Inclusive pelo reteste (passou ou falhou).
- `issue.assigned`: Responsável mudou. Responsável ou QA responsável.
- `comment.created`: Comentário novo. Inclusive respostas e respostas por e-mail.
- `automation.triggered`: uma regra de automação do projeto com a ação "Enviar webhook" disparou. Vai só para o webhook que a regra escolheu, assine ele o evento ou não, e traz `automation.rule` (`id`, `name`).
- `ping`: o envio de teste da tela, com `message`.

Corpo (JSON), igual em todo evento: `id` (do evento; o mesmo nas retentativas, use para não processar duas vezes), `event`, `created_at`, `organization` (`id`, `slug`, `name`), `actor` (`id`, `name`: quem fez a mudança) e `issue`, o retrato da issue na hora: `id`, `code`, `title`, `url`, `type`, `status` (a chave do fluxo), `status_name`, `status_category` (`todo`, `in_progress`, `done`), `severity`, `priority`, `project` (`id`, `name`, `key`), `assignee`, `qa_owner` e `reporter` (`id`, `name`, ou `null`), `labels`, `release_id`, `fixed_version`, `description`, `custom_fields`, `created_at`, `updated_at` e `resolved_at`. `issue.updated`, `issue.status_changed` e `issue.assigned` trazem `changes`, campo a campo, `{"status": {"from": "open", "to": "doing"}}` (as chaves do histórico da issue). `comment.created` traz `comment` (`id`, `body` em markdown, `parent_id` quando é resposta, `author`, `mentions` e `url`).

Cabeçalhos: `Content-Type: application/json`, `User-Agent: tracker-by-aquarela-webhooks/1.0`, `X-Tracker-Event` (o evento), `X-Tracker-Delivery` (o id da entrega) e `X-Tracker-Signature`.

Entrega: só endereço `https` público (rede interna é recusada), sem seguir redirecionamento, com 10 s para responder. Qualquer 2xx conta como entregue; outra resposta, ou nenhuma, tenta de novo até 6 vezes, depois de 1 min, 5 min, 30 min, 2 h, 6 h. Responda rápido e processe depois: a ordem de chegada não é garantida.

Assinatura: `X-Tracker-Signature: t=<unix>,v1=<hex>`, em que `v1` é o HMAC-SHA256, em hexadecimal, do texto `<t>.<corpo cru>` com o segredo inteiro do webhook (`whsec_...`) como chave. Recalcule com o corpo exatamente como chegou (antes de interpretar o JSON), compare em tempo constante e recuse `t` com mais de 5 minutos de diferença. Durante a troca do segredo o cabeçalho pode trazer mais de um `v1`: aceite se um deles conferir. Em Node:

```js
import { createHmac, timingSafeEqual } from "node:crypto";

// body: o corpo cru da requisição (string), antes do JSON.parse
function isFromTracker(body, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const t = Number(parts.t);
  if (Math.abs(Date.now() / 1000 - t) > 300) return false; // mais de 5 min
  const expected = createHmac("sha256", secret).update(`${t}.${body}`).digest();
  const given = Buffer.from(parts.v1 ?? "", "hex");
  return given.length === expected.length && timingSafeEqual(given, expected);
}
```

## Conceitos

- Organização: a empresa cliente. Os dados de uma organização nunca aparecem em outra.
- Plataforma: a equipe da Aquarela que administra o tracker. O dono da plataforma define o que cada pessoa vê ou gerencia (empresas, suporte, convites, créditos de IA, registro); empresa suspensa fica sem acesso até ser reativada.
- Beta: o tracker está em beta, com acesso por convite. A equipe da plataforma gera o convite do beta (`create_beta_invite`, `POST /beta-invites`); quem usa cria a conta e a própria empresa, e o convite registra quem convidou quem.
- Projeto: tem um prefixo (ex.: MOB) usado no código das issues (MOB-0001), tipos de issue, labels, módulos e campos personalizados próprios.
- Fluxo de status: cada projeto tem os seus status, cada um num grupo (todo, in_progress, done), com os perfis que podem mover para ele e de quais status ele pode vir. Projetos começam no modelo Software + QA (Triagem, A fazer, Fazendo, Em revisão, Em teste, Feito, Cancelado), no modelo Software (A fazer, Fazendo, Em revisão, Feito) ou no modelo QA (Rascunho, Aberto, Triagem, Priorizado, Em desenvolvimento, Pronto para QA, Em reteste, Aprovado, Reprovado, Concluído e Fechado). "Em aberto" é tudo que não está no grupo done.
- Reteste: o QA registra o resultado com versão e dispositivo. No Software + QA, passar leva para Feito e reprovar devolve para A fazer com a marca de reprovada (`retest_failed`), até passar; no modelo QA, vai para Aprovado ou Reprovado.
- Fechado (modelo QA): um status só para o que fecha sem resolver, com o motivo (`close_reason`: duplicada, cancelada, não reproduzida ou não será feita).
- Bloqueio: uma marca na issue, com o motivo, que vale em qualquer status e fluxo (não é uma coluna). Filtre com `blocked_only` ou `bloqueio = sim` na consulta avançada.
- Projetos criados antes desses fluxos continuam com os status antigos (Em reteste, Aprovado, Reprovado, Bloqueado, Reaberto, Duplicado...) até alguém pedir "Simplificar o fluxo" em Configurações > Fluxo de status.
- Severidade: S1 (crítica) a S4 (baixa), impacto técnico. Prioridade: urgent, high, medium, low, importância de negócio.
- Horas: cada issue tem estimativa, início e prazo, e registros de horas (quem, dia, quanto, o que fez). Restante = estimativa menos o registrado. Duração em texto: "2h", "1h30", "45m", "1d" (8 h).
- Documentos: a base de conhecimento da empresa (manuais, regras de negócio, FAQs, processos), em markdown, da empresa toda ou de um projeto. Rascunho (draft) só quem edita vê; internal vale para a equipe (admins e quem é PO/PM, QA ou dev do projeto; stakeholders não veem) e para os agentes conectados em nome dela; public aparece também na central de ajuda pública da empresa, que tem o próprio llms.txt (e llms-full.txt, com todos os textos) para chatbots e RAG sem login. A busca (search_docs, GET /docs/search) devolve trechos por seção, sem diferenciar acento.

## Releases e testes

Guia completo na tela /releases/como-funciona (botão "Como funciona" na lista de releases).
- Release: uma versão de um projeto (ex.: App 2.4.0), com data prevista, issues vinculadas, ciclos de teste e notas da versão (rascunho gerado das issues resolvidas, editável, para copiar ou enviar ao cliente).
- Caminho da release (status): Planejada (planned: no plano, ninguém trabalhando ainda) → Em desenvolvimento (in_development: o time faz as issues) → Em teste (staging: o QA testa em ciclos de teste; antes se chamava Homologação) → Aprovada (approved: o gate registrou APPROVED, pronta para ir ao ar) → Em produção (production: foi ao ar). Cancelada (cancelled) sai do caminho e pode voltar para Planejada. PO/PM move o status; Aprovada normalmente vem da decisão APPROVED do gate; Em produção exige o gate APPROVED (sem ele, só admin, com justificativa), menos na OTA.
- Qual está no ar e qual é a próxima (momento da release): versão e OTA são trilhos separados: em cada projeto, a versão mais recente em produção é a versão no ar e a OTA mais recente em produção é a OTA no ar (current, "Em produção"); as outras em produção do mesmo trilho são anteriores (previous). A próxima (is_next, selo "Próxima") é a que vai ao ar em seguida no seu trilho: a mais adiantada no caminho (Aprovada, depois Em teste, Em desenvolvimento, Planejada) e, empatando, a de data prevista mais cedo. A lista de releases é separada em Em produção, Em teste (inclui Aprovadas), Próximas e Anteriores (inclui Canceladas).
- Atualização sem loja (OTA): release com tipo (kind) "ota", para o que chega aos aparelhos sem passar pela App Store ou Play Store. Crie uma release nova para cada OTA, com a versão que ela leva (ex.: 2.4.1) e o build. Pode seguir o caminho com ciclo de teste e gate, mas não precisa: hotfix por OTA vai ao ar em horas e o QA valida depois, já em produção. Por isso a OTA vai para Em produção de qualquer passo, sem decisão no gate, e pode até ser criada direto como Em produção (status "production") quando já foi enviada. Qualquer release que já foi ao ar fora do tracker (deploy do backend, versão publicada antes) também pode nascer Em produção, com a data em que foi ao ar. A página dela mostra a validação pelas issues vinculadas: quantas estão em Pronto para QA, Em teste, Aprovado e Reprovado. Publicada, ela vira a OTA no ar do projeto e a OTA anterior vai para Anteriores; a versão da loja continua no ar, porque são trilhos separados. Versão normal (loja ou deploy) é kind "version", o padrão.
- Na página da release, o topo diz em uma frase onde ela está, qual está no ar e qual o próximo passo (ex.: criar um ciclo de teste, terminar os testes, corrigir o que falhou, registrar APPROVED, publicar).
- Issue e release: o campo Release da issue diz em qual versão ela sai (a release principal), normalmente do projeto dela; quando a correção sai só em outro projeto (o deploy da plataforma, por exemplo), a principal pode ser a release de lá; o cartão do quadro e a issue mostram, por exemplo, "Sai na 2.4.0 · em teste". Quando o mesmo conserto sai em mais de um lugar (deploy do backend, OTA de cada runtime, console), as outras releases entram em "Também sai em", de qualquer projeto da empresa. A issue aparece em todas elas: na lista da release, no gate, nas notas da versão e na validação. A "Versão corrigida" do registro técnico é só a anotação do dev sobre o build da correção.
- Caso de teste: roteiro com passos e resultado esperado, reaproveitado em cada versão. Ciclo de teste: uma rodada de testes de uma release; cada caso recebe passou, falhou ou bloqueado, e um FAIL pode abrir uma issue já preenchida.
- Release Gate: decisão do QA de liberar (APPROVED) ou segurar (BLOCKED) a versão. O app sugere APPROVED quando há ciclo de teste com casos, todos os testes passaram e não há issue S1 aberta; S2 aberta só gera aviso.
