|
| 1 | +# Database Schema |
| 2 | + |
| 3 | +**SPEC-DB-001** |
| 4 | + |
| 5 | +Three tables store AI summaries, tag definitions, and tag assignments. |
| 6 | + |
| 7 | +```sql |
| 8 | +CREATE TABLE IF NOT EXISTS commands ( |
| 9 | + command_id TEXT PRIMARY KEY, |
| 10 | + content_hash TEXT NOT NULL, |
| 11 | + summary TEXT NOT NULL, |
| 12 | + security_warning TEXT, |
| 13 | + last_updated TEXT NOT NULL |
| 14 | +); |
| 15 | + |
| 16 | +CREATE TABLE IF NOT EXISTS tags ( |
| 17 | + tag_id TEXT PRIMARY KEY, |
| 18 | + tag_name TEXT NOT NULL UNIQUE, |
| 19 | + description TEXT |
| 20 | +); |
| 21 | + |
| 22 | +CREATE TABLE IF NOT EXISTS command_tags ( |
| 23 | + command_id TEXT NOT NULL, |
| 24 | + tag_id TEXT NOT NULL, |
| 25 | + display_order INTEGER NOT NULL DEFAULT 0, |
| 26 | + PRIMARY KEY (command_id, tag_id), |
| 27 | + FOREIGN KEY (command_id) REFERENCES commands(command_id) ON DELETE CASCADE, |
| 28 | + FOREIGN KEY (tag_id) REFERENCES tags(tag_id) ON DELETE CASCADE |
| 29 | +); |
| 30 | +``` |
| 31 | + |
| 32 | +CRITICAL: No backwards compatibility. If the database structure is wrong, the extension blows it away and recreates it from scratch. |
| 33 | + |
| 34 | +## Implementation |
| 35 | + |
| 36 | +**SPEC-DB-010** |
| 37 | + |
| 38 | +- **Engine**: SQLite via `node-sqlite3-wasm` |
| 39 | +- **Location**: `{workspaceFolder}/.commandtree/commandtree.sqlite3` |
| 40 | +- **Runtime**: Pure WASM, no native compilation (~1.3 MB) |
| 41 | +- **CRITICAL**: `PRAGMA foreign_keys = ON;` MUST be executed on EVERY database connection |
| 42 | +- **Orphan Prevention**: `ensureCommandExists()` inserts placeholder command rows before adding tags |
| 43 | +- **API**: Synchronous, no async overhead for reads |
| 44 | + |
| 45 | +### Test Coverage |
| 46 | +- [db.e2e.test.ts](../src/test/e2e/db.e2e.test.ts): "initSchema is idempotent — calling twice succeeds" |
| 47 | + |
| 48 | +## Commands Table |
| 49 | + |
| 50 | +**SPEC-DB-020** |
| 51 | + |
| 52 | +- **`command_id`**: `{type}:{filePath}:{name}` (PRIMARY KEY) |
| 53 | +- **`content_hash`**: SHA-256 hash for change detection (NOT NULL) |
| 54 | +- **`summary`**: AI-generated description, 1-3 sentences (NOT NULL) |
| 55 | +- **`security_warning`**: AI-detected security risk (nullable) |
| 56 | +- **`last_updated`**: ISO 8601 timestamp (NOT NULL) |
| 57 | + |
| 58 | +### Test Coverage |
| 59 | +- [db.e2e.test.ts](../src/test/e2e/db.e2e.test.ts): "inserts new command", "upsert updates content hash on conflict", "returns undefined for non-existent command" |
| 60 | + |
| 61 | +## Tags Table |
| 62 | + |
| 63 | +**SPEC-DB-030** |
| 64 | + |
| 65 | +- **`tag_id`**: UUID primary key |
| 66 | +- **`tag_name`**: Tag identifier, UNIQUE (NOT NULL) |
| 67 | +- **`description`**: Optional description (nullable) |
| 68 | + |
| 69 | +### Test Coverage |
| 70 | +- [db.e2e.test.ts](../src/test/e2e/db.e2e.test.ts): "addTagToCommand creates tag and junction record", "getAllTagNames returns all distinct tags" |
| 71 | + |
| 72 | +## Command Tags Junction Table |
| 73 | + |
| 74 | +**SPEC-DB-040** |
| 75 | + |
| 76 | +- **`command_id`**: FK to `commands.command_id` with CASCADE DELETE |
| 77 | +- **`tag_id`**: FK to `tags.tag_id` with CASCADE DELETE |
| 78 | +- **`display_order`**: Integer for ordering (default 0) |
| 79 | +- **Primary Key**: `(command_id, tag_id)` |
| 80 | + |
| 81 | +### Test Coverage |
| 82 | +- [db.e2e.test.ts](../src/test/e2e/db.e2e.test.ts): "addTagToCommand creates tag and junction record", "addTagToCommand is idempotent", "removeTagFromCommand removes junction record", "removeTagFromCommand succeeds for non-existent tag" |
| 83 | + |
| 84 | +## Content Hashing |
| 85 | + |
| 86 | +**SPEC-DB-050** |
| 87 | + |
| 88 | +Content hashing is used for change detection to avoid re-processing unchanged commands. |
| 89 | + |
| 90 | +### Test Coverage |
| 91 | +- [db.e2e.test.ts](../src/test/e2e/db.e2e.test.ts): "returns consistent hash for same input", "returns different hash for different input", "returns 16-char hex string" |
0 commit comments