Menuabrir
EstávelAtualizado em 14 de mai. de 2026, 00:06

Este módulo depende de

0

Nenhuma dependência outbound.

Módulos que dependem deste

1
  • billingApproval workflow cross-DB — super-admin aprova credenciais antes de ativar

Platform Admin

Status: 🟢 Estável (operações cross-tenant centralizadas) Code: backend/app/modules/platform_admin UI: frontend/src/app/(admin)/[slug]/admin/platform (super-admin only) Última revisão deste doc: 2026-05-13 por Felipe + Claude Dependências fortes: mandir_platform DB (cross-DB writes), billing (approval workflow), all tenants


1. Identidade

O que faz (uma frase)

Operações cross-tenant centralizadas que vivem no mandir_platform DB: provisioning de novo tenant (cria DB + role + cifragem), approval queue de credenciais Asaas (cross-DB writes), dunning lifecycle (D+1 → D+15), drop_scheduler (LGPD offboarding D+45), audit chain SHA256 e custom domains com Traefik provisioning.

Por que existe (negócio)

Algumas operações precisam ser globais (não escopadas a 1 tenant):

  • Provisioning de novo tenant cria DB + role + password — superuser only.
  • Billing approval — só admin Mandir aprova credenciais Asaas (anti-fraude).
  • Dunning — workflow padronizado pra todos os tenants em atraso (não pode ser per-tenant config divergente).
  • Audit chain — tamper-proof central (SHA256 hash chain).
  • Custom domains — Traefik YAML escrito uma vez, serve todos os tenants.

Por que existe (técnico)

  • 0 tabelas próprias no Suite DB — usa mandir_platform.*.
  • Cross-DB writes documentados em ADR (cross-db-writes.md): superuser_conn separado, transacional por tenant DB, audit log entry.
  • Reentrant-safe — endpoint retry-apply permite reaplicar approval após erro.

Status atual

Em prod, todas as features deployadas. Memória [[postgres-role-separation]] documenta padrão de role separation (alembic conecta como dono via *_MIGRATION_DATABASE_URL; runtime usa role limitado).


2. Cases de uso reais

Case 1: Provisioning novo tenant

  1. Felipe via UI /admin/platform/tenants → "Novo Tenant" → form (slug, plan, region).
  2. Backend provision_tenant() → cria DB físico (mandir_<slug>) + role (<slug>_app) + password (gerada + cifrada SOPS) + insere em mandir_platform.tenant.
  3. Tenant pronto pra alembic migrations.

Case 2: Approval credencial Asaas

Tenant submete credencial → fica em mandir_platform.provider_approval_request(status=pending) → Felipe aprova → backend faz cross-DB write em tenant DB (tenant_provider_credentials.status=active) → audit log central.

Case 3: Dunning automático

Beat platform_admin.dunning.run → query tenants com fatura overdue → D+1 envia email soft_reminder → D+3 marca read_only → D+7 suspend → D+15 offboard → D+45 drop_scheduler executa DROP DATABASE (irreversível).


3. Oportunidades de negócio

  • Self-service tenant provisioning: atualmente via super-admin; abrir flow self-service é direto vendas (CRM premium).
  • Multi-region routing: custom_domains + Traefik permite balanceamento global (US/BR/EU).
  • Audit trail vendido como compliance pack: SHA256 chain auditável é diferencial pra setores regulados.

4. Arquitetura interna

Arquivos

ArquivoPropósito
provisioning.pyprovision_tenant (DB + role + password)
billing_approvals.pyWorkflow cross-DB
dunning.pyBeat task lifecycle
custom_domains.pyDNS verify + Traefik YAML
drop_scheduler.pyDROP DATABASE D+45
subscriptions.pyTrial + Asaas webhook (Fase 3)
audit_chain.pySHA256 hash chain
routes.py15 endpoints

Tasks Celery

TaskSchedule
platform_admin.run_dunningBeat diário
platform_admin.run_drop_schedulerBeat diário

5. Tabelas (em mandir_platform, não no Suite DB)

  • mandir_platform.tenant — slug, db_host, db_name, db_user, db_password_secret_ref, status, plan, region.
  • mandir_platform.provider_approval_request — provider, instance_key, status, applied_at, apply_error.
  • mandir_platform.audit_log — SHA256 chain (actor_type, action, prev_hash, current_hash).
  • mandir_platform.subscription — trial/paid (Fase 3).
  • mandir_platform.evolution_server — fleet config global.

Relacionamentos cross-módulo

DireçãoOutro móduloComo
↘ Escreve cross-DBtenant DB.tenant_provider_credentialsApproval workflow
↗ LêbillingSubmit pra approval
↗ Lê tenantsTodosIteração em dunning, drop_scheduler

6. API / Endpoints (15)

Prefixo /api/admin/platform.

Tenant lifecycle (4)

MétodoRotaO que faz
POST/tenantsProvision (DB + role + password)
POST/tenants/{id}/suspendRead-only mode
POST/tenants/{id}/reactivateVolta active
POST/tenants/{id}/offboardLGPD offboarding (DROP em D+45)

Billing approvals (5)

MétodoRotaO que faz
GET/billing/approval-requestsLista (filter status)
GET/billing/approval-requests/{id}Detalhe
POST/billing/approval-requests/{id}/approveCross-DB write → tenant credential active
POST/billing/approval-requests/{id}/rejectMarca rejected
POST/billing/approval-requests/{id}/retry-applyRetry cross-DB

Audit + Health + Subscriptions + Domains (6)

  • GET /audit/verify?start_id&end_id — verifica hash chain.
  • GET /router/metrics — load balancer snapshot.
  • GET /health — agregado.
  • GET /whatsapp/evolution-status — global WA por tenant.
  • POST /subscriptions/checkout — trial + Asaas (idempotency-key).
  • GET /subscriptions/{tenant_id} — list.
  • POST /dunning/run — trigger ad-hoc.
  • POST /tenants/{id}/domains/request — gera token TXT.
  • POST /tenants/{id}/domains/verify — DNS lookup + Traefik YAML.
  • DELETE /tenants/{id}/domains — remove.

7. Configuração

Env vars

VarPropósito
MANDIR_PLATFORM_DATABASE_URLCentral DB
MANDIR_SUPERUSER_DATABASE_URLProvisioning superuser
MANDIR_TENANT_PWD_<SLUG>Cifrado SOPS
MANDIR_TRAEFIK_DYNAMIC_DIR/data/coolify/proxy/dynamic/mandir
MANDIR_VASUDEVA_HOSTHostname remoto

8. Operações + Troubleshooting

Sintoma: Approval workflow apply_error populado

Causa: Cross-DB write falhou (tenant DB indisponível, FK error). Diagnóstico: Verificar apply_error no record; logs platform_admin.billing_approvals.error. Fix: POST /retry-apply após resolver causa raiz.

Sintoma: Dunning não enviou email

Causa: Brevo offline ou user já recebeu (anti-duplicate). Fix: Verificar logs; manual re-trigger.


9. Limitações e débitos técnicos

#Item
1Eventual consistency mandir_platform ↔ tenant DB
2Custom domain DNS apenas TXT — sem CNAME automático
3Offboarding D+45 irreversível
4Audit chain rebuild não automático
5Alembic não é multi-tenant nativo

10. Histórico

ADR 0008 cravou DB-per-tenant. ADR 0009 crypto + Asaas. Memórias [[postgres-role-separation]] + [[alembic-multi-tenant-gotchas]] documentam padrões.