summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorAnders Betts <anders.betts@gmail.com>2026-09-20 09:20:39 +0200
committerAnders Betts <anders.betts@gmail.com>2026-09-20 09:20:39 +0200
commit5b27bb0950fd03d29c223b5960faff89baf37970 (patch)
tree5cc99420a4fc1365fdb8bf4bbec8237fa306fd4b /docs
parenta61cfeefb0599e74fc9189b189b16dd0b6d36f0f (diff)
downloadbokf-5b27bb0950fd03d29c223b5960faff89baf37970.tar.gz
bokf-5b27bb0950fd03d29c223b5960faff89baf37970.zip
audit: verify voucher chains and attachment hashes
Diffstat (limited to 'docs')
-rw-r--r--docs/PROTOCOL.md5
-rw-r--r--docs/STATE.md69
2 files changed, 64 insertions, 10 deletions
diff --git a/docs/PROTOCOL.md b/docs/PROTOCOL.md
index 7052b83..47f6f26 100644
--- a/docs/PROTOCOL.md
+++ b/docs/PROTOCOL.md
@@ -443,10 +443,11 @@ be created.
|---|---|---|
| `backup.snapshot` | `dest?` | `path`, `sha256`, `size`, `at` — uses SQLite `VACUUM INTO`, no downtime |
| `audit.list` | `from?`, `to?`, `action?`, `actor?`, `limit`, `cursor` | behandlingshistorik |
-| `audit.verify` | `full?` | recomputes voucher and audit hash chains; `ok`, `checked`, first/last mismatch if any |
+| `audit.verify` | `full?` | recomputes the voucher and audit hash chains, flags unbalanced vouchers, and with `full:true` re-hashes attachments; `ok`, `checked` (audit entries), `vouchers_checked`, `attachments_checked`, `unbalanced_vouchers` and the first bad `first_bad_voucher_id` / `first_bad_seq` / `first_bad_attachment_id` / `first_unbalanced_voucher_id` on failure |
`audit.verify` is cheap enough to run after every import and before every
-backup; `full:true` includes attachment hashes.
+backup; `full:true` includes attachment hashes. The voucher chain is verified
+per org in posting order (SCHEMA.md §7.1); the audit chain globally.
## 8. The TUI is just a client
diff --git a/docs/STATE.md b/docs/STATE.md
index d75f3cb..9f2f29f 100644
--- a/docs/STATE.md
+++ b/docs/STATE.md
@@ -74,11 +74,14 @@ server/protocol/ledger only.
cert reload on file change) with client targets `tls:host:port` and
system-trust verification (`BOKFD_TLS_CA` for private CAs). Certificates
come from a lego sidecar using INWX DNS-01 (`compose.yaml`). Externals
- get accounts/roles/tokens, never VPN access. `scripts/deploy.sh` builds
- locally and ships over SSH, or builds on the host when architectures
- differ. `scripts/deploy.sh --dev` cross-compiles the binaries here and
- hot-reloads the daemon (SIGHUP re-exec via `docker cp`), skipping the
- image build and container recreate.
+ get accounts/roles/tokens, never VPN access. The runtime image is
+ **Alpine + backend only** (`bokfd`, `bokfctl`; the ncurses TUI is a
+ frontend built on the client machine). `scripts/deploy.sh` builds locally
+ and ships over SSH, or builds the same image natively on the host when
+ architectures differ (no cross-compilation — a musl cross toolchain is
+ not trusted yet). `scripts/deploy.sh --dev` hot-reloads the binaries in
+ the running container (SIGHUP re-exec via `docker cp`) when the
+ architecture matches, otherwise it falls back to a full remote build.
15. **Reports in the TUI**: rendered as fixed-width Swedish tables that mirror
the Kapitas PDF exports (Saldobalans, Resultatrapport with previous-year
column and 89xx bokfört/ej bokfört, Balansrapport with Ing balans/Ing
@@ -152,8 +155,15 @@ server/protocol/ledger only.
years are flagged in the document. ~~SRU files (INK2/INK2R/INK2S)~~ done
as `sru.export` (official 2025P4 field tables, BAS mapping, TUI save in
Rapporter -> Inkomstdeklaration).
-4. `audit.verify` must also verify the **voucher** hash chain (today only the
- audit chain is verified).
+4. ~~`audit.verify` must also verify the **voucher** hash chain (today only the
+ audit chain is verified).~~ Done: recomputes every org's voucher chain in
+ posting order (SCHEMA.md §7.1), flags unbalanced vouchers as a backstop,
+ and `full:true` re-hashes attachment content; result carries
+ `vouchers_checked`, `unbalanced_vouchers`, `attachments_checked` and the
+ first bad voucher/audit/attachment id. TUI Revision shows both counts and
+ the bad ids. **Found while testing: `attachments` has no
+ append-only triggers** (COMPLIANCE.md §2 claims it does); content changes
+ are detected only by `audit.verify full:true`.
5. ~~`report.general_ledger` and `report.voucher_list`~~ implemented
(Huvudbok, Verifikationslista) with Kapitas-style TUI tables; the ledger
API supports `accounts`/`from`/`to`, the list an optional `series`.
@@ -182,6 +192,21 @@ server/protocol/ledger only.
## Environment / how to run
+- **Deployed**: `scripts/deploy.sh` (latest `v0.1.44`, healthy on nas).
+ Live daemon `tls:bokf.makandra.eu:8788`, token
+ `~/.config/bokf/migration-token` (scopes `read,write`; owner-only actions
+ like closing years must be done by the human in the TUI). Git remote
+ `origin` is `nas:/mnt/data/git-repos/bokf.git` (push `main` and tags).
+- **Local test rig** (transient, `/tmp`): daemon
+ `./build/bokfd --db /tmp/opencode/bokf-local/t.db --socket
+ /tmp/opencode/bokf-local/sock`, org 1, login `admin`/`testpass123`.
+ Drive the TUI over a pty with `scripts/tui-sandbox.sh -- ./build/bokftui
+ --socket /tmp/opencode/bokf-local/sock --org 1 --fy 1 ...` plus a small
+ driver that feeds keys and an ANSI renderer (recreate if gone; arrows are
+ `ESC O B/A`, Tab `\t`, `^X` `\x18`, `^Enter` `ESC[27;5;13~`, F5
+ `ESC[15~`). Never test against the live daemon.
+
+
- Demo: db `~/bokf-demo/bokfd.db`, socket `~/bokf-demo/bokfd.sock`,
pid file `~/bokf-demo/bokfd.pid`; login `admin` / `demo1234`.
Start TUI: `cd ~/work/bokf && BOKFD_SOCKET=$HOME/bokf-demo/bokfd.sock \
@@ -207,4 +232,32 @@ server/protocol/ledger only.
- Never commit unless the human asks.
- SQLite files must not be backed up live with restic; use
`backup.snapshot` (`VACUUM INTO`) and point restic at the snapshots.
-- Schema version is 3; forward migrations are in `db.c`.
+- Schema version is 6 (v3 moms rules; v4/v6 year info; v5 org
+ description/shares + board members); forward migrations are in `db.c`.
+
+## Makandra driftstatus (org 2)
+
+- **Org**: Makandra AB, org 2. Räkenskapsår (id): 2022=3, 2023=4, 2024=5,
+ 2025=6, 2026=7, **2027=2 (öppet, aktuellt)**. Bokslut/AR/deklaration görs
+ för det år som är valt i sessionen.
+- **FK2027**: importerade Kapitas-böcker + 28 bokförda verifikat (V21–V48)
+ för bank/skatt maj–sep 2026, samt V49 som makulerar en dubblett (V20).
+ 1930 stämmer mot banken utom **CDON 2 409 kr** (väntar på kvittots del
+ 2–4; bokförs när det kommer). 1630 = 40 721 (exakt enligt Skatteverket).
+- **Underlag**: 279 attachment i org 2 (alla historikdokument + insamlade
+ underlag). Bank-/SKV-utdrag ligger i `~/Makandra AB/{bank,skatteverket}`
+ (Syncthing), källkorpus i `~/Downloads/Makandra AB-…/Bokföring/`.
+- **Stängning**: 2022–2026 ska stängas av ägaren via **Räkenskapsår** i
+ TUI:n; låt FK2027 vara öppen till nästa bokslut.
+- **Deklaration**: FK2026 är deklarerad av revisorn. FK2027 deklareras
+ våren 2027 (INK2/SRU via Bokslutshubben → Inkomstdeklaration).
+- **Årshäftet**: fylls i Bokslutshubben (händelser, stämma, utdelning +
+ datum, medelantal, noter). OBS: `dividend_ore` för FK2027 kan vara ett
+ testvärde (10 000) — kontrollera före AR/deklaration.
+- **Beslut/regler från bokföringsarbetet**: inga bokföringar utan
+ godkännande; låsta år förblir låsta (rättelser görs i aktuellt år); SIE-
+ importören ändras inte och importerad data "manipuleras" inte;
+ historikårens P&L nettar noll pga källsystemets stängningar (AR hoppar
+ över "Stäng"-verifikat i flerårsöversikten); utdelning bokförs vid stämman
+ med mallen **Utdelning** (D 2099/K 2898); pappersoriginal finns i fysisk
+ pärm (får refereras i efterhand, även i stängda år).