Target Skills: senior-backend (design) & code-reviewer (enforcement)
Version: 3.0 · 2026-08-24
Single-device, offline-first, client-only app holding real family financial data (~1.14M BDT scope). No server, no network I/O, no telemetry.
| Threat | Vector | Mitigation |
|---|---|---|
| Data loss/corruption | bad write, quota exhaustion, browser eviction, disk failure | OPFS primary storage, ring-buffer restore points, integrity digests, folder sync |
| Accidental destruction | user deletes tx/account/member | soft-delete + Recycle Bin + 30-day auto-purge |
| Boot hang / invisible dialogs | corrupt storage meets blocking UI | watchdog (15 s) + typed errors → visible recovery screen (BUG-7 lesson) |
| Privacy leak via git | exports/dumps committed | §5 guardrails (violated once historically — commit 68f3771) |
| Remote attack | nothing worth stealing remotely — no auth, cookies, tokens | N/A |
None by design. Single-admin local app; device unlock = access. No passwords/tokens/sessions/secrets exist. Do not add any without a PRD change. Cloud sync, if approved, mandates auth + RLS → this doc gets v4.
- Soft delete everywhere (
deleted_at). Hard delete only via Recycle Bin purge orpurgeExpiredItems(30). - Restore-before-destroy: flush writes main DB; snapshots rotate on cooldown with per-slot guards; a failed write prunes snapshots and retries before surfacing an error — never silently gives up.
- Balance invariants (TAD §4): running balance from full history; loan
outstandingre-synced on edit/delete. - Amount validation:
amount > 0at DB level; wizard warns non-blocking on insufficient balance. - No blocking dialogs anywhere on boot/mutation paths — all failures surface through the Database Error screen or store error state.
- All SQL parameterized (
$namedparams via prepared statements); string-concatenated SQL is rejected in review. - React escapes by default;
dangerouslySetInnerHTMLbanned. - File System Access API: user explicitly grants directory;
FolderSyncwrites only its own db files. - Digest caveat: on insecure origins (LAN http) integrity uses FNV fingerprint (
f:prefix) — detects accidental corruption but is NOT collision-resistant. Accepted because plain-http transport is already outside the threat model. Do not rely on it for tamper evidence.
This repo contains a real product with real financial data. Enforced by code-reviewer on every PR:
.gitignoreMUST coverUSER_DATA/,db_b64.txt, debug dump scripts,*.db, env files. (Hardened in Phase 10 after near-miss.)- Never commit: exported PDFs, base64/db dumps, screenshots with names/amounts, real spreadsheet seed data (fixtures use fake names).
- If sensitive data lands in history: treat as leaked — purge via filter-repo + coordinated force-push, then re-audit
.gitignore. mastermust build and pass tests on a fresh clone with zero user data required.- Docs must not contain real person names tied to financial figures (scrub on sight).
- No direct
sql.js/adapter imports outside infrastructure - No
(db as any)casts bypassing the port - Mutating ops await
flush(); no new silent-catch around persistence - Balance math uses full-history computation via shared utils
- Destructive flows reversible (soft-delete/restore point)
- Diff touches no data files;
.gitignoreupdated when new artifact types appear - Bug fixes update BUGS.md status + CHANGELOG in the same commit