SIFIA

Arquitetura · plataforma financeira para construtoras e incorporadoras

O dado do cliente nunca sai do banco do cliente.

O SIFIA lê o ERP da construtora, normaliza num modelo medalhão dentro de um banco exclusivo daquele cliente e serve painéis executivos com número conferido ao centavo. Esta página mostra as peças, como elas se ligam, e por que as regras que parecem "boas práticas" aqui são código que reprova o build.

1 : 1 Uma empresa = um banco Postgres = um projeto Supabase. Não existe tenant_id.
4 Schemas do medalhão: raw · core · kpi · ops
51 Migrations num trilho único, com drift-gate — todo silo recebe o mesmo esquema
895 Testes automatizados em Python, mais 48 suítes no frontend
01 · o princípio

Isolamento físico, não lógico

A forma barata de fazer SaaS multi-cliente é uma coluna tenant_id e um WHERE em toda query. Um bug no WHERE e um cliente vê o outro. Aqui cada cliente tem um banco inteiro só dele — o vazamento não é improvável, é inexprimível.

construtora-a ativa
raw · bruto do ERP core · normalizado kpi · views de painel

Credencial, regras, precedentes e curadoria: todos deste cliente.

construtora-b provisionando
raw · bruto do ERP core · normalizado kpi · views de painel

Mesmo trilho de migrations. Regra de negócio configurada do zero — nada herdado.

construtora-c ativa
raw · bruto do ERP core · normalizado kpi · views de painel

Perímetro de SPEs próprio. O que o motor aprendeu aqui fica aqui.

a muralha Nenhuma seta liga um silo ao outro. Só uma coisa atravessa: lacuna de motor — não-pessoal, sem número, sem nome — que vira melhoria de produto para todos.
bronze — como veio prata — normalizado ouro — pronto para a tela porta humana / fail-closed
02 · o caminho do dado

Do ERP até a tela, em quatro descidas

O dado nunca pula uma camada. Cada descida tem uma responsabilidade única e uma regra que ela é obrigada a fazer valer — é por isso que dá para responder "de onde veio este número?" apontando um arquivo.

Fonte fora do silo

ERP e sistemas do cliente

3 conectores leitura autorizada

Sienge (financeiro e obra), CV CRM (vendas) e Prevision (planejamento físico). Credencial vive no cofre e é resolvida no último instante — nunca em URL, log, argv ou traceback.

extrair · janela + checkpoint
raw bronze

raw.extracao

1 tabela de pouso

A resposta da API cai aqui como veio, com carimbo de quando e de onde. Nada é interpretado nesta camada — se amanhã a regra mudar, o bruto ainda está lá para reprocessar.

Gate anti-zero. Se uma entidade que tinha volume ontem vem vazia hoje, a run para. Zero silencioso é o modo clássico de um painel financeiro mentir sem ninguém notar.

normalizar · regra de negócio
core prata

core.titulos_cp · core.parcelas_cr · core.fc_realizado · …

15 tabelas

O modelo canônico da construtora: título a pagar, parcela a receber, extrato, contrato de venda, unidade, fluxo realizado. Aqui mora a aritmética — líquido de contas a pagar, classificação de recebido, rateio por categoria financeira, regime de caixa.

Uma fórmula, um lugar. Cada regra tem rule_id e origem citada. Duplicar cálculo entre camadas é achado de auditoria, não conveniência.

agregar · nenhuma tabela nova
kpi ouro

kpi.cr_kpis · kpi.cp_por_spe · kpi.fc_mensal · kpi.frescor · …

31 views só views, zero tabelas

A camada que o painel enxerga. São exclusivamente views security_invoker: elas rodam com a identidade de quem perguntou, então a permissão do usuário atravessa a view em vez de ser contornada por ela.

Sem tabela em kpi. Se existisse tabela aqui, existiria um número gravado sem linhagem — e ninguém saberia dizer de qual run ele veio.

ler · PostgREST, filtrado por RLS
Tela o produto

Painel executivo

14 abas white-label em runtime

Fluxo de caixa, contas a pagar e a receber, carteira, comercial, custo, viabilidade e raio-x por obra. Cada bloco trata os quatro estados — carregando, vazio, erro e dado velho — e sinaliza o frescor da última carga.

Degradação honesta. Bloco sem fonte publicada mostra "indisponível" e diz por quê. Nunca R$ 0,00 no lugar de "não sei".

