motor de faturamento de energia bitemporal

Ele cobra pela leitura que um medidor produz — com exatidão e reprodutibilidade, mesmo com dado sujo.

O Ledgerline recebe as leituras do medidor sem se importar com a ordem ou com repetições, calcula o preço por uma tarifa ANEEL versionada (posto de horário, bandeira, feriado), lança tudo num livro-razão de partida dobrada que sempre soma zero, e guarda um histórico bitemporal que o próprio banco de dados garante — de modo que qualquer conta antiga pode ser reproduzida exatamente como era conhecida em qualquer data, e uma mudança retroativa gera uma nota de ajuste em vez de reescrever a conta original.

Next 16TypeScriptPostgres · EXCLUDE gistOutbox transacional · QStashfast-checkVercel
Provar com um número, não afirmar. A invariante de soma-zero do livro é verificada por propriedade, sobre milhares de sequências embaralhadas — na integração contínua e, abaixo, ao vivo no seu navegador.

Em termos simples: é o sistema que transforma o consumo medido em uma conta de luz correta — e que, se algo for corrigido depois, sabe recontar a história sem apagar o que já havia registrado. Tudo o que está no console abaixo é interativo: mexa à vontade.

Ledgerlineconsole de faturamento bitemporal
medidor MTR-2207ciclo 2026-07motor: no navegadoragora 01/08/2026, 16:00

Ingestão & tarifa

Simule o dia a dia de um medidor: registre leituras de consumo (inclusive repetidas ou atrasadas), escolha a bandeira do mês e feche a conta. Passe o mouse sobre o ? de cada painel para entender o que ele faz.

Registrar uma leitura
Bandeira tarifária
Faturamento
cenário iniciado · 5 leituras, bandeira amarela, fatura emitida

Máquina do tempo bitemporal

Arraste para voltar no tempo. Cada painel é recalculado para aquilo que o sistema sabia naquele instante — reproduzindo a fatura como ela estava antes de qualquer correção posterior.

ao vivo · agoracomo se sabia em 01/08/2026, 16:00
01/08/2026, 09:005 leituras conhecidas01/08/2026, 16:00

Outbox transacional

7 pendentes

Cada mudança grava um evento na mesma transação do dado. Um processo os entrega depois do commit — então nada se perde se a função cair entre uma coisa e outra.

  • pendentefatura emitida2026-07 · 4862
  • pendentebandeira declarada2026-07 → Amarela
  • pendenteleitura registrada5.5 kWh @ MTR-2207
  • pendenteleitura registrada22.5 kWh @ MTR-2207
  • pendenteleitura registrada16 kWh @ MTR-2207
  • pendenteleitura registrada9.5 kWh @ MTR-2207
  • pendenteleitura registrada3 kWh @ MTR-2207

Fatura

2026-07

A conta de luz do mês, aberta por faixa de horário (posto) e com o adicional da bandeira. O valor muda conforme a data escolhida na máquina do tempo — abaixo você vê o que o sistema sabia naquele momento.

como se sabe agorareproduz a fatura emitida
Total
R$ 48,62
Energia
56,5 kWh
Bandeira
Amarela
PostokWhR$/kWhEnergia
Ponta9,51,24738R$ 11,85
Fora-ponta470,52109R$ 24,49
Adicional de bandeira (Amarela)
R$ 1,06
Subtotal
R$ 37,40
Tributos (ICMS + PIS/COFINS)
R$ 11,22
Total
R$ 48,62

Verificador de invariantes

parado

A mesma prova que roda na integração contínua, ao vivo: milhares de sequências embaralhadas — fora de ordem, duplicadas, corrigidas — cada uma conferida para que o livro-razão some zero a cada passo. Prova o motor, em vez de apenas alegar que funciona.

Livro-razão · partida dobrada

4 lançamentos

O registro contábil por trás da conta. Cada valor é lançado em duas contas ao mesmo tempo — uma recebe (débito, D), a outra entrega (crédito, C) — e a soma de tudo tem de fechar em zero.

Fechamento do livroΣ de todos os lançamentos
Σ = R$ 0,00
Contas a receberDR$ 48,62
Receita de energiaCR$ 36,34
Receita de bandeiraCR$ 1,06
Tributos a recolherCR$ 11,22
AjustesR$ 0,00
Lançamentos recentes
  • C Tributos a recolher · Fatura inv-6R$ 11,22
  • C Receita de bandeira · Fatura inv-6R$ 1,06
  • C Receita de energia · Fatura inv-6R$ 36,34
  • D Contas a receber · Fatura inv-6R$ 48,62

Histórico de leituras (bitemporal)

5 versões

Cada versão registrada. Uma correção encerra a leitura anterior e anexa uma nova — a linha antiga nunca é sobrescrita.

Intervalo válidokWhSituação
6 de jul. de 20263 kWhvigente
6 de jul. de 20269,5 kWhvigente
7 de jul. de 202616 kWhvigente
8 de jul. de 202622,5 kWhvigente
9 de jul. de 20265,5 kWhvigente

As quatro partes difíceis

Bitemporal, imposto pelo banco

Dois tempos para cada fato: quando o consumo aconteceu e quando o sistema ficou sabendo dele. Isso permite reconstruir qualquer conta como ela era numa data passada. No Postgres, uma restrição de exclusão (EXCLUDE gist) sobre intervalos de tempo torna impossível haver duas versões conflitantes — a garantia é o próprio banco, não uma linha de código.

Tarifa versionada — a regra é dado

Posto de horário (ponta/intermediário/fora-ponta), bandeira (verde/amarela/vermelha) e feriados móveis calculados a partir da Páscoa são dados versionados, não condicionais no código. Mudar a tarifa de um mês já faturado não altera a conta antiga: emite uma nota de ajuste com a diferença. A original é imutável.

Livro-razão de partida dobrada, soma zero

Todo valor entra em duas contas ao mesmo tempo (débito e crédito), em centavos inteiros. A soma tem de dar sempre zero — e uma transação desequilibrada é impossível de existir: o construtor a recusa. Somar inteiros é exato e independente da ordem, e é isso que torna a convergência um teorema, não uma esperança.

Outbox transacional

Cada mudança grava seu evento na mesma transação do dado; depois, um processo o envia adiante (para o QStash), com o cron diário da Vercel como rede de segurança. Uma função sem servidor pode morrer entre gravar e enviar, e ainda assim nenhum evento se perde.

Como é provado, não afirmado

Testes de propriedade

O fast-check gera milhares de sequências fora de ordem, duplicadas e corrigidas, e prova a convergência, a idempotência e a invariante de soma-zero — a mesma bateria que o console roda ao vivo.

O banco impõe a regra

Uma suíte de integração aplica a migração real a um Postgres e prova que a restrição EXCLUDE gist rejeita uma versão bitemporal sobreposta — quem sustenta a regra é o banco, não a aplicação.

Núcleo determinístico

O motor é uma função pura das suas entradas — sem relógio nem sorteio lido por dentro. Repetir os mesmos comandos produz um estado idêntico, e é isso que torna tudo acima reproduzível.