## Phase 1 — Foundation: isolate SQLite-specific code behind generic trait ### Goal Create `trapfall-db` crate with a `Database` trait. Move all 60+ raw SQL queries from `store.rs` + `auth.rs` into `SqliteBackend` impl. Zero behavior change. ### Tasks - [ ] Create `crates/trapfall-db/` with `lib.rs`, `schema.rs`, `sqlite.rs` - [ ] Define `Database` trait with all store methods (projects, issues, events, auth, alerts, lifecycle) - [ ] Move entity structs (`Project`, `Issue`, `Event`, `User`, `Session`, `AlertRule`, `AuthAttempt`) to `schema.rs` - [ ] Implement `SqliteBackend` — copy existing SQLite queries from `store.rs` + `auth.rs` - [ ] Update `AppState` to hold `Box<dyn Database>` instead of `SqlitePool` - [ ] Update all consumers: `server.rs`, `digest.rs`, `alert.rs`, `retention.rs`, `ws.rs`, `metrics.rs`, `search.rs`, `mcp.rs` - [ ] Run full test suite — all tests pass, zero behavior change ### Acceptance Criteria - [ ] `trapfall-db` crate compiles and passes tests - [ ] `trapfalld` uses `Box<dyn Database>` everywhere - [ ] No `SqlitePool` reference outside `sqlite.rs` - [ ] All existing tests pass ### Effort ~1-2 days ### Depends on None — this is the foundation for all other phases.
Phase 1 — Foundation: isolate SQLite-specific code behind generic trait
Goal
Create
trapfall-dbcrate with aDatabasetrait. Move all 60+ raw SQL queries fromstore.rs+auth.rsintoSqliteBackendimpl. Zero behavior change.Tasks
crates/trapfall-db/withlib.rs,schema.rs,sqlite.rsDatabasetrait with all store methods (projects, issues, events, auth, alerts, lifecycle)Project,Issue,Event,User,Session,AlertRule,AuthAttempt) toschema.rsSqliteBackend— copy existing SQLite queries fromstore.rs+auth.rsAppStateto holdBox<dyn Database>instead ofSqlitePoolserver.rs,digest.rs,alert.rs,retention.rs,ws.rs,metrics.rs,search.rs,mcp.rsAcceptance Criteria
trapfall-dbcrate compiles and passes teststrapfalldusesBox<dyn Database>everywhereSqlitePoolreference outsidesqlite.rsEffort
~1-2 days
Depends on
None — this is the foundation for all other phases.