feat(giro): Capital de Giro G1-G3 — núcleo, série mensal e a tela do Nível 0 - #57
Merged
Conversation
…Nível 0
A tela `/financeiro/giro` era morta: três cards vazios alimentados por um motor que
inferia PMR/PMP de regex na descrição do OFX mapeando para prazos CONSTANTES
(`STONE`→1d, `PAGTO BOLETO`→30d), com selo de "confiança alta" que media quantas
linhas casaram o regex — não acerto. E `cash_cycle_analyses` fazia upsert por
`project_id`: uma linha por projeto, sobrescrita para sempre. O sistema nunca teve
histórico de capital de giro.
Spec canônica: docs/atros-v3/capital-de-giro-spec.md
G1 — núcleo puro (src/lib/giro/), zero I/O, 121 testes
· série operacional: mede o buraco ANTES do socorro (exclui L90 e L65).
Medir depois da antecipação é medir o buraco já tapado — erra PRA MENOS.
· régua em DIAS de faturamento. "Razão de giro" e centavos saíram do produto:
o dono negocia prazo, não índice. As pernas somam com o total exibido.
· decomposição volume × eficiência, fecha exata, termo cruzado na eficiência
· custo do giro = deságio (L65) + juros de contrato de giro
· cadeia do crescimento: pede quanto → tenho → falta → de onde tiro
G2 — série mensal (giro_monthly_snapshots)
· grão projeto+mês+version, imutável; re-fechamento cria version+1
· snapshotGiro no 3o after() do fechar-mes, depois da reconciliação
· estende marcar_snapshot_desatualizado() para marcar o giro na MESMA
varredura (transactions é tabela quente; STATEMENT-level custa O(meses))
· backfill de 34 meses + provador de fidelidade da função SECURITY DEFINER
G3 — a tela do Nível 0
· um DTO só, montado por um serviço só (GET /api/projetos/[id]/giro)
· herói (custo + variação) · mecanismo · crescer · custo · captura
· paleta validada nos 6 checks: CVD deutan dE 13,1 · normal 31,4
Dois bugs que só o dado real pegou, não os testes:
1. custo do giro saía pela METADE. A spec mandava filtrar contrato por
`finalidade`, e ela está NULL em 100% dos contratos do banco. Dois contratos
modalidade='capital_giro' pagando R$ 272.804/ano estavam invisíveis:
R$ 201.390 medido contra R$ 474.194 real — 58% pra menos, na manchete
permanente da tela. Agora é finalidade OU modalidade.
2. o texto do descasamento assumia saída-antes-de-entrada. As duas empresas reais
RECEBEM antes de pagar — a tela teria fabricado um aperto inexistente. Virou
centro de massa com sinal, que funciona nos dois sentidos.
Nada foi deletado: os 6 leitores de cash_cycle_analyses (§3.1) são repontados um a
um, e o DROP é o G7, em sessão própria com re-dump.
Migration aplicada no remoto e re-dump feito (schema.sql 15.030 → 15.206; +1 tabela,
+2 policies, +3 índices, +0 funções — a função foi REPLACE, não duplicada).
Pendente: o visual (hierarquia, fonte, disposição) — o Lucas desenha e eu aplico.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Updates to Preview Branch (feat/capital-de-giro-g1-g3) ↗︎
Tasks are run on every commit but only new migration files are pushed.
View logs for this Workflow Run ↗︎. |
O gate `gerar-estrutura.ts --check` reprovou no CI. Causa: rodei o gerador logo depois do G2, antes de `giro-view-service.ts` existir, e não repeti depois. O serviço do DTO acrescentou três leituras que o mapa não contava: projects 110 → 111 dre_monthly_snapshots 59 → 60 giro_monthly_snapshots 3 → 4 O mapa é gerado do dump cruzado com `src/`, então ele envelhece a cada arquivo novo que lê tabela — não só a cada re-dump. É exatamente o apodrecimento silencioso que o gate existe para pegar, e pegou. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fecha as fases G1, G2 e G3 da trilha de Capital de Giro.
Spec canônica:
docs/atros-v3/capital-de-giro-spec.md·Handoff:
handoff-2026-08-13-capital-de-giro.mdO problema
/financeiro/giroera uma tela morta — três cards vazios e "Ainda não calculado".A causa não era preguiça: a tela calculava um índice de balanço (CR + estoque − fornecedores) a partir de uma fonte de fluxo (o extrato). Extrato é o que passou pelo banco; essas três coisas são exatamente o que ainda não passou. Sem resposta na fonte, o sistema fabricou: PMR/PMP saíam de regex na descrição do OFX mapeando para prazos constantes (
STONE→1d,PAGTO BOLETO→30d), com selo de "confiança alta" que media quantas linhas casaram o regex — não acerto.E
cash_cycle_analysesfazia upsert porproject_id: uma linha por projeto, sobrescrita para sempre. O sistema nunca teve histórico de capital de giro.O que entra
src/lib/giro/— zero I/O, zero Supabase, 121 testesgiro_monthly_snapshots+snapshotGironoafter()do fechar-mes + backfillA pergunta mudou. De "qual é o meu PMR?" para "quanto preciso ter parado pra atravessar o mês, e quanto me custa não ter?". A régua é dias de faturamento parados — o dono negocia prazo a vida inteira, não índice. "Razão de giro" e centavos por real saíram do vocabulário do produto.
Dois bugs que só o dado real pegou
Os testes passavam. O check contra produção não.
1. O custo do giro saía pela metade. A spec mandava filtrar contrato por
finalidade— e ela está NULL em 100% dos contratos do banco. Dois contratosmodalidade='capital_giro'pagando R$ 272.804/ano estavam invisíveis:Na manchete permanente da tela, e na direção que ninguém percebe — número menor não provoca conferência. Agora é
finalidadeOUmodalidade, com teste de regressão.2. O texto do descasamento assumia saída-antes-de-entrada. As duas empresas reais recebem antes de pagar (sai dia 19, entra dia 17). A tela teria dito "é esse descasamento que precisa ser financiado todo mês" sobre um calendário que trabalha a favor delas. Virou centro de massa com sinal, que funciona nos dois sentidos.
Banco
Migration já aplicada no remoto e re-dump feito. Deltas batendo um a um com a intenção:
Funções +0é o número que importa:marcar_snapshot_desatualizado()foi substituída, não duplicada — o risco era criar uma segunda função varrendotransactions(tabela quente) de novo.Fidelidade da função
SECURITY DEFINERprovada duas vezes (anti-padrão 7 da lei de método):scripts/db/provar-fidelidade-trigger.tscompara migration × baseline, e o corpo extraído do dump foi comparado com o da migration — idênticos, 112 linhas. É a diferença entre "a migration diz" e "o banco faz". (O provador reprovou na primeira execução, por uma linha em branco a mais.)Backfill de 34 meses rodado, com check ao vivo recalculando
vale,vale_diaeprofundidadepor caminho independente: zero divergência.Nada foi deletado
Os 6 leitores de
cash_cycle_analyses(§3.1) são repontados um a um.PainelAnaliseSectionseEstoqueSectionficaram órfãs e foram preservadas com comentário honesto — o DROP é o G7, em sessão própria com grep-de-prova e re-dump. Misturar deleção com feature é o anti-padrão 6.Verificação
tsc --noEmitlimpoeslint src/lib/giro src/components/giro→ exit 0PainelCasaTab.tsx→ 2 erros de token, os mesmos 2 do HEAD (débito pré-existente, não tocado)gerar-estrutura.ts --checkem dianext buildnão foi rodado localmente de propósito — o dev server do Lucas estava no ar e o build derruba as rotas dele. O CI cobre.Pendente
O visual. Hierarquia, fonte, cores e disposição ficam como estão: o Lucas desenha e eu aplico depois. Três fatos conhecidos: a casa usa
font-monosó atétext-xl(acima disso vira fonte de terminal), o mockup usava Rajdhani (que o app não carrega), e a composição do mockup foi desenhada paramax-width: 1000px.Próximo: G4 — os 3 saldos no fechamento, que destravam o Nível 1.
🤖 Generated with Claude Code