Click Tracker is an Electron-based desktop application that monitors and tracks user productivity by recording mouse clicks, keyboard activity, and time duration across multiple projects and tasks.
┌─────────────────────────────────────────────────────────────────┐
│ ELECTRON MAIN PROCESS │
│ (src/main.js) │
│ │
│ • Window Management │
│ • uIOhook Event Handlers (clicks & keystrokes) │
│ • IPC Request Handlers │
│ • Timer Service Management │
└──────────────────────────┬──────────────────────────────────────┘
│
IPC Bridge (preload.js)
│
┌──────────────────────────┴──────────────────────────────────────┐
│ RENDERER PROCESS (React) │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ App.js (Root Component) │ │
│ │ • Routes projects to selected project │ │
│ │ • Passes handlers to children │ │
│ └────────────────┬─────────────────────────────┬─────────┘ │
│ │ │ │
│ ┌────────────────▼──────┐ ┌──────────────▼──────────┐ │
│ │ ProjectList.js │ │ TaskTracker.js │ │
│ │ • List all projects │ │ • Task table display │ │
│ │ • Add project │ │ • Start/Stop tracking │ │
│ │ • Delete project │ │ • Real-time stats │ │
│ │ • Select project │ │ • Add/Delete tasks │ │
│ └───────────────────────┘ └────────────────────────┘ │
│ │
│ Styles: │
│ • App.css (main layout, header, sidebar, content area) │
│ • ProjectList.css (project items, modals) │
│ • TaskTracker.css (task table, buttons, forms) │
│ • index.css (global styles, scrollbars, fonts) │
└───────────────────────┬──────────────────────────────────────┘
│
IPC API Calls
│
┌───────────────────────┴──────────────────────────────────────┐
│ SERVICES (Node.js Backend) │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ database.js - SQLite Operations │ │
│ │ • CRUD projects and tasks │ │
│ │ • Record activity events │ │
│ │ • Calculate statistics (clicks, keys, duration) │ │
│ │ • Cascading deletes with foreign keys │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ timerService.js - Timing Management │ │
│ │ • Start/Stop/Pause timer │ │
│ │ • Emit tick events every second │ │
│ │ • Calculate elapsed time │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ mouseTracker.js - Mouse Event Listener │ │
│ │ • Attached to uIOhook click events │ │
│ │ • Tracks click coordinates and count │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ keyboardTracker.js - Keyboard Event Listener │ │
│ │ • Attached to uIOhook keydown events │ │
│ │ • Tracks keystroke count │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ activityDetector.js - Idle Detection │ │
│ │ • Monitors activity status │ │
│ │ • Calculates idle time │ │
│ └──────────────────────────────────────────────────────┘ │
└───────────────────────┬──────────────────────────────────────┘
│
uIOhook-napi
│
┌───────────────────────┴──────────────────────────────────────┐
│ NATIVE SYSTEM HOOKS (uIOhook) │
│ │
│ • System-wide click detection (mouse events) │
│ • System-wide keyboard detection (key events) │
│ • Works globally even when app is not focused │
└───────────────────────┬──────────────────────────────────────┘
│
┌───────────────────────┴──────────────────────────────────────┐
│ DATABASE (SQLite) │
│ Location: %APPDATA%/click-tracker/tracker.db │
│ │
│ Tables: │
│ • projects (id, name, description, status, created_at) │
│ • tasks (id, project_id, name, duration, timestamps) │
│ • activity_events (id, task_id, event_type, coords, key) │
└──────────────────────────────────────────────────────────────┘
User clicks START → TaskTracker.handleStartTask()
→ window.api.startTracking(taskId)
→ main.js 'start-tracking' handler
→ Start uIOhook listeners for THIS task
→ Start timerService
→ Send 'timer-tick' events to renderer
User clicks mouse/presses key
→ uIOhook detects event (global hook)
→ main.js handler fires
→ database.recordEvent(taskId, eventType, ...)
→ mainWindow.webContents.send('click-event'|'key-event')
→ React state updates live counter
→ Database accumulates event count
User clicks STOP → TaskTracker.handleStopTask()
→ window.api.stopTask(activeTaskId)
→ main.js 'stop-task' handler
→ Stop timerService
→ database.stopTask(taskId, durationSeconds)
→ Remove all uIOhook listeners
→ Clear active task state
User starts task OR navigates to project
→ TaskTracker.loadTasks()
→ For each task: window.api.getTaskStats(taskId)
→ database.getTaskStats(taskId)
→ Query: COUNT events by type WHERE task_id = ?
→ Return: { clicks: X, keystrokes: Y }
→ React displays stats in table
Invocations (Request-Response):
getProjects()- Fetch all projectscreateProject(name, description)- Create new projectdeleteProject(projectId)- Delete project with cascading deletesaddTask(projectId, taskName)- Add task without trackingstartTracking(taskId)- Start tracking existing taskstopTask(taskId)- Stop current trackingdeleteTask(taskId)- Delete task and eventsgetProjectTasks(projectId)- Get tasks for projectgetTaskStats(taskId)- Get click/keystroke countsgetTaskEvents(taskId)- Get all events for task
Events (Async Notifications):
timer-tick- Timer update (00:00:00 format)click-event- Mouse click detectedkey-event- Key press detected
| Component | Technology | Purpose |
|---|---|---|
| Desktop Framework | Electron 40.3.0 | Cross-platform desktop app |
| UI Framework | React 19.2.4 | Component-based UI with hooks |
| Bundler | Webpack 5.105.1 | Module bundling & dev server |
| Database | SQLite3 5.1.7 | Local data persistence |
| System Hooks | uiohook-napi 1.5.4 | Global keyboard/mouse detection |
| Styling | CSS3 | Gradient, animations, dark theme |
src/
├── App.js # Root React component
├── index.js # Entry point
├── main.js # Electron main process
├── preload.js # IPC bridge (secure context)
├── components/
│ ├── ProjectList.js # Project sidebar
│ └── TaskTracker.js # Task tracking UI
├── services/
│ ├── database.js # SQLite operations
│ ├── timerService.js # Timing logic
│ ├── mouseTracker.js # Click listener
│ ├── keyboardTracker.js # Key listener
│ └── activityDetector.js # Idle detection
└── styles/
├── index.css # Global styles
├── App.css # App layout
├── ProjectList.css # Projects styling
└── TaskTracker.css # Tasks styling
Renderer State (React):
tasks- Array of task objectstaskStats- Statistics map by task IDactiveTaskId- Currently tracking tasktimer- Formatted time string (HH:MM:SS)liveStats- Current click/key countersselectedProject- Active project object
Main Process State:
currentTaskId- Active task in trackingclickHandler- Current click event listenerkeyHandler- Current keyboard event listener
Database State:
- Persistent SQLite database with 3 tables
- Cascading foreign key relationships
- Accumulated duration across sessions
START TASK
↓
Clear old listeners (removeListener for click/keydown)
↓
Define NEW click & keydown handlers for CURRENT task
↓
Register handlers: uIOhook.on('click', handler)
uIOhook.on('keydown', handler)
↓
uIOhook.start()
↓
Track events [User actively working]
↓
STOP TASK
↓
removeListener for both handlers
↓
uIOhook.stop()
↓
Database updated with accumulated stats
- Context Isolation - Renderer cannot access Node.js directly
- Preload Bridge - Controlled IPC API exposure
- No nodeIntegration - Renderer process sandboxed
- Validation - All IPC messages validated on main process