{
  "schema_version": 1,
  "diagram_type": "architecture",
  "meta": {
    "title": "Cobrança do revendedor — planos, limites, Stripe, Asaas e régua",
    "subtitle": "O provedor só acorda a leitura; o estado vem da releitura, a régua avisa com o link de pagamento e quem paga volta sozinho",
    "output": "cobranca-do-revendedor.html",
    "quality_profile": "standard"
  },
  "lanes": [
    { "id": "dono", "label": "Dono da instalação" },
    { "id": "cliente", "label": "Empresa cliente" },
    { "id": "app", "label": "Aplicativo" },
    { "id": "motor", "label": "Motor da IA" },
    { "id": "db", "label": "Banco" },
    { "id": "provedor", "label": "Provedor de pagamento" }
  ],
  "mainPath": ["telaConexao", "rotaConexao", "adaptador", "stripe", "rotaWebhook", "eventLog", "sinalHandler", "sincronizar", "assinaturas", "fnReativar", "orgs"],
  "nodes": [
    { "id": "telaCobranca", "lane": "dono", "col": 1, "type": "ui", "label": "/admin/cobranca › Planos · Clientes", "sublabel": "app/admin/(protected)/cobranca/page.tsx; porta no AdminSidebar com modulo:'cobranca'" },
    { "id": "telaTenant", "lane": "dono", "col": 1, "type": "ui", "label": "/admin/tenants/[id] card Cobrança · /admin/tenants/new", "sublabel": "CardDeCobranca: atribuir, trocar em teste, dar prazo, isentar, gerar link de pagamento (CPF/CNPJ no Asaas); plano no novo tenant" },
    { "id": "acaoModulo", "lane": "app", "col": 1, "type": "service", "label": "updateModuloDaInstalacao", "sublabel": "requirePlatformAdminEscrita; liga pela tela desde a PR 3a; desligar libera as suspensas por cobrança" },
    { "id": "modulos", "lane": "app", "col": 2, "type": "lib", "label": "lib/instalacao/modulos.ts · MODULO_COBRANCA", "sublabel": "falha fechada; MODULOS_SO_DA_INSTALACAO esconde da empresa", "espelho": "recursos-opcionais.architecture.json#modulos" },
    { "id": "rotasDono", "lane": "app", "col": 2, "type": "api", "label": "admin/cobranca/planos · admin/tenants/[id]/assinatura (+ /prazo, /checkout, DELETE)", "sublabel": "requirePlatformAdminEscrita; 404 com a chave desligada; audit cobranca.*" },
    { "id": "criar", "lane": "app", "col": 2, "type": "service", "label": "POST admin/tenants", "sublabel": "plan (chave desligada) ou plano_id (ligada)", "espelho": "organizacoes-e-acesso.architecture.json#criar" },
    { "id": "cadastro", "lane": "app", "col": 2, "type": "service", "label": "lib/auth/provision.ts (cadastro e provisionamento)", "sublabel": "org criada por caminho de servidor, com created_by do cliente" },
    { "id": "convite", "lane": "app", "col": 3, "type": "service", "label": "POST team/invite", "sublabel": "plano cheio: recusa antes do e-mail (decisão do dono); a trava do aceite é o gatilho", "espelho": "organizacoes-e-acesso.architecture.json#convite" },
    { "id": "rotasCanais", "lane": "app", "col": 3, "type": "api", "label": "channel-sessions · onboarding/whatsapp/session · channels/{official,partner,social,graph-partner}", "sublabel": "traduzirLimiteDoPlano (lib/cobranca/limites.ts): PT402 → 409 plan_limit_reached" },
    { "id": "billing", "lane": "cliente", "col": 4, "type": "ui", "label": "/app/settings/billing › PainelDaAssinatura", "sublabel": "components/cobranca/PainelDaAssinatura.tsx; estado, uso contra os limites e Assinar, Já paguei, Gerenciar, Trocar de plano, Cancelar" },
    { "id": "faixa", "lane": "cliente", "col": 4, "type": "ui", "label": "Faixa de teste grátis em /app", "sublabel": "components/cobranca/FaixaDoTesteGratis.tsx; só admin, só com a chave ligada: teste grátis nos últimos 7 dias; em atraso e cancelamento agendado com o link de pagamento" },
    { "id": "centralUi", "lane": "cliente", "col": 5, "type": "ui", "label": "Central de avisos", "sublabel": "org_reativada · budget_exceeded com ref_kind='plano' (abre Billing)", "espelho": "central-avisos.architecture.json#ui" },
    { "id": "fila", "lane": "cliente", "col": 6, "type": "ui", "label": "/app/inbox, aba Fila", "espelho": "suspensao-de-organizacao.architecture.json#fila" },
    { "id": "tetoPlano", "lane": "motor", "col": 4, "type": "service", "label": "lerTetoDoPlano · decidirTetoDoPlano (orcamento.ts)", "sublabel": "só com a chave de IA da instalação; erro de leitura segue sem teto" },
    { "id": "runModel", "lane": "motor", "col": 5, "type": "service", "label": "aplicarOrcamento (run-model-call)", "sublabel": "AI_BUDGET_ENFORCEMENT=off desliga também o teto do plano", "espelho": "teto-de-orcamento.architecture.json#runmodel" },
    { "id": "legado", "lane": "motor", "col": 5, "type": "service", "label": "ai-response-worker · vetoPorTetoDeGasto", "espelho": "teto-de-orcamento.architecture.json#legado" },
    { "id": "platformConfig", "lane": "db", "col": 2, "type": "table", "label": "platform_config.MODULO_COBRANCA" },
    { "id": "fnLigada", "lane": "db", "col": 3, "type": "database", "label": "fn_cobranca_ligada()" },
    { "id": "planos", "lane": "db", "col": 3, "type": "table", "label": "cobranca_planos", "sublabel": "da instalação; RLS sem policy; só service_role" },
    { "id": "assinaturas", "lane": "db", "col": 3, "type": "table", "label": "cobranca_assinaturas", "sublabel": "uma linha por org; sem linha = isenta; o admin da org lê" },
    { "id": "fnLimite", "lane": "db", "col": 4, "type": "database", "label": "fn_limite_do_plano(org, recurso)", "sublabel": "nulo = sem limite (chave desligada, sem linha ou plano sem teto)" },
    { "id": "trgAssentos", "lane": "db", "col": 5, "type": "database", "label": "trg_trava_assentos_do_plano", "sublabel": "PT402 'limite_do_plano:assentos:N'; linha provisória só pelo servidor (42501)" },
    { "id": "trgCanais", "lane": "db", "col": 5, "type": "database", "label": "trg_trava_canais_do_plano", "sublabel": "PT402 'limite_do_plano:canais:N'; o mesmo lock de fn_reserve_channel_connection" },
    { "id": "trgTrial", "lane": "db", "col": 4, "type": "database", "label": "fn_trial_na_criacao_da_org", "sublabel": "AFTER INSERT em organizations; plano padrão do cadastro" },
    { "id": "vinculo", "lane": "db", "col": 3, "type": "database", "label": "fn_create_tenant_with_owner", "sublabel": "settings.plan como antes; plano_id cria o teste grátis na mesma transação", "espelho": "organizacoes-e-acesso.architecture.json#vinculo" },
    { "id": "aceite", "lane": "db", "col": 6, "type": "database", "label": "fn_accept_team_invite", "sublabel": "PT402 → aplicar-convite: limite_do_plano", "espelho": "organizacoes-e-acesso.architecture.json#aceite" },
    { "id": "orgs", "lane": "db", "col": 4, "type": "table", "label": "organizations.status + suspended_kind", "espelho": "suspensao-de-organizacao.architecture.json#orgs" },
    { "id": "fnSuspender", "lane": "db", "col": 5, "type": "database", "label": "fn_suspender_organizacao", "sublabel": "kind cobranca sem linha de assinatura → org_isenta", "espelho": "suspensao-de-organizacao.architecture.json#fnSuspender" },
    { "id": "fnReativar", "lane": "db", "col": 5, "type": "database", "label": "fn_reativar_organizacao", "sublabel": "passo 7: zera ultimo_aviso da assinatura", "espelho": "suspensao-de-organizacao.architecture.json#fnReativar" },
    { "id": "fnLiberar", "lane": "db", "col": 4, "type": "database", "label": "fn_cobranca_liberar_suspensoes(p_ator)", "sublabel": "reativa toda org suspensa por cobrança" },
    { "id": "eventLog", "lane": "db", "col": 6, "type": "table", "label": "event_log", "sublabel": "tenant.suspended / tenant.reactivated (nascem done, sem consumidor)" },
    { "id": "itens", "lane": "db", "col": 6, "type": "table", "label": "agent_inbox_items", "sublabel": "org_reativada · budget_exceeded ref_kind='plano' (dedup por ref_kind)", "espelho": "teto-de-orcamento.architecture.json#itens" },
    { "id": "regua", "lane": "db", "col": 5, "type": "database", "label": "fn_gasto_de_ia_do_mes(uuid)", "sublabel": "a régua única de gasto; soma o mês inteiro, inclusive chave própria (D-9)", "espelho": "teto-de-orcamento.architecture.json#regua" },
    { "id": "telaConexao", "lane": "dono", "col": 2, "type": "ui", "label": "/admin/cobranca › Visão geral · Conexão · Régua", "sublabel": "checklist de publicação; selo TESTE/PRODUÇÃO; problemas do dono; última leitura; tolerância 5–30" },
    { "id": "rotaConexao", "lane": "app", "col": 3, "type": "api", "label": "POST admin/cobranca/conexao · PATCH admin/cobranca/regua", "sublabel": "única escritora das chaves telaDona:'cobranca'; cifra com AI_CRED_AES_KEY; audit provedor_conectado, modo_publicado, regua_salva" },
    { "id": "baseTeste", "lane": "app", "col": 3, "type": "lib", "label": "base-de-teste.ts · COBRANCA_API_BASE_URL_TESTE", "sublabel": "só loopback e só com o app em loopback; Stripe em <base>/v1, Asaas em <base>/v3; vazio = APIs oficiais" },
    { "id": "adaptador", "lane": "app", "col": 4, "type": "lib", "label": "lib/cobranca/provedores/{contrato,stripe,asaas,index}.ts", "sublabel": "fetch sem SDK; Stripe: Stripe-Version fixada e Idempotency-Key em todo POST; Asaas: access_token, User-Agent próprio, releitura antes de criar, datas civis no fim do dia em São Paulo" },
    { "id": "stripe", "lane": "provedor", "col": 5, "type": "external", "label": "Stripe (API, Checkout, fatura, portal)", "sublabel": "no CI: tests/e2e/fixtures/provedor-de-cobranca.ts em 127.0.0.1:3995, que assina os avisos" },
    { "id": "asaas", "lane": "provedor", "col": 6, "type": "external", "label": "Asaas (API v3: fatura com Pix, boleto e cartão)", "sublabel": "sandbox ou produção pelo prefixo da chave; no CI: o mesmo dublê em 127.0.0.1:3995, dialeto /v3 (tests/e2e/fixtures/provedor-de-cobranca-asaas.ts); fora do CI: scripts/smoke-asaas.ts" },
    { "id": "rotaWebhook", "lane": "app", "col": 5, "type": "api", "label": "POST webhooks/cobranca/[provedor]", "sublabel": "corpo cru; assinatura em tempo constante; 23505 com linha received reemite; recusa deixa rastro (valid_signature=false) e só recusas contam no limite" },
    { "id": "webhookLog", "lane": "db", "col": 6, "type": "table", "label": "webhook_events_log (stripe|asaas)", "sublabel": "org nula; corpo {id,type}; sem cabeçalhos" },
    { "id": "sinalHandler", "lane": "app", "col": 6, "type": "service", "label": "cobrancaSinalHandler", "sublabel": "naOrgParada:'roda'; coalesce 30 s por relida_em" },
    { "id": "sincronizar", "lane": "app", "col": 6, "type": "service", "label": "lib/cobranca/sincronizar.ts", "sublabel": "HTTP fora de transação; compare-and-set por updated_at (a linha lida) e relida_em (a leitura mais nova); e-mails depois do commit" },
    { "id": "estadoPuro", "lane": "app", "col": 7, "type": "lib", "label": "lib/cobranca/{estado,regua}.ts", "sublabel": "tradução e régua puras; o agora é injetável só aqui" },
    { "id": "cronCobranca", "lane": "app", "col": 7, "type": "api", "label": "cron api/v1/cron/cobranca (43 * * * *, scheduler)", "sublabel": "reconciliação de 6 h; régua; 80% da IA; audit cobranca.rodada só com efeito" },
    { "id": "rotasCliente", "lane": "app", "col": 4, "type": "api", "label": "api/v1/cobranca/assinatura/{checkout,sincronizar,plano,cancelar,gerenciar}", "sublabel": "admin da org; permiteOrgSuspensa; checkout em 3 fases" },
    { "id": "hub", "lane": "cliente", "col": 5, "type": "ui", "label": "/account-suspended › Pagar agora · Já paguei", "sublabel": "PainelDaAssinatura no hub do suspenso por cobrança" },
    { "id": "email", "lane": "app", "col": 7, "type": "service", "label": "lib/email/roteador.ts · marcaDaSaida", "sublabel": "avisos da régua ao cliente; troca de chave aos admins full; melhor esforço" }
  ],
  "edges": [
    { "id": "e1", "from": "acaoModulo", "to": "platformConfig", "label": "gravarModulo" },
    { "id": "e2", "from": "acaoModulo", "to": "fnLiberar", "label": "desligar: rpc com p_ator + audit cobranca.modulo_desligado" },
    { "id": "e3", "from": "platformConfig", "to": "modulos", "label": "moduloLigado" },
    { "id": "e4", "from": "platformConfig", "to": "fnLigada", "label": "valor = ligado" },
    { "id": "e5", "from": "modulos", "to": "telaCobranca", "label": "porta só com a chave ligada" },
    { "id": "e6", "from": "modulos", "to": "billing", "label": "cobranca em modulosLigados; desligada = a tela de antes" },
    { "id": "e7", "from": "modulos", "to": "faixa", "label": "cobranca em modulosLigados" },
    { "id": "e8", "from": "telaCobranca", "to": "rotasDono", "label": "planos" },
    { "id": "e9", "from": "telaTenant", "to": "rotasDono", "label": "card Cobrança" },
    { "id": "e10", "from": "telaTenant", "to": "criar", "label": "novo tenant com plano" },
    { "id": "e11", "from": "rotasDono", "to": "planos", "label": "criar, editar, arquivar; preço trava com assinante (409)" },
    { "id": "e12", "from": "rotasDono", "to": "assinaturas", "label": "atribuir, trocar em teste, prazo_extra_ate, apagar = isentar; checkout_url do link gerado pelo dono (org do path)" },
    { "id": "e13", "from": "rotasDono", "to": "fnReativar", "label": "prazo ou isenção de suspensa por cobrança" },
    { "id": "e14", "from": "criar", "to": "vinculo", "label": "p_request com plan ou plano_id" },
    { "id": "e15", "from": "vinculo", "to": "orgs", "label": "INSERT (created_by = platform admin: sem trial automático)" },
    { "id": "e16", "from": "vinculo", "to": "assinaturas", "label": "trial na mesma transação" },
    { "id": "e17", "from": "cadastro", "to": "orgs", "label": "INSERT com created_by do cliente" },
    { "id": "e18", "from": "cadastro", "to": "trgAssentos", "label": "dono em user_organizations" },
    { "id": "e19", "from": "orgs", "to": "trgTrial", "label": "AFTER INSERT" },
    { "id": "e20", "from": "fnLigada", "to": "trgTrial", "label": "só com a chave ligada" },
    { "id": "e21", "from": "planos", "to": "trgTrial", "label": "padrao_no_cadastro, trial_dias" },
    { "id": "e22", "from": "trgTrial", "to": "assinaturas", "label": "estado trial, trial_ate" },
    { "id": "e23", "from": "fnLigada", "to": "fnLimite", "label": "desligada → nulo" },
    { "id": "e24", "from": "planos", "to": "fnLimite", "label": "max_assentos, max_canais, teto_ia_usd_cents" },
    { "id": "e25", "from": "assinaturas", "to": "fnLimite", "label": "plano_id (sem linha → nulo)" },
    { "id": "e26", "from": "fnLimite", "to": "trgAssentos", "label": "'assentos'" },
    { "id": "e27", "from": "fnLimite", "to": "trgCanais", "label": "'canais'" },
    { "id": "e28", "from": "fnLimite", "to": "tetoPlano", "label": "'ia_usd_cents'" },
    { "id": "e29", "from": "convite", "to": "fnLimite", "label": "recusa antes do e-mail" },
    { "id": "e30", "from": "convite", "to": "aceite", "label": "link do convite; a trava é no aceite (D-10)" },
    { "id": "e31", "from": "aceite", "to": "trgAssentos", "label": "INSERT em user_organizations" },
    { "id": "e32", "from": "trgAssentos", "to": "aceite", "label": "PT402" },
    { "id": "e33", "from": "rotasCanais", "to": "trgCanais", "label": "INSERT/UPDATE em channel_sessions" },
    { "id": "e34", "from": "trgCanais", "to": "rotasCanais", "label": "PT402 → 409 com o texto do plano" },
    { "id": "e35", "from": "regua", "to": "tetoPlano", "label": "gasto do mês" },
    { "id": "e36", "from": "regua", "to": "billing", "label": "uso de IA contra o teto" },
    { "id": "e37", "from": "tetoPlano", "to": "runModel", "label": "gasto ≥ teto → bloquear" },
    { "id": "e38", "from": "tetoPlano", "to": "legado", "label": "depois de resolver a origem da chave" },
    { "id": "e39", "from": "runModel", "to": "itens", "label": "budget_exceeded ref_kind='plano'" },
    { "id": "e40", "from": "legado", "to": "itens", "label": "budget_exceeded ref_kind='plano'" },
    { "id": "e41", "from": "runModel", "to": "fila", "label": "handoff humano (LlmBudgetExceededError)" },
    { "id": "e42", "from": "assinaturas", "to": "billing", "label": "estado, plano, trial_ate" },
    { "id": "e43", "from": "assinaturas", "to": "faixa", "label": "trial_ate" },
    { "id": "e44", "from": "faixa", "to": "billing", "label": "ver o plano" },
    { "id": "e45", "from": "fnLiberar", "to": "fnReativar", "label": "kind exigido cobranca" },
    { "id": "e46", "from": "fnReativar", "to": "orgs", "label": "status=active" },
    { "id": "e47", "from": "fnReativar", "to": "assinaturas", "label": "ultimo_aviso = null" },
    { "id": "e48", "from": "fnReativar", "to": "eventLog", "label": "tenant.reactivated" },
    { "id": "e49", "from": "fnReativar", "to": "itens", "label": "org_reativada: conversas, agendamentos desligados e passos descartados" },
    { "id": "e50", "from": "telaTenant", "to": "fnSuspender", "label": "Suspender (administrativa, pela rota da PR 1)" },
    { "id": "e51", "from": "fnSuspender", "to": "orgs", "label": "status=suspended, suspended_kind" },
    { "id": "e52", "from": "fnSuspender", "to": "assinaturas", "label": "kind cobranca exige linha" },
    { "id": "e53", "from": "fnSuspender", "to": "eventLog", "label": "tenant.suspended" },
    { "id": "e54", "from": "itens", "to": "centralUi", "label": "projeção sob RLS" },
    { "id": "e55", "from": "centralUi", "to": "fila", "label": "Abrir o Inbox" },
    { "id": "e56", "from": "centralUi", "to": "billing", "label": "budget_exceeded ref_kind='plano' → Abrir plano e cobrança (admin)" },
    { "id": "e57", "from": "telaConexao", "to": "rotaConexao", "label": "Testar e conectar; tolerância" },
    { "id": "e58", "from": "rotaConexao", "to": "adaptador", "label": "testarChave, clienteExiste (chave de outra conta), prepararWebhook → confirmar/desfazer" },
    { "id": "e59", "from": "rotaConexao", "to": "platformConfig", "label": "STRIPE_* cifradas, COBRANCA_PROVEDOR, COBRANCA_TOLERANCIA_DIAS" },
    { "id": "e60", "from": "rotaConexao", "to": "email", "label": "chave trocada → admins full" },
    { "id": "e61", "from": "baseTeste", "to": "adaptador", "label": "base da API em bancada" },
    { "id": "e62", "from": "baseTeste", "to": "rotaConexao", "label": "app em loopback só com o dublê" },
    { "id": "e63", "from": "adaptador", "to": "stripe", "label": "fetch com Stripe-Version" },
    { "id": "e64", "from": "stripe", "to": "rotaWebhook", "label": "aviso assinado (Stripe-Signature)" },
    { "id": "e65", "from": "rotaWebhook", "to": "webhookLog", "label": "ponteiro {id,type}" },
    { "id": "e66", "from": "rotaWebhook", "to": "eventLog", "label": "emit_event cobranca.sinal" },
    { "id": "e67", "from": "eventLog", "to": "sinalHandler", "label": "loop do worker / event-log-drain" },
    { "id": "e68", "from": "sinalHandler", "to": "sincronizar", "label": "releitura" },
    { "id": "e69", "from": "sincronizar", "to": "adaptador", "label": "lerSituacao" },
    { "id": "e70", "from": "sincronizar", "to": "estadoPuro", "label": "tradução + régua" },
    { "id": "e71", "from": "sincronizar", "to": "assinaturas", "label": "estado, vencida_desde, ultimo_aviso, relida_em" },
    { "id": "e72", "from": "sincronizar", "to": "fnSuspender", "label": "fn_cobranca_suspender_se_devendo: trava a linha, recusa quem pagou no meio" },
    { "id": "e73", "from": "sincronizar", "to": "fnReativar", "label": "pagou → reativa" },
    { "id": "e74", "from": "sincronizar", "to": "itens", "label": "kind cobranca com link de pagamento" },
    { "id": "e75", "from": "sincronizar", "to": "email", "label": "avisos depois do commit" },
    { "id": "e76", "from": "cronCobranca", "to": "sincronizar", "label": "reconciliação > 6 h" },
    { "id": "e77", "from": "cronCobranca", "to": "estadoPuro", "label": "transições de tempo" },
    { "id": "e78", "from": "cronCobranca", "to": "assinaturas", "label": "avisos da régua" },
    { "id": "e79", "from": "cronCobranca", "to": "fnSuspender", "label": "limite + aviso final ≥ 48 h" },
    { "id": "e80", "from": "billing", "to": "rotasCliente", "label": "Assinar, Já paguei, Gerenciar, Trocar, Cancelar" },
    { "id": "e81", "from": "hub", "to": "rotasCliente", "label": "Já paguei / Assinar de novo" },
    { "id": "e82", "from": "rotasCliente", "to": "adaptador", "label": "iniciarAssinatura, urlDeGerenciar, trocarPlano, cancelarNoFim" },
    { "id": "e83", "from": "rotasCliente", "to": "sincronizar", "label": "volta do checkout / Já paguei" },
    { "id": "e84", "from": "orgs", "to": "hub", "label": "suspended{cobranca} → redirect" },
    { "id": "e85", "from": "assinaturas", "to": "telaConexao", "label": "saúde e problemas do dono" },
    { "id": "e86", "from": "webhookLog", "to": "telaConexao", "label": "último aviso do provedor há X" },
    { "id": "e87", "from": "hub", "to": "stripe", "label": "Pagar agora abre a fatura hospedada" },
    { "id": "e88", "from": "billing", "to": "stripe", "label": "checkout e portal hospedados" },
    { "id": "e89", "from": "adaptador", "to": "asaas", "label": "fetch com access_token; lerSituacao com includeDeleted" },
    { "id": "e90", "from": "asaas", "to": "rotaWebhook", "label": "aviso com asaas-access-token (token estático: só acorda a leitura, nunca gravado)" },
    { "id": "e91", "from": "billing", "to": "asaas", "label": "Assinar com CPF/CNPJ (vai ao Asaas, não ao banco); Pagar agora abre a fatura (invoiceUrl)" },
    { "id": "e92", "from": "hub", "to": "asaas", "label": "Pagar agora abre a fatura do Asaas" },
    { "id": "e93", "from": "telaConexao", "to": "asaas", "label": "webhook manual: passo a passo copiável, token mostrado uma vez" },
    { "id": "e94", "from": "rotasDono", "to": "adaptador", "label": "garantirCliente, iniciarAssinatura, lerSituacao via lib/cobranca/checkout.ts (e-mail do admin da empresa, D-15)" }
  ],
  "cards": [
    {
      "dot": "rose",
      "title": "Não-ligações declaradas: o que a cobrança NÃO liga",
      "items": [
        "o aviso do Asaas é um token estático, sem assinatura nem horário: o corpo é só ponteiro e toda decisão vem da releitura (risco 5)",
        "o CPF/CNPJ de quem paga vai direto ao Asaas e não é gravado no banco (§2.3)",
        "o corpo do aviso do provedor nunca decide estado: webhook_events_log guarda só {id,type}; toda decisão vem de lerSituacao",
        "emit_event não reserva cobranca.sinal: um sinal forjado custa no máximo uma releitura a cada 30 s por empresa, o mesmo que Já paguei",
        "nenhuma chamada ao provedor dentro de transação ou com lock aberto: leitura primeiro, escrita curta com compare-and-set depois",
        "SQL_CONFIG_COM_ORCAMENTO (credentials.ts) não consulta o teto do plano: o catch dele desligaria o orçamento da org inteiro",
        "empresa sem linha em cobranca_assinaturas é isenta de limite, régua e cobrança; a org do dono e toda org anterior à chave nascem assim",
        "a empresa não vê a cobrança em Recursos opcionais; troca de plano só vale na virada paga (D-3), salvo no teste grátis (D-13)",
        "sem nota fiscal, cupom, Pix Automático nem upgrade imediato cobrando a diferença (spec §1.2); Pix e boleto recorrentes são a assinatura do Asaas"
      ]
    }
  ]
}
