Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

112 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Ledgerly

Jurisdiction-aware bookkeeping for single-director companies.

Multi-currency invoicing · double-entry ledger · bank reconciliation · dividend paperwork · a compliance advisor that never guesses — all in one small, self-hostable binary.

License: Apache-2.0 CI Status: Design Phase PRs Welcome


What is Ledgerly?

Running a one-person limited company means juggling invoices in two currencies, reconciling bank feeds, watching your director's loan account, working out how much you can safely take as dividends — and never being quite sure which filing deadline is creeping up. General-purpose accounting suites are built for accountants; Ledgerly is built for the owner-director who does their own books.

  • 💶 Multi-currency invoicing — invoice in EUR or GBP with the ECB rate locked at issue time; realised FX gain/loss is computed automatically on settlement.
  • 📒 Double-entry ledger underneath everything — append-only journal; every balance is derivable from postings. No magic numbers, no drift.
  • 🏦 Bank reconciliation — CSV import (Revolut GBP + EUR first), match suggestions, one-click reconcile.
  • 💷 Director's loan account — running ledger with overdrawn detection and benefit-in-kind warnings.
  • 📄 Dividend paperwork, done — headroom calculation plus generated dividend vouchers and board minutes as PDFs.
  • 📊 Reports & filings — P&L, VAT return figures, a filing calendar, and an export pack for your accountant.
  • 🧭 A deterministic compliance advisor — a rule engine (not an LLM) that evaluates your books against a versioned jurisdiction rules pack and surfaces insights: deadlines, warnings, opportunities. Auditable and testable, as compliance tooling should be.
  • 🤖 CLI + MCP server — AI agents (Claude Code, Codex, …) consume Ledgerly as a tool over the same API you use.

v1 jurisdiction: Isle of Man — deliberately not UK; the rules differ materially. All tax rates, deadlines, and advisor wording live in a versioned rules pack (isle-of-man@1.0), never in code. Adding a jurisdiction means adding a pack, not forking modules.

Design principles

From the high-level design:

  1. Correctness over scale. One company, one or two users, tens of invoices a month. Every design decision favours being right over being fast.
  2. No floats in money paths. Money is int64 minor units + currency; allocation uses largest-remainder so pennies never leak.
  3. Append-only ledger. Journal rows are never updated or deleted; auditability is structural, not procedural.
  4. Jurisdiction as data. Nothing outside the jurisdiction module hard-codes a tax rate, deadline, or advisor sentence — CI guards enforce it.
  5. Modular monolith with real boundaries. One binary, but each module gets its own PostgreSQL schema and DB role; modules interact only through public Go interfaces and domain events. Boundary violations are compile/runtime errors, not review comments.

Architecture

A single Go binary serving a React SPA, with strict internal module boundaries:

graph LR
    subgraph feature ["feature modules"]
        invoicing
        banking
        dla
        dividends
    end
    subgraph core ["core"]
        moneyfx["money-fx"]
        ledger
    end
    subgraph derived ["derived"]
        reports
        advisor
        jurisdiction
    end
    invoicing --> moneyfx
    banking --> moneyfx
    dla --> moneyfx
    dividends --> moneyfx
    moneyfx --> ledger
    reports --> ledger
    advisor --> jurisdiction
    advisor -.read APIs.-> feature
Loading

Modules communicate two ways: synchronous calls through a module's public interface (api.go — the only thing other modules may import), and domain events on an in-process bus with a transactional outbox (invoicing.InvoiceSettled → money-fx posts realised FX to the ledger, in the same DB transaction).

Dig deeper:

Tech stack

Layer Choice
Backend Go (modular monolith), chi router
Database PostgreSQL 16 (Docker Compose locally), schema-per-module
Frontend React + TypeScript (Vite), TanStack Query, React Router
API REST/JSON with OpenAPI 3, generated TS client
Documents React print routes rendered to PDF via chromedp
FX rates ECB daily reference rates (cron fetch)
Agents ledgerly CLI + stdio MCP server

Project status

🚧 Design phase. The architecture and all eleven module designs are complete; implementation is starting with the walking skeleton (see build order). There is no runnable application yet — what you can set up today is the development toolchain below.

Getting started (contributors)

Ledgerly pins its toolchain with mise and automates chores with Task.

Install go-task with:

go install github.com/go-task/task/v3/cmd/task@latest

Current task --list output:

task: Available tasks for this project:
* build:                  Build and vet all Go packages
* ci:                     Run the same checks as CI
* lint:                   Run all lint checks
* run:                    Run the ledgerly skeleton
* test:                   Run unit tests
* lint:arch:              Enforce internal module import boundaries
* lint:fmt:               Check Go formatting
* lint:golangci:          Run golangci-lint
* lint:rates:             Prevent compliance literals outside jurisdiction packs
* test:integration:       Run integration tests

See CONTRIBUTING.md for the full development guide, including the module-boundary rules every PR is held to.

Module directory convention

Each module under internal/<module>/ will use:

  • api.go for the public interface other modules may import
  • events.go for published event types
  • service.go for module orchestration
  • store.go for private persistence
  • http.go for REST handlers

Contributing

Contributions are welcome — especially once the walking skeleton lands. Please read CONTRIBUTING.md first; Ledgerly has strict architectural rules (module boundaries, money handling, jurisdiction data) that reviews enforce firmly.

Found a security issue? Please don't open a public issue — see SECURITY.md.

License

Ledgerly is licensed under the Apache License 2.0.

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages