aboutsummaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
authorAnders Betts <anders.betts@gmail.com>2026-09-21 12:01:06 +0200
committerAnders Betts <anders.betts@gmail.com>2026-09-21 12:01:06 +0200
commit0712cab7f76e49c854a977aceae000cbe3778d41 (patch)
tree164b4fa4e1e6cd122d5ef930829d0e4615ffad3d /README.md
parent9f5a3ac8ed07bdc6b26e7b3ca7242ebfbe67af57 (diff)
downloadbokf-0712cab7f76e49c854a977aceae000cbe3778d41.tar.gz
bokf-0712cab7f76e49c854a977aceae000cbe3778d41.zip
docs: README features, Docker quickstart and agent section
Diffstat (limited to 'README.md')
-rw-r--r--README.md155
1 files changed, 151 insertions, 4 deletions
diff --git a/README.md b/README.md
index 8559ca2..fc1aa33 100644
--- a/README.md
+++ b/README.md
@@ -3,13 +3,61 @@
Self-hosted bookkeeping for Swedish organizations. One C daemon, one SQLite
file, one JSON API shared by the CLI, the ncurses UI and LLM agents.
-Status: **0.1.0-dev — walking skeleton.** Not production ready. See
+Status: **0.1.0-dev — working, not production-proven.** See
`docs/COMPLIANCE.md` §9.
+## Features
+
+Everything below lives in the daemon and one SQLite file; every feature is a
+JSON command in `docs/PROTOCOL.md`, so the TUI, the CLI and an AI agent can
+do the same things.
+
+**Bookkeeping**
+- BAS chart of accounts (K2 and K3 variants), per organization; multi-org with
+ owner/bookkeeper/viewer roles.
+- Verifikat with unbroken numbering per series and fiscal year, balanced
+ rows in integer öre, ändringsverifikat for corrections — nothing is ever
+ edited or deleted.
+- Konteringsmallar: reusable templates with a small formula language
+ (`x*0.25`, `-x`), applied at posting time.
+- Underlag: attachments stored in the database (SHA-256 verified,
+ append-only), an inbox for unlinked documents.
+- Fiscal years, period locks, ingående balans, year-end close.
+
+**Reports and filing**
+- Saldobalans, resultatrapport, balansrapport, huvudbok,
+ verifikationslista — Kapitas-style tables in the TUI, JSON on the API.
+- Momsrapport ruta för ruta with per-org editable rules; eSKD XML export
+ for the momsdeklaration.
+- Bokslut: automated year-end postings (avskrivningar, periodiseringsfond,
+ skatt, resultatdisposition) from a dry-run plan.
+- Årsredovisning K2 text draft and INK2/SRU files (INK2, INK2R, INK2S).
+- SIE 4 import and export (CP437), multi-year history import.
+
+**Invoicing, bank and payroll**
+- Customer register; invoices rendered as PDF (own renderer, no
+ dependencies), OCR numbers, issue = number + PDF + voucher in one
+ transaction, e-mail over SMTP with the password encrypted at rest.
+- Bank reconciliation: import SEB CSV statements, match against vouchers,
+ create prefilled vouchers from unmatched transactions.
+- Payroll engine: employees, Skatteverket tax tables, monthly runs with
+ preview/post, payslips (PDF + e-mail) and AGI underlag — API and TUI
+ complete (Lönekörningar, Anställda, Skattetabeller).
+
+**Compliance and operations** (`docs/COMPLIANCE.md`)
+- SHA-256 hash chains over vouchers and the audit log; `audit.verify`
+ recomputes them and re-hashes attachments.
+- Every mutation is audited; secrets never reach the log.
+- `backup.snapshot` (`VACUUM INTO`) for consistent backups; pre-migration
+ snapshots before schema upgrades.
+- Unix socket, optional TLS listener with certificate reload, Argon2id
+ passwords, scoped revocable API tokens, login rate limiting.
+
## Build
-Requirements: Linux, a C11 compiler, GNU make, and libncursesw for the TUI.
-No other system libraries — SQLite, yyjson, SHA-256 and Argon2 are vendored.
+Requirements: Linux, a C11 compiler, GNU make, libncursesw for the TUI and
+OpenSSL (`libssl-dev`) for TLS and SMTP. SQLite, yyjson, SHA-256 and Argon2
+are vendored.
```sh
make -j$(nproc)
@@ -28,7 +76,9 @@ Produces `build/bokfd` (daemon), `build/bokfctl` (CLI) and `build/bokftui`
```sh
./build/bokfd init --db /var/lib/bokfd/bokfd.db --user admin
-BOKFD_PASSWORD=secret ./build/bokfd init ... # non-interactive
+# non-interactive, same command with the password in the environment:
+BOKFD_PASSWORD=secret ./build/bokfd init --db /var/lib/bokfd/bokfd.db \
+ --user admin
./build/bokfd --db /var/lib/bokfd/bokfd.db --socket /run/bokfd/bokfd.sock
```
@@ -43,11 +93,108 @@ BOKFD_USER=admin BOKFD_PASSWORD=secret \
./build/bokfctl --socket /run/bokfd/bokfd.sock org.create '{"name":"AB Ett","org_nr":"5560123456"}'
```
+## Run the backend with Docker
+
+The image carries `bokfd` and `bokfctl` only (Alpine, ~30 MB). It is built
+from the checkout; there is no registry. The TUI is built on the machine you
+sit at and talks to the container over TLS.
+
+```sh
+# 1. Image
+docker build -t bokf:dev .
+
+# 2. A directory for compose.yaml, .env and the state (var/db, var/run)
+mkdir -p ~/bokf && cp compose.yaml ~/bokf/ && cd ~/bokf
+printf 'BOKF_IMAGE=bokf\nBOKF_TAG=dev\nLEGO_DOMAIN=localhost\n' > .env
+
+# 3. A certificate. Self-signed is fine on a LAN; compose.yaml also has a
+# lego sidecar for Let's Encrypt via DNS-01 (see docs/DEPLOY.md).
+mkdir -p var/db/certs/certificates
+openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes \
+ -days 3650 -subj /CN=localhost -addext subjectAltName=DNS:localhost \
+ -keyout var/db/certs/certificates/localhost.key \
+ -out var/db/certs/certificates/localhost.crt
+
+# 4. Create the database and the admin user, then start
+docker compose run --rm -e BOKFD_PASSWORD=secret123 bokfd init --user admin
+docker compose up -d bokfd
+docker compose ps # wait for "healthy"
+```
+
+Then from any machine that trusts the certificate:
+
+```sh
+export BOKFD_SOCKET=tls:localhost:8788 \
+ BOKFD_TLS_CA=~/bokf/var/db/certs/certificates/localhost.crt
+BOKFD_USER=admin BOKFD_PASSWORD=secret123 ./build/bokfctl health
+BOKFD_USER=admin BOKFD_PASSWORD=secret123 ./build/bokftui
+```
+
+`init` refuses to run twice. State lives in `var/db` (database, `backup/`,
+`export/`, `certs/`) and `var/run` (the Unix socket, for clients on the same
+host). Set `BOKFD_SECRET_KEY` in `.env` (32 random bytes, hex or base64)
+before storing SMTP passwords or employee personnummer (payroll needs it).
+Use `LEGO_DOMAIN`, `LEGO_EMAIL`,
+`INWX_USERNAME`/`INWX_PASSWORD` for a real certificate, and
+`scripts/deploy.sh` to ship releases to a remote host over SSH — both in
+`docs/DEPLOY.md`.
+
+## Working with an AI agent
+
+bokf is designed so that an LLM agent can do the bookkeeping, with a human
+approving what matters:
+
+- **One protocol, self-describing.** `describe` returns every command with
+ its permission, argument schema and defaults; `agent.instructions` returns
+ the workflow rules in Markdown. An agent needs no other documentation.
+- **Safe by construction.** Every mutation supports `dry_run:true`, and
+ postings carry an idempotent `client_ref`; the ledger is append-only, so a
+ wrong posting is corrected by a new voucher, never hidden. Locked periods
+ and closed years are hard stops the agent cannot override.
+- **Least privilege.** Give the agent a scoped API token (`read`, `write`,
+ never `admin`), bound to one organization, shown once and revocable. Owner
+ actions (closing a year in the TUI, token administration in `bokfctl`)
+ stay with the human.
+- **Fully audited.** Every call the agent makes is in the hash-chained audit
+ log with the token that made it.
+
+Setup is one command per agent:
+
+```sh
+BOKFD_USER=admin BOKFD_PASSWORD=… ./build/bokfctl --org 1 token.create \
+ '{"label":"claude","scopes":["read","write"]}'
+```
+
+Point the agent at the socket (or `tls:host:8788`) and the token, tell it to
+fetch `agent.instructions` first, and prompts like these are enough:
+
+- *"Post the September invoices from `~/underlag/2026-09/` — attach each PDF,
+ use the `Försäljning 25 %` template, dry-run everything and show me the
+ list before posting."*
+- *"Import `seb-2026-09.csv`, match what you can against existing vouchers,
+ and prepare — but don't post — vouchers for the rest."*
+- *"Give me the momsrapport for Q3, explain any box that changed more than
+ 20 % from Q2, and save the eSKD file."*
+- *"Run the October payroll preview for all employees and list the
+ differences from September."*
+
+`bokfctl` speaks the same NDJSON protocol from shell scripts and MCP-style
+tool wrappers alike: `bokfctl <command> '<json args>'`.
+
+The same applies to developing bokf. `AGENTS.md` holds the invariants and
+the recipe for adding a command; `make check` fails when code and
+`docs/PROTOCOL.md` drift; `make gate` is the pre-push bar. Most of the
+project was written by agents working from short briefs.
+
## Documentation
- `docs/PROTOCOL.md` — transport, auth, command reference
- `docs/SCHEMA.md` — database schema, invariants, hash chains
- `docs/COMPLIANCE.md` — BFL/BFNAR mapping and operator duties
+- `docs/DEPLOY.md` — Docker, TLS certificates, deploying to a remote host
+- `docs/INVOICING.md`, `docs/PAYROLL.md` — design notes for those modules
+- `docs/TUI-GUIDELINES.md` — keys, widgets and conventions for the TUI
+- `AGENTS.md` — how to work on the code (for humans and agents)
## License