Linhagem de dois domínios, ponta a ponta
DomínioOrigemCamada prataCamada ouroOnde aparece
Contas a pagar Sienge bulk /outcome core.titulos_cp — líquido = saldo − desconto − taxa; marca previsão, inconsistência e parte relacionada cp_kpis, cp_por_spe, cp_por_credor, cp_por_mes Contas a Pagar, Relatório de Contas, Visão Executiva
Contas a receber Sienge bulk /income + /customer-extract-history core.parcelas_cr e core.extrato_cr — classificação de recebido e valor corrigido cr_kpis, cr_clientes, cr_parcelas, cr_fila_cobranca Contas a Receber, Radar de Cobrança, Visão Executiva
Fluxo realizado Sienge bulk, janelas mensais com checkpoint core.fc_realizado — regime de caixa, plano de contas nível 3, rateio por categoria kpi.fc_mensal Fluxo de Caixa 24m, Fluxo 2035
03 · como as peças se ligam

Leitura e ação andam por portas diferentes

A separação mais importante do sistema não é entre front e back — é entre ler e agir. Painel lê o banco direto, com a permissão do usuário aplicada pelo próprio Postgres. Só o que tem efeito colateral passa pela API.

Navegador

React 19 · Vite · TanStack · Tailwind

SPA de página única. A marca, as cores e o domínio do cliente vêm de um arquivo de configuração lido em runtime — o mesmo build serve qualquer construtora.

14 abas + 4 relatórios Cada item do menu aparece só para quem tem o domínio — financeiro ou comercial.
SandBox Demo offline com dados fictícios sobre o mesmo código — três apelidos trocam banco, API e config por dublês.
leitura direta · ação por HTTPS

Leitura — PostgREST

views kpi.*

O painel consulta as views direto. Não existe camada intermediária que possa esquecer de filtrar: o filtro é a política de linha do banco, avaliada com o token do usuário.

Ação — API FastAPI

só efeitos colaterais

Aprovar, recusar, promover versão do fluxo projetado, marcar cobrança, rodar ciclo. Nada de painel passa por aqui — e desembolso exige perfil de CFO ou admin com segundo fator.

um banco por cliente

Postgres do silo

RLS em 100% das tabelas

Os quatro schemas do medalhão mais a governança: configuração, perímetro de SPEs, fila de aprovações, trilha de auditoria, memória do motor de previsão. As contas de serviço do ETL e da API não fazem login e não têm permissão de contornar a política de linha.

raw · 1 Pouso do bruto
core · 15 Modelo canônico
kpi · 31 Views de painel
ops · 26 Governança, aprovações, memória
escreve

ETL e conectores

checkpoint e retomada

Carga histórica de anos inteiros em janelas, com ponto de retomada gravado: se cair no meio, volta de onde parou em vez de recomeçar. Toda regra de normalização vive aqui ou na view — nunca nos dois.

orquestra N silos, um a um

Control-plane

registro + cofre

O único lugar que sabe que existem vários clientes. Guarda o registro de empresas (apelido, referência do banco, referência da credencial, status), resolve segredos no cofre e roda o loop de carga e de migração empresa por empresa. Ele nunca junta dados — abre uma conexão, faz o trabalho, fecha, vai para a próxima.

migrate_all Aplica o trilho com drift-gate; simulação é o padrão, aplicar de verdade é explícito.
etl_all Loop de carga por silo, com relatório de saúde por empresa.
cofre Segredo por referência. Em produção nada de credencial em arquivo.
04 · as fontes

Uma fonte, um conector, um contrato

Três sistemas com transportes, autenticações e paginações completamente diferentes entram no medalhão pela mesma porta: todo conector declara o que sabe fazer, extrai e normaliza. Quem chama não precisa saber se é REST, GraphQL ou bulk.

FontePapelTransporteLimite e incrementalArmadilha já tratada
Sienge ERP financeiro e de obra REST v1 + bulk-data Ritmo com recuo progressivo; janela de competência Usuário de API não é o login web — a credencial é testada antes de ser salva
CV CRM CRM de vendas REST (CVDW) 20 requisições/minuto — estourar bloqueia por 1 minuto; incremental por data de referência A paginação vai no corpo JSON de um GET — é o que o cliente oficial faz
Prevision Planejamento físico de obra GraphQL (Relay) Cursor de página; 60/min por prudência GraphQL falha com HTTP 200 e errors[] no corpo — aqui isso é erro, não sucesso parcial

capacidade é fail-closed

Uma capacidade só habilita regra se estiver comprovadamente suportada. a_confirmar — documentação lida, instância nunca consultada — não habilita nada, mas é reportado separado de ausente: "não olhamos" não é o mesmo que "não tem".

python3 -m conectores

normalizar nunca devolve lista vazia

Enquanto uma entidade não tem destino no medalhão, a normalização levanta erro em vez de devolver []. Lista vazia seria indistinguível de "a fonte não tem registros" — e viraria um zero na tela.

NormalizacaoPendente

PII de funil fica de fora por decisão

Leads, atendimentos e pessoas existem na API do CRM e estão marcados como ausentes, com o motivo escrito. Ligar exige decisão registrada no inventário de tratamento de dados — não uma linha de código.

LGPD · base legal antes do endpoint

05 · a camada agêntica

Automação que propõe. Humano que decide.

Sobre o mesmo dado roda uma camada de agentes — mas ela fica ao lado do duto, nunca dentro dele. Nenhum agente escreve número no painel: eles preparam, conferem, explicam e enfileiram decisões para uma pessoa assinar.

mesa/

zero LLM

Motor determinístico de controladoria. Roda em ciclo: ingestão → conselho → frentes → executor → revisor → memória.

  • 7 cadeiras deliberam: CFO, tesouraria, controladoria, contabilidade, engenharia de custos, auditoria e risco, societário
  • Estado inteiro dentro do silo — nada de estado compartilhado entre clientes
  • Modo simulação é o padrão; teto de aporte começa em zero

python3 -m mesa.main --empresa <slug>

executor

porta única de ação

Toda ação com efeito passa por cinco travas em ordem. Falhar em qualquer uma para tudo.

1 · kill switchBarra tudo, interno e externo
2 · idempotênciaNão paga nem envia duas vezes
3 · tie-outSem conciliação provada, não publica
4 · guarda de caixaTeto de desembolso do cliente
5 · aprovação humanaDecisão registrada na fila, não flag de ambiente

copiloto/

conversa

Pergunta em português, resposta com número certo e evidência citada. Três fases separadas de propósito: planejar (modelo, sem banco) → coletar (banco, sem modelo) → redigir (modelo, sem banco).

  • 10 ferramentas numa lista fechada — cada uma faz um único SELECT numa única view
  • 6 especialistas com roteamento determinístico — quem responde não é escolha do modelo
  • Vigília noturna: prepara o briefing antes de alguém perguntar
  • Ação é sempre proposta: vira item na fila, e a estrutura veta desembolso por essa porta

grounding ao centavo · degrada honesto

controladoria/

11 famílias · A–K

Confronta o dado carregado contra o modelo de expectativa e separa o que é motor do que é decisão humana.

  • Motor aplica sozinho: janelas de carga, thresholds, higiene do silo
  • Dado sempre escala: perímetro de SPEs, identidade das obras, premissas datadas, regime fiscal
  • Misto: a heurística é motor, o nome do pagador é dado sensível e vai para a fila
  • Validação humana vira precedente — o motor fica mais preciso naquele cliente, e só nele

fila de validação · precedentes silados

ml/

previsão de caixa

Curvas de realização aprendidas no histórico do próprio cliente, com cenários pessimista, central e otimista.

  • O baseline é o gate: o modelo esperto só existe se vencer o modelo burro num teste que avança no tempo. Se não vencer, morre documentado
  • Previsão sem linhagem é recusada pelo esquema do banco — não é convenção, é restrição
  • Aritmética de biblioteca padrão: o piso de honestidade antes de qualquer caixa-preta

walk-forward · p10 / p50 / p90

esteira/

implantação

Ligar um cliente novo é um procedimento executável, não um projeto. Sete etapas em ordem, cada uma com semáforo próprio.

  • provisionar → credenciais → carregar → regras → validar → paridade → go-live
  • 9 portas humanas onde alguém assina embaixo — inclusive o tie-out ao centavo
  • Etapa não implementada nunca conta como verde, nem sozinha nem no total
  • Sai um dossiê de implantação com a trilha inteira

fail-closed · backup antes de tudo

06 · os diferenciais

Sete regras que o build cobra

Todo fornecedor promete isolamento, rastreabilidade e IA responsável em slide. A diferença aqui é que cada uma dessas promessas tem um pedaço de código que reprova o build quando ela é violada. Abaixo, a regra, por que ela importa em reais, e onde ela é cobrada.

isolamento

Um cliente, um banco — e o produto se recusa a fazer diferente

Não é convenção de equipe. Existe uma verificação que reprova qualquer banco que tenha uma coluna tenant_id. O recorte de SPEs dentro de uma mesma construtora existe e é outra coisa — é organograma do cliente, não multi-cliente.

o que evita

O incidente de vazamento entre clientes que nenhum seguro cobre e nenhuma construtora perdoa.

onde é cobrado

supabase/invariantes.py · drift-gate do migrate_all

honestidade numérica

Zero nunca substitui "não sei"

O modo silencioso de um painel financeiro mentir é preencher a lacuna com zero. Aqui a carga para quando uma entidade encolhe sem explicação, o bloco sem fonte publicada mostra "indisponível" com o motivo, e o frescor da última carga fica visível na tela.

o que evita

