MyFinAI · o sistema operacional financeiro com IA← Documentação
Documentação técnica · v1.0.0 · atualizado 2026-06-09 · ESENPT · ⬇ Baixar Markdown

Arquitetura

O MyFinAI é um monólito FastAPI autocontido sobre PostgreSQL que *extrai* padrões comprovados dos demais sistemas Lopettia em vez de se acoplar a eles: o razão de partida dobrada e a auditoria encadeada do AICOS, o RLS multi-tenant do Kairos, o BYOK Fernet+HKDF do Servitium, os agentes LAF do AIaaSAgents. Um único serviço, uma única base de dados, sem dependências entre produtos.

O plano

Caddy (TLS, reverse proxy)
  ├── /            → site de marketing estático (/srv/myfinai)
  ├── /app, /app/* → o console SPA (contêiner)
  └── /api/*       → a API FastAPI (contêiner)

Contêiner myfinai-api  ──►  PostgreSQL compartilhado
  (rede lopettia_net)         papel myfinai_app (NOSUPERUSER, NOBYPASSRLS)
                              base de dados myfinai

O contêiner expõe a porta 8000 dentro de lopettia_net; o Caddy roteia por rota. O site de marketing vive como estático no host (/opt/www/myfinai, que o Caddy monta como /srv).

Uma identidade, vários espaços

O modelo de dados separa quem você é de onde você trabalha:

household ou platform.

Uma pessoa pode pertencer a vários espaços (Felipe é owner do café e homeowner do lar). Ao mudar de espaço (/api/auth/switch) o sistema valida a associação e reemite o token com o novo tenant_id e papel ativos. O livro do negócio e o do lar nunca se misturam.

RLS: o isolamento vive na base de dados

Cada requisição autenticada roda dentro de uma transação que fixa duas variáveis do Postgres que as políticas RLS leem:

SELECT set_config('app.current_tenant_id', :tenant, true);
SELECT set_config('app.is_platform',       :flag,   true);

Como são usadas com is_local = true (equivalente a SET LOCAL), elas se reiniciam ao terminar a transação e não vazam entre conexões do pool. Todas as tabelas com dados de inquilino levam FORCE ROW LEVEL SECURITY, e a aplicação se conecta com um papel sem BYPASSRLS: nem um erro da aplicação pode ver outro inquilino. A camada de identidade (login, switch) usa uma sessão raw_db sem contexto de inquilino, e nunca consulta dados de negócio.

O livro de partida dobrada

Toda operação financeira é registrada como um lançamento (journal_entries) com suas linhas (journal_lines), cada uma débito ou crédito. O sistema rejeita um lançamento que não fecha, de modo que o balancete de verificação (∑DR = ∑CR) está fechado por construção, não por revisão posterior. Os painéis (caixa, margem, resultado) são calculados a partir do livro em cada carregamento; não há cifras paralelas.

Camadas extraídas

CamadaArquivoOrigem do padrão
Configuraçãoapp/config.pyEducatio
Sessões RLSapp/db.pyKairos
Identidade / JWTapp/security.pyServitium
BYOK (cifragem de chaves)app/crypto.pyServitium
Auth + workspacesapp/routers/auth.pynovo (memberships)
Dashboards por personaapp/routers/dash.pynovo
Superfícies de dadosapp/routers/data.pynovo
Agente Norteapp/routers/agent.pyAIaaSAgents (LAF)

O esquema e as políticas vivem em api/migrations/V001…V005. Para implantar usa-se o padrão operador-laptop da Lopettia (api/infra/scripts/deploy.sh), nunca runners de CI.