diff options
| author | Anders Betts <anders.betts@gmail.com> | 2026-09-20 10:36:09 +0200 |
|---|---|---|
| committer | Anders Betts <anders.betts@gmail.com> | 2026-09-20 10:36:09 +0200 |
| commit | 9ee8cb18b1017dce11e7c8c9b7fafad301cb766e (patch) | |
| tree | ab28600c9c29bb425a25d2375d28e95a97aa1f2c /docs | |
| parent | ae60b7d2c87cc9ed6878faa57cd4233f77f6f7c3 (diff) | |
| download | bokf-9ee8cb18b1017dce11e7c8c9b7fafad301cb766e.tar.gz bokf-9ee8cb18b1017dce11e7c8c9b7fafad301cb766e.zip | |
db: make attachments append-only (schema v7)
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/SCHEMA.md | 12 | ||||
| -rw-r--r-- | docs/STATE.md | 13 |
2 files changed, 17 insertions, 8 deletions
diff --git a/docs/SCHEMA.md b/docs/SCHEMA.md index 89dd0b1..2a85521 100644 --- a/docs/SCHEMA.md +++ b/docs/SCHEMA.md @@ -306,6 +306,11 @@ CREATE TABLE attachments ( UNIQUE (org_id, sha256, filename) ) STRICT; +CREATE TRIGGER attachments_no_update BEFORE UPDATE ON attachments +BEGIN SELECT RAISE(ABORT, 'attachments are append-only'); END; +CREATE TRIGGER attachments_no_delete BEFORE DELETE ON attachments +BEGIN SELECT RAISE(ABORT, 'attachments are append-only'); END; + CREATE TABLE voucher_attachments ( org_id INTEGER NOT NULL, voucher_id INTEGER NOT NULL, @@ -317,8 +322,11 @@ CREATE TABLE voucher_attachments ( ) STRICT; ``` -Attachments are content-addressed and immutable; linking is an insert into -`voucher_attachments` and is itself audited. Unlinked attachments form the +Attachments are content-addressed and immutable — the triggers abort updates +and deletes even for a root `sqlite3` session, and `audit.verify full:true` +re-hashes the content; linking is an insert into +`voucher_attachments` and is itself audited (the link table stays mutable so +underlag can be unlinked). Unlinked attachments form the inbox the TUI shows. The 7-year archive rule means content must never be garbage-collected; deduplication by hash keeps repeated receipts cheap. diff --git a/docs/STATE.md b/docs/STATE.md index 526c1a6..e210e1c 100644 --- a/docs/STATE.md +++ b/docs/STATE.md @@ -172,9 +172,9 @@ check. 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`. + the bad ids. Fixed in schema v7: `attachments` now has + `no_update`/`no_delete` triggers; `audit.verify full:true` still detects + on-disk tampering. 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`. @@ -207,7 +207,7 @@ check. ## Environment / how to run -- **Deployed**: `scripts/deploy.sh` (latest `v0.1.44`, healthy on nas). +- **Deployed**: `scripts/deploy.sh` (latest `v0.1.48`, 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 @@ -254,8 +254,9 @@ check. - 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 6 (v3 moms rules; v4/v6 year info; v5 org - description/shares + board members); forward migrations are in `db.c`. +- Schema version is 7 (v3 moms rules; v4/v6 year info; v5 org + description/shares + board members; v7 attachments append-only triggers); + forward migrations are in `db.c`. ## Makandra driftstatus (org 2) |