Decisão de caixa tomada sobre um número que só parecia estar lá.

onde é cobrado

gate anti-zero (etl) · componente Indisponivel + kpi.frescor (web)

grounding

Número financeiro sem âncora não sai como verdade

Quando o copiloto redige uma resposta, um verificador confere se cada valor em reais aparece de fato no resultado da consulta. Valor inventado não é bloqueado no prompt — é rebaixado depois de escrito, com ressalva visível e confiança baixa. É a diferença entre pedir para o modelo não alucinar e conferir se ele alucinou.

o que evita

O caso em que a resposta soa perfeita, cita a fonte certa e o número está errado.

onde é cobrado

copiloto/grounding.py — o gate, com suíte própria

papel do modelo

O modelo escreve. Ele nunca decide.

Gate, veredito e fila são resolvidos por régua determinística em código. O modelo de linguagem redige a prosa opcional, sempre rotulada como tal — e se ele não estiver disponível, o sistema continua funcionando e diz que a explicação saiu determinística. Ele também nunca toca o banco: quem tem conexão é o Python, e a lista de consultas permitidas é fechada e só de leitura.

o que evita

Um veredito financeiro que muda de opinião entre duas execuções idênticas.

onde é cobrado

roteamento determinístico · catálogo fechado de ferramentas · transação read only

porta humana

Toda decisão irreversível tem nome, hora e assinatura

Ativar uma empresa, aceitar o tie-out, confirmar a curadoria de recebidos, aprovar um desembolso, apagar o banco de um cliente que saiu — cada uma é uma porta nomeada, que diz por escrito o que a pessoa está assinando embaixo. Aprovação é registro na fila auditável, não uma variável de ambiente ligada.

o que evita

"Ninguém sabe quem aprovou" — a frase que transforma um erro operacional em crise de governança.

onde é cobrado

9 portas nomeadas na esteira · ops.approvals · segundo fator no desembolso

aprendizado

O motor aprende com cada cliente sem misturar nenhum

Toda validação humana vira precedente — e o precedente fica no silo daquele cliente. O que atravessa a muralha rumo ao produto é só lacuna de motor: não-pessoal, sem número, sem nome. O concorrente que treina um modelo comum com o dado de todo mundo tem um argumento de vendas mais fácil e um problema jurídico mais difícil.

o que evita

Explicar a uma construtora por que o modelo dela ficou melhor depois que a concorrente entrou.

onde é cobrado

curadoria de precedentes · rejeitado não volta · muralha auditada

tie-out

O número bate com o relatório oficial, ao centavo

Antes de qualquer cliente ver a primeira tela, contas a pagar e a receber são conferidos contra o relatório que ele já emite no ERP dele — e a diferença tem que ser zero. Isso é o que autoriza o go-live; o semáforo verde da carga não é. E se a conciliação não existir, o motor se recusa a publicar.

o que evita

A reunião em que o controller abre o ERP ao lado do painel e os dois discordam.

onde é cobrado

qa/aceite_paridade.py · gate de tie-out no executor (fail-closed)

07 · como se prova

O que roda antes de qualquer mudança entrar

Nada é dado como concluído sem arquivos alterados, testes rodados, resultado, regras usadas, limitações e riscos declarados. Estes são os gates automáticos.

drift-gate Nenhum silo sai do trilho único de migrations; simulação é o padrão
hermético Postgres em contêiner, banco reconstruído do zero, permissão de linha provada
varredura de marcas Segredo, dado pessoal ou marca de terceiro no diff reprova o PR — sem degradar para aviso
gate de donos Toda tabela do trilho tem um produtor declarado. Tabela órfã não passa
tie-out CR/CP Conferência ao centavo contra o relatório oficial do cliente
auditoria viva do silo Verificação diária de configuração e permissão no banco de cada cliente
build · lint · tipos Frontend com verificação de tipos separada do empacotamento
risco alto = porta humana Banco, autenticação, permissão e regra financeira param e esperam autorização
895 Testes Python em 101 arquivos, de contrato de conector a fila de aprovação
48 Suítes de frontend, mais bateria de ponta a ponta por aba e por perfil
21 Decisões de arquitetura registradas — inclusive as que foram recusadas
9 Rotinas automatizadas: integração, carga, backup, migração, saúde, publicação
em uma frase

A arquitetura é o produto: cada garantia comercial tem um pedaço de código que a cobra.

Painel de fluxo de caixa qualquer fornecedor entrega. O que é difícil de copiar é a combinação de banco separado por cliente, número conferido ao centavo contra o ERP, automação que propõe e humano que assina e aprendizado que nunca cruza a muralha — com cada uma dessas quatro coisas verificada por código que reprova o build, e não por uma política escrita num documento.