# SQLite Storage Spike Chanora proof-of-concept. **Not product code.** | Field | Value | |---|---| | PoC name | `sqlite-storage-spike` | | PoC plan | [`docs/architecture/proof-of-concept-plan.md`](../../docs/architecture/proof-of-concept-plan.md) §2 | | Purpose | Prove embedded local non-secret persistence | | Exit criterion | "Schema, migration, and repository pattern are demonstrated" | | Authority | SRS-089 (acceptance criteria: embedded data store + migration mechanism), SDD-077, SAD-067 | ## What it proves - A **schema** managed entirely inside SQLite (`bookmarks`, `settings`) with a UNIQUE index, secondary indices, and `ON CONFLICT` upsert semantics for the settings table. - A **forward-only migration mechanism** keyed on `PRAGMA user_version`. Migrations are applied atomically inside an IMMEDIATE transaction and rolled back on failure. - A **repository pattern**: `BookmarkRepository` and `SettingsRepository` traits, implemented once by `LocalDatabaseRepository`. The rest of the Rust core can depend on the traits and avoid leaking SQLite-specific types upward (SAD-067, SDD-077). - **Cross-spike contract**: `Bookmark.identity_ref` is a *name*, not a secret. The secret behind that name lives in `SecretStorageRepository` (see `secure-storage-spike`). ## Layout ```text sqlite-storage-spike/ src/ lib.rs # crate root, re-exports migrate.rs # Migrator + canonical migrations (v1..v3) repo.rs # traits, DTOs, LocalDatabaseRepository main.rs # sqlite-storage-cli driver tests/ storage.rs # 11 tests — migration + repo + persistence Cargo.toml ``` ## Canonical migrations | Version | Description | |---|---| | 1 | Initial `bookmarks` table + UNIQUE index on (server_host, identity_ref); `settings` key/value table. | | 2 | `ALTER TABLE bookmarks ADD COLUMN nickname TEXT`. | | 3 | `ALTER TABLE bookmarks ADD COLUMN last_connected_at INTEGER` + descending index. | Future migrations are appended only. The migrator refuses to start if the DB's `user_version` exceeds the highest known migration (downgrade guard). ## Reproduce Requires Rust stable (developed against 1.95). `rusqlite` is built with the `bundled` feature, so no system `libsqlite3` is needed. ```bash cargo test cargo run --bin sqlite-storage-cli ``` ## Scope boundaries - **Non-secret data only.** Any secret material (identity private keys, server passwords) belongs to `secure-storage-spike` / `SecretStorageRepository`. This is the SAD-067 separation. - **Single-process access.** Connection pooling, multi-process contention, and concurrent transactions are not exercised here. Production code will likely run on a single Rust core worker. - **No encryption at rest.** SQLCipher and similar are not in scope. Secrets must not land in this DB in the first place. - **No backup / restore.** - **No reverse migrations.** Forward-only is the documented policy; rollbacks require a fresh DB. - The migration-engine choice (`refinery`, `sqlx::migrate!`, etc.) remains open for the product crate. The PoC's ~50-line custom mechanism is intentional, to keep the audit surface explainable. ## Verification log See `VERIFICATION.md` in this directory.