Skip to content

eriksonwilliam/clojure-xtdb-ledger

Repository files navigation

clojure-xtdb-ledger

Ledger de dupla entrada (contabilidade) em Clojure sobre XTDB — um banco de dados imutável e bitemporal, no espírito do que o Nubank faz com Datomic. Cada lançamento é append-only: nada é atualizado ou apagado, só acrescentado. O saldo é sempre derivado do histórico.

A invariante central da dupla entrada: toda transação soma zero — o que sai de uma conta entra em outra(s). O domínio garante isso antes de persistir.

Destaques

  • Dupla entrada de verdade — transações precisam balancear (soma = 0); o saldo é a soma dos lançamentos, nunca um campo mutável.
  • XTDB (imutável) — persistência append-only; roda com um node em memória, sem serviço externo.
  • Arquitetura hexagonal — a persistência é um defprotocol (port). Há dois adapters: em memória e XTDB. O domínio é Clojure puro, sem I/O.
  • 100% de cobertura de linhas — domínio, serviço, ambos os adapters (o de XTDB testado contra um node real em memória) e a camada HTTP.
  • OpenAPI/Swagger — documentação interativa em /docs.

Stack

  • Linguagem: Clojure 1.12 (na JVM 21)
  • Banco: XTDB 1.x (node em memória)
  • HTTP: handler ring puro (testável sem servidor) + Jetty no bootstrap
  • JSON: Cheshire
  • Testes/cobertura: clojure.test + Cloverage

Arquitetura

src/ledger/
├── domain.clj            # regras puras (validação, saldo)
├── ports.clj             # protocolo LedgerStore
├── service.clj           # casos de uso
├── adapters/
│   ├── memory.clj        # store em memória (atom)
│   └── xtdb.clj          # store XTDB (append-only)
├── http.clj              # handler ring (rotas + erros)
├── openapi.clj           # spec OpenAPI + Swagger UI
└── main.clj              # bootstrap (XTDB + Jetty)

Como rodar

Requer o Clojure CLI (ou o deps.clj) e a JVM 21.

clojure -M:run          # http://localhost:3000

Docker

docker compose up --build

Endpoints

Método Rota Descrição
POST /accounts Cria uma conta (id?, name)
GET /accounts/{id} Consulta uma conta
GET /accounts/{id}/balance Saldo (em centavos)
GET /accounts/{id}/statement Extrato (lançamentos)
POST /transactions Posta uma transação (deve balancear)
GET /docs Swagger UI
GET /health Health check

Exemplo (transferência de R$ 10,00 da Alice para o Bob):

curl -X POST localhost:3000/accounts -d '{"id":"alice","name":"Alice"}'
curl -X POST localhost:3000/accounts -d '{"id":"bob","name":"Bob"}'
curl -X POST localhost:3000/transactions \
  -d '{"entries":[{"account-id":"alice","amount":-1000},
                  {"account-id":"bob","amount":1000}]}'
curl localhost:3000/accounts/alice/balance   # -> {"account-id":"alice","balance":-1000}

Testes e cobertura

clojure -M:coverage

A cobertura de linhas é 100% em todos os namespaces (o main/bootstrap fica de fora). O Cloverage também reporta cobertura de forms (métrica mais rígida, que instrumenta a expansão de macros como cond/try); ela fica em ~99% e é usada apenas como piso no gate.

Licença

MIT.

About

Ledger de dupla entrada (contabilidade) em Clojure sobre XTDB imutavel/append-only, estilo Nubank/Datomic. Arquitetura hexagonal, OpenAPI, Docker, cobertura de linhas 100%

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors