A3 Toyota · Produto & Arquiteturav1
A3 — Hub de APIs (Mercosul/CMA)
O cliente pediu uma API pra os clientes dele rastrearem carga (navio + viagem). Na reunião de 28/07 o time decidiu não travar isso num projeto grande: a fase 1 entra dentro do admin que já existe (rota própria, autenticação simples, log de tudo), rápido o bastante pra não atrasar a renovação de contrato. A ideia original — um serviço novo e separado — não foi descartada, vira a fase 2, escrita no mesmo documento, pra não virar surpresa nem se perder como aconteceu com a atualização do Laravel.
Duas tensões do doc original (banco, auth) se resolveram no contato com a realidade: o banco já é MySQL (a "decisão final" do doc estava certa, só a seção de stack citava Postgres do cenário serviço-novo); auth de fase 1 é App Key simples (precedente do webhook e-cargo), não o HMAC completo do doc. Seguem abertas: versionamento (T3, decidir antes da v1), escopo do sandbox (T4) e se a superfície agentic (T5, MCP sobre a mesma API) entra no desenho do contrato desde já.
Background — o pedido e a analogia
O dono da empresa trouxe: "o cliente pediu que a gente faça uma API externa" — uma API pra os clientes dos nossos clientes. Analogia exata: é como se o GitHub fosse nosso cliente e a gente construísse a API pública do GitHub pra ele. Quem consome essa API a gente não controla e não conhece: backend de terceiro, SaaS integrador, cada vez mais agentes de IA. Muda tudo vs API interna: contrato é promessa pública, segurança é permanente, operação vira produto.
Por que o admin não serve de borda (hoje)
| mercosul-admin (hoje) | Canal externo (precisa) |
|---|---|
| Autenticação de usuário humano | Autenticação por aplicação (m2m) |
| Rota evolui com a tela | Contrato estável e versionado |
| Tenant implícito na sessão | Multi-tenant explícito, da credencial |
| Sem medição de consumo | Quota, rate limit, billing por uso |
| Sem onboarding externo | Sandbox, docs, time-to-first-call |
Baseline do estudo — inegociável · must-have · bom-ter
Inegociáveis: tenant vem da credencial nunca do request · autorização por objeto (anti-BOLA) · auth m2m separada do login humano · rate limit de segurança · validação+serializer explícito · idempotência na escrita · versionamento com depreciação anunciada · PII never-return-by-default · segredos com hash/rotação/revogação · request_id + log estruturado. Must-have: OpenAPI 3.1 spec-first · erro RFC 9457 · sandbox sk_test_/sk_live_ · paginação por cursor · webhooks assinados · headers de rate limit na resposta · docs + time-to-first-call medido · changelog + status page · SLO por segmento. Bom-ter: SDKs gerados · MCP fino sobre a mesma API · erros que instruem o agente · dry-run · bulk endpoints · GET /events · uso quase-real-time pro integrador · llms.txt.
Proposta original do Claudio (fase 2 — documentada, não descartada)
Hub separado do mercosul-admin, monólito modular DDD, 1 deploy só (nasce já com vários microsserviços pequenos foi explicitamente rejeitado no doc). Stack Azure: API Management na borda + Laravel em Container Apps + Postgres/MySQL ver T1 + Redis + Service Bus + Key Vault + App Insights. Módulos: Identidade, Tenant, Catálogo, Execução, Quota, Metering, Auditoria.
Decisão de fase (reunião 28/07 — Rogério · Claudio · Gabriel)
Contexto real: renovação de contrato em negociação, cliente condicionando operação a essa API, gente dentro da Mercosul querendo derrubar o projeto. Infra real: sem docker-compose do time, deploy via ticket com a prestadora, Datadog já derrubou produção antes, especialista de infra saiu da empresa. "Solução simples primeiro" é decisão comercial consciente, não atalho técnico.
| Fase | O quê | Por quê |
|---|---|---|
| Fase 1 | Dentro do admin: rota + middleware + módulo próprios, App Key (precedente webhook e-cargo), autorização via painel, log de toda operação (base pro billing) | não travar renovação de contrato nem dar munição a quem quer cancelar |
| Fase 2+ | O serviço separado do Claudio inteiro (monólito modular DDD, banco próprio, Azure APIM) | observabilidade real, escala, billing sem sobrecarregar o MySQL compartilhado |
Começar barato dentro do admin sabendo que fica caro no longo prazo — o precedente do Laravel desatualizado mostra que "depois a gente tira" pode levar 1+ ano. Mitigação acordada: a evolução entra escrita e ciente no documento pra Mercosul, como foi feito no plano de atualização do Laravel.
Tensões em aberto — o que precisa de dono
Checklist "dá pra lançar?" — vale pra fase 1 também
Do corpus (api-operational-readiness-runbooks): se não dá pra operar, não dá pra lançar. Não é exclusivo do serviço separado — aplica ao escopo fase-1-dentro-do-admin também.
| Item | Status |
|---|---|
| Decisões T1–T5 fechadas e registradas | T1/T2 resolvidos · T3–T5 abertos |
| OpenAPI publicada + docs no ar | a fazer |
| Sandbox funcionando com dados de teste | escopo em aberto (T4) |
| Teste automatizado de isolamento entre tenants | a fazer |
| Playbook de credencial vazada (revogar em segundos) | a fazer |
| Rate limit + quota testados sob carga | a fazer |
| Alerta em sintoma do cliente (não em CPU) | a fazer |
| Status page fora da infra principal | a fazer |
| Política de depreciação publicada | a fazer |
| Metering separando recebida / autorizada / faturável | log de operação já previsto na fase 1 |
Fontes
Google Doc "Hub de APIs como serviço separado" (Claudio Henrique, 27/07) · reunião Rogério · Claudio · Gabriel (28/07) · corpus do vault — 80 notas, moc-public-api-design-security · A3 visual completo com todos os diagramas: ~/.obsidian/03-projects/hub-apis-visao.html · nota pinada no caderninho da Julia: note webvni4y0gir.