NIIA-Watcher Database
Tracks file system events from the detached watcher daemon.Copy
╔═════════════════════════════════════════════════════════════════════╗
║ NIIA-WATCHER.DB OVERVIEW ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ ┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐║
║ │ file_events │ │ watch_paths │ │ worker_status │║
║ │ │ │ │ │ │║
║ │ - ts (timestamp) │ │ - path (UNIQUE) │ │ - pid (PK) │║
║ │ - event_type │ │ - depth │ │ - start_time │║
║ │ - abs_path │ │ - active │ │ - last_ping │║
║ │ - rel_path │ │ - ignore_patterns │ │ - queue_size │║
║ │ - basename │ │ - is_auto_added │ │ - watcher_count │║
║ │ - file_size │ │ │ │ - memory_usage │║
║ │ - is_directory │ │ │ │ - status │║
║ └───────────────────┘ └───────────────────┘ └───────────────────┘║
║ ║
║ ┌───────────────────┐ ┌───────────────────┐ ║
║ │ daily_stats │ │ user_exclusions │ ║
║ │ │ │ │ ║
║ │ - date (PK) │ │ - exclusion_type │ ║
║ │ - total_events │ │ - pattern │ ║
║ │ - create_count │ │ - created_at │ ║
║ │ - change_count │ │ │ ║
║ │ - unlink_count │ │ │ ║
║ │ - rename_count │ │ │ ║
║ └───────────────────┘ └───────────────────┘ ║
║ ║
║ niia-watcher.db ║
╚═════════════════════════════════════════════════════════════════════╝
Architecture
The watcher runs as a detached sidecar process with direct database access.Copy
╔═════════════════════════════════════════════════════════════════════╗
║ DAEMON ARCHITECTURE ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ Tauri App Start ║
║ │ ║
║ │ spawn_daemon() ║
║ ▼ ║
║ ┌──────────────────────────────────────────────────────────────┐ ║
║ │ File Watcher Daemon (Detached Sidecar Process) │ ║
║ │ │ ║
║ │ ┌────────────────────────┐ ┌────────────────────────┐ │ ║
║ │ │ Control Socket │ │ Database Writer │ │ ║
║ │ │ /tmp/niia-watcher.sock│ │ rusqlite WAL mode │ │ ║
║ │ └────────────────────────┘ └────────────────────────┘ │ ║
║ │ │ │ │ ║
║ │ │ │ │ ║
║ │ ┌────────────────────────┐ ┌────────────────────────┐ │ ║
║ │ │ File Watcher Pool │ │ Heartbeat Timer │ │ ║
║ │ │ Rust notify crate │ │ Every 10 seconds │ │ ║
║ │ │ (FSEvents/inotify) │ │ UPDATE worker_status │ │ ║
║ │ └────────────────────────┘ └────────────────────────┘ │ ║
║ │ │ ║
║ └──────────────────────────────────────────────────────────────┘ ║
║ ║
║ KEY BENEFIT: Daemon survives app crash ║
║ ║
║ Tauri App Crash ║
║ │ ║
║ ✕── Daemon continues running (detached) ║
║ │ File events still captured ║
║ │ ║
║ Tauri App Restart ║
║ │ ║
║ │ Check worker_status.pid ║
║ │ Process still alive? ──▶ Reuse existing daemon ║
║ │ Process dead? ──▶ Spawn new daemon ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Write/Read Separation
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ WRITE/READ ARCHITECTURE ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ WRITE (Daemon Only - NO IPC) ║
║ ┌───────────────────────────────────────────────────────────────┐ ║
║ │ │ ║
║ │ File Watcher Daemon │ ║
║ │ │ │ ║
║ │ │ OS File System Event (FSEvents/inotify) │ ║
║ │ ▼ │ ║
║ │ Event Handler │ ║
║ │ │ │ ║
║ │ │ Debounce + Filter │ ║
║ │ ▼ │ ║
║ │ Direct rusqlite INSERT │ ║
║ │ │ │ ║
║ │ ▼ │ ║
║ │ file_events table │ ║
║ │ │ ║
║ │ BENEFIT: No IPC overhead = Maximum performance │ ║
║ └───────────────────────────────────────────────────────────────┘ ║
║ ║
║ READ (Tauri Commands ──▶ Frontend) ║
║ ┌───────────────────────────────────────────────────────────────┐ ║
║ │ │ ║
║ │ Frontend │ ║
║ │ │ │ ║
║ │ │ invoke("query_niia_watcher") │ ║
║ │ ▼ │ ║
║ │ Tauri Command ──▶ Rust Module │ ║
║ │ │ │ ║
║ │ │ SELECT FROM file_events WHERE ts > ? │ ║
║ │ ▼ │ ║
║ │ JSON Response ──▶ UI Update │ ║
║ │ │ ║
║ └───────────────────────────────────────────────────────────────┘ ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
File Event Types
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ FILE EVENT TYPES ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ EVENT │ DESCRIPTION ║
║ ════════════│══════════════════════════════════════════════════════║
║ Create │ New file or directory created ║
║ Change │ File content modified ║
║ Unlink │ File or directory deleted ║
║ Rename │ File renamed (old_path populated) ║
║ ║
║ RENAME EVENT HANDLING ║
║ ┌───────────────────────────────────────────────────────────────┐ ║
║ │ Rename events generate TWO records: │ ║
║ │ │ ║
║ │ Record 1: Unlink event │ ║
║ │ - abs_path = old path │ ║
║ │ - correlation_id = X │ ║
║ │ │ ║
║ │ Record 2: Create event │ ║
║ │ - abs_path = new path │ ║
║ │ - correlation_id = X │ ║
║ │ │ ║
║ │ Frontend can GROUP BY correlation_id for atomic display │ ║
║ └───────────────────────────────────────────────────────────────┘ ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Cross-Database Relationship
The watcher database helps resolve truncated paths in terminal output.Copy
╔═════════════════════════════════════════════════════════════════════╗
║ CROSS-DB PATH RESOLUTION ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ atomic-term.db niia-watcher.db ║
║ ┌───────────────────────────┐ ┌───────────────────────────┐║
║ │ │ │ │║
║ │ parsed_activities │ QUERY │ file_events │║
║ │ ┌─────────────────────┐ │────────▶│ ┌─────────────────────┐ │║
║ │ │ target (truncated) │ │ │ │ basename │ │║
║ │ │ timestamp │ │ │ │ abs_path │ │║
║ │ └─────────────────────┘ │ │ │ ts │ │║
║ │ │ │ │ └─────────────────────┘ │║
║ │ │ │ │ │║
║ │ UPDATE │ │ └───────────────────────────┘║
║ │ ▼ │ ║
║ │ ┌─────────────────────┐ │ ║
║ │ │ path (resolved) │ │ ║
║ │ │ rel_path │ │ ║
║ │ └─────────────────────┘ │ ║
║ │ │ ║
║ └───────────────────────────┘ ║
║ ║
║ Auto-fix query: ║
║ ┌───────────────────────────────────────────────────────────────┐ ║
║ │ SELECT abs_path FROM file_events │ ║
║ │ WHERE basename = ? │ ║
║ │ AND ts BETWEEN (activity_ts - window) AND (activity_ts + w) │ ║
║ └───────────────────────────────────────────────────────────────┘ ║
║ ║
║ PURPOSE: Terminal shows truncated paths. Watcher provides full ║
║ paths based on filename + timestamp correlation. ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Worker Status Monitoring
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ WORKER STATUS TABLE ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ Column │ Type │ Description ║
║ ══════════════│══════════│═════════════════════════════════════════║
║ pid │ INTEGER │ Process ID (Primary Key) ║
║ start_time │ INTEGER │ When daemon started ║
║ last_ping │ INTEGER │ Last heartbeat timestamp ║
║ queue_size │ INTEGER │ Pending events in queue ║
║ watcher_count │ INTEGER │ Number of active file watchers ║
║ memory_usage │ INTEGER │ Memory consumption in bytes ║
║ status │ TEXT │ running/paused/error ║
║ error_message │ TEXT │ Last error (if any) ║
║ ║
║ HEARTBEAT MECHANISM ║
║ ┌───────────────────────────────────────────────────────────────┐ ║
║ │ Daemon updates worker_status every 10 seconds │ ║
║ │ │ ║
║ │ App checks: last_ping > (NOW - 30 seconds)? │ ║
║ │ YES ──▶ Daemon is alive, reuse │ ║
║ │ NO ──▶ Daemon is dead, spawn new │ ║
║ └───────────────────────────────────────────────────────────────┘ ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Design Principles Applied
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ DESIGN PRINCIPLES ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ SIMPLICITY (SMPC) ║
║ ┌───────────────────────────────────────────────────────────────┐ ║
║ │ [x] Daemon writes directly via rusqlite (no IPC overhead) │ ║
║ │ [x] 5 tables with clear, single responsibilities │ ║
║ │ [x] WAL mode for concurrent read/write │ ║
║ │ [x] Simple event types (Create/Change/Unlink/Rename) │ ║
║ └───────────────────────────────────────────────────────────────┘ ║
║ ║
║ ORDER FROM CHAOS (OFAC) ║
║ ┌───────────────────────────────────────────────────────────────┐ ║
║ │ [x] Detached daemon survives app crash │ ║
║ │ [x] Control socket for runtime commands │ ║
║ │ [x] Auto-added default watch paths on startup │ ║
║ │ [x] Heartbeat ping for daemon health monitoring │ ║
║ │ [x] user_exclusions for user-customizable filtering │ ║
║ └───────────────────────────────────────────────────────────────┘ ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Quick Reference
| Aspect | Value |
|---|---|
| Location | ~/Library/Application Support/monolex/protocols/niia/database/niia-watcher.db |
| Primary Owner | File Watcher Daemon (sidecar) |
| Write Method | Direct rusqlite (no IPC) |
| Read By | Frontend watcher tab, Auto-fix module |
| Survives Crash | Yes (detached process) |