# kanban-persistence-sqlite SQLite storage backend for the kanban workspace. Implements `KanbanBackendFactory`/`KanbanBackend` from `kanban-backend`. ## `SqliteStore` ```rust pub struct SqliteStore { path: String, instance_id: String, // connection pool (lazily initialized) } impl SqliteStore { pub fn new(path: &str) -> Self; pub fn with_instance_id(path: &str, instance_id: &str) -> Self; } ``` The connection pool is initialized lazily on the first operation. The database file is created automatically on first use. --- ## Connection Pool Configuration | Setting | Value | |---------|-------| | Max connections | 2 | | Journal mode | WAL (Write-Ahead Logging) | | Foreign keys | Enforced (`PRAGMA foreign_keys = ON`) | --- ## Schema The schema consists of 13 tables: | Table | Description | |-------|-------------| | `metadata` | Singleton row holding `instance_id`, `saved_at`, and `schema_version` | | `boards` | Board records | | `board_sprint_names` | Sprint name pool per board (ordered by position) | | `board_sprint_counters` | Per-prefix sprint number counters | | `columns` | Column records | | `sprints` | Sprint records | | `cards` | Card records (active and archived live here) | | `sprint_logs` | Sprint assignment history per card | | `archived_cards` | Archive metadata for cards (original column/position, archived_at) | | `spawns_edges` | DAG edges for the `spawns` relation | | `blocks_edges` | DAG edges for the `blocks` relation, with `severity` | | `relates_edges` | Undirected edges for the `relates` relation, with `kind` | | `command_log` | Per-batch JSON serialisation for cross-session undo (KAN-191) | All foreign key relationships are enforced. `boards` → `columns` → `cards` cascade on delete. Edge tables intentionally omit foreign keys on `source_id` / `target_id`: edges are bulk-replaced on every save (DELETE-all + re-INSERT). ### Dependency edge tables The single legacy `card_edges` table was split into one table per kind to mirror the in-memory split (`DagGraph` / `DagGraph` / `UndirectedGraph`). Each table carries only the metadata its kind needs — no nullable catch-all columns. | Table | Columns | CHECK constraints | |-------|---------|-------------------| | `spawns_edges` | `source_id`, `target_id`, `created_at`, `archived_at` | — | | `blocks_edges` | `source_id`, `target_id`, `severity`, `created_at`, `archived_at` | `severity IN ('Low', 'Medium', 'High', 'Critical')` | | `relates_edges` | `source_id`, `target_id`, `kind`, `created_at`, `archived_at` | `kind IN ('General', 'Duplicates', 'MentionedIn')` | Each table has `(source_id, target_id)` as the composite primary key and indexes on both columns. --- ## Save Flow 1. Begin a write transaction 2. `PRAGMA defer_foreign_keys = ON` to allow ordered re-population 3. Delete from every table in dependency order (edges, archive metadata, sprint logs, cards, sprints, board aux tables, columns, boards) 4. Re-insert boards, columns, sprints, cards, archived metadata, then graph edges 5. Commit All operations occur within a single transaction; a failure at any point rolls back completely. This is a full-snapshot replace, not an incremental upsert. --- ## Load Flow 1. Read all tables in join order (boards → columns → sprints → cards → archived metadata → graph edges) 2. Reconstruct `kanban_domain::Snapshot` from relational rows 3. Return snapshot + `PersistenceMetadata` derived from the `metadata` row --- ## Schema Versioning There is no dedicated `schema_version` table. The `metadata` table carries the `schema_version` column (currently `1`) on its singleton row. Migration helpers in `sqlite_store.rs` drop legacy tables (`card_edges`, an older `command_log` shape) when an older database is opened. --- ## Position in the workspace Unlike `kanban-persistence-json`, `kanban-persistence-sqlite` is reachable only as a `KanbanBackend`; nothing in the workspace can ask it for its whole contents as a single storage-format value. ```mermaid graph TD CORE[kanban-core] DOM[kanban-domain] --> CORE PER[kanban-persistence] --> CORE PER --> DOM BE[kanban-backend] --> PER BEMEM[kanban-backend-memory] --> BE SQL[kanban-persistence-sqlite] --> CORE SQL --> DOM SQL --> PER SQL --> BE SQL --> BEMEM TUI[kanban-tui] --> SQL SRV[kanban-server] --> SQL SVC[kanban-service] -.->|feature: sqlite, default-on| SQL CLI[kanban-cli] -.->|feature: sqlite, default-on| SQL MCP[kanban-mcp] -.->|feature: sqlite, default-on| SQL ``` Solid arrows are normal (`[dependencies]`) edges; dotted arrows are feature-gated. Unlike `kanban-persistence-json`, `kanban-service` keeps an *optional* production dependency on this crate, gated behind its own `sqlite` feature (default-on) — SQLite is still the crate's default storage backend even after KAN-1027 dropped the JSON one. Not shown: this crate dev-depends on `kanban-service` (feature `test-helpers`) for the shared contract test suite, and `kanban-service` dev-depends back on it — a dev-dependency-only cycle, never reachable from a release build. See the [root README](../../README.md) for the full workspace dependency graph. ## Dependencies | Crate | Purpose | |-------|---------| | [`kanban-persistence`](../kanban-persistence/README.md) | `PersistenceMetadata` type | | [`kanban-core`](../kanban-core/README.md) | `KanbanError`, `KanbanResult` | | [`kanban-domain`](../kanban-domain/README.md) | `Snapshot` type | | [`kanban-backend`](../kanban-backend/README.md) | `KanbanBackend` trait this backend's `KanbanBackendFactory` produces | | [`kanban-backend-memory`](../kanban-backend-memory/README.md) | Shared in-memory scaffolding this backend's `KanbanBackend` impl builds on | | `sqlx` | Async SQLite with connection pooling | | `tokio` | Async runtime | | `serde` + `serde_json` | Serialisation for the `command_log` table | | `async-trait` | Async trait methods | | `chrono` | Timestamps | | `tracing` | Structured logging | | `flate2` | Compression for durable pre-migration `VACUUM INTO` backups | | `tempfile` | Temp file handling | ## Related crates Used by: [kanban-cli](../kanban-cli/README.md) (optional feature `sqlite`, default-on), [kanban-mcp](../kanban-mcp/README.md) (optional feature `sqlite`, default-on), [kanban-tui](../kanban-tui/README.md), [kanban-server](../kanban-server/README.md), and [kanban-service](../kanban-service/README.md) (optional feature `sqlite`, default-on).