Comprehensive architecture documentation covering: - docs/architecture/README.md: Full C4 model diagrams (system context, container, component), data flow sequences, security architecture, AI provider class diagram, CI/CD pipeline, and deployment diagrams. All diagrams use Mermaid for version-controlled diagram-as-code. - docs/architecture/adrs/ADR-001: Tauri vs Electron decision rationale - docs/architecture/adrs/ADR-002: SQLCipher encryption choices and cipher_page_size=16384 rationale for Apple Silicon - docs/architecture/adrs/ADR-003: Provider trait + factory pattern - docs/architecture/adrs/ADR-004: Regex + Aho-Corasick PII detection - docs/architecture/adrs/ADR-005: Auto-generate encryption keys at runtime (documents the fix from PR #24) - docs/architecture/adrs/ADR-006: Zustand state management rationale - docs/wiki/Architecture.md: Updated module table (14 migrations, not 10), corrected integrations description, updated startup sequence to reflect key auto-generation, added links to new ADR docs. - README.md: Fixed stale database paths (tftsr → trcaa) and updated env var descriptions to reflect auto-generation behavior. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2.8 KiB
ADR-002: SQLCipher for Encrypted Storage
Status: Accepted Date: 2025-Q3 Deciders: sarman
Context
All incident data (titles, descriptions, log contents, AI conversations, resolution steps, RCA documents) must be stored locally and at rest must be encrypted. The application cannot rely on OS-level full-disk encryption being enabled.
Requirements:
- AES-256 encryption of the full database file
- Key derivation suitable for per-installation keys (not user passwords)
- No plaintext data accessible if the
.dbfile is copied off-machine - Rust-compatible SQLite bindings
Decision
Use SQLCipher via rusqlite with the bundled-sqlcipher-vendored-openssl feature flag.
Rationale
Alternatives considered:
| Option | Pros | Cons |
|---|---|---|
| SQLCipher (chosen) | Transparent full-DB encryption, AES-256, PBKDF2 key derivation, vendored so no system dep | Larger binary; not standard SQLite |
| Plain SQLite | Simple, well-known | No encryption — ruled out |
| SQLite + file-level encryption | Flexible | No atomicity; complex implementation |
| LevelDB / RocksDB | Fast, encrypted options exist | No SQL, harder migration |
sled (Rust-native) |
Modern, async-friendly | No SQL, immature for complex schemas |
SQLCipher specifics chosen:
PRAGMA cipher_page_size = 16384; -- Matches 16KB kernel page (Apple Silicon)
PRAGMA kdf_iter = 256000; -- 256k PBKDF2 iterations
PRAGMA cipher_hmac_algorithm = HMAC_SHA512;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA512;
The cipher_page_size = 16384 is specifically tuned for Apple Silicon (M-series) which uses 16KB kernel pages — using 4096 (SQLCipher default) causes page boundary issues.
Key Management
Per ADR-005, encryption keys are auto-generated at runtime:
- Release builds: Random 256-bit key generated at first launch, stored in
.dbkey(mode 0600) - Debug builds: Hardcoded dev key (
dev-key-change-in-prod) - Override:
TFTSR_DB_KEYenvironment variable
Consequences
Positive:
- Full database encryption transparent to all SQL queries
- Vendored OpenSSL means no system library dependency (important for portable AppImage/DMG)
- SHA-512 HMAC provides authenticated encryption (tampering detected)
Negative:
bundled-sqlcipher-vendored-opensslsignificantly increases compile time and binary size- Cannot use standard SQLite tooling to inspect database files (must use sqlcipher CLI)
cipher_page_sizemismatch between debug/release would corrupt databases — mitigated by auto-migration (ADR-005)
Migration Handling:
If a plain SQLite database is detected in a release build (e.g., developer switched from debug), migrate_plain_to_encrypted() automatically migrates using ATTACH DATABASE + sqlcipher_export. A .db.plain-backup file is created before migration.