Skip to main content

max / goingson

14.1 KB · 360 lines History Blame Raw
1 # GoingsOn Architecture
2
3 Email, calendar, tasks in one place. Project management for individuals and small teams.
4
5 A Rust-based productivity application built with Tauri 2 (Rust backend + Vanilla JS frontend), SQLite with sqlx 0.8, and a "Neobrute" design aesthetic. 2 crates: `core` (domain models), `db-sqlite` (repository).
6
7 ## High-Level Overview
8
9 ```
10 ┌─────────────────────────────────────────────────────────┐
11 │ User Interface │
12 │ ┌────────────────────────────────────────────────────┐ │
13 │ │ Tauri Desktop (Vanilla JS) │ │
14 │ └─────────────────────┬──────────────────────────────┘ │
15 │ │ │
16 │ ┌─────────────────────▼──────────────────────────────┐ │
17 │ │ Tauri Commands (src-tauri/) │ │
18 │ └─────────────────────┬──────────────────────────────┘ │
19 └────────────────────────┼─────────────────────────────────┘
20
21 ┌────────────────────────▼─────────────────────────────────┐
22 │ goingson-core │
23 │ ┌──────────┐ ┌──────────┐ ┌────────────┐ ┌────────────┐ │
24 │ │ Models │ │Repository│ │ Urgency │ │ Parser │ │
25 │ │ │ │ Traits │ │ Calculator │ │ (Quick-Add)│ │
26 │ └──────────┘ └────┬─────┘ └────────────┘ └────────────┘ │
27 └────────────────────┼─────────────────────────────────────┘
28
29 ┌──────▼───────────┐
30 │ goingson-db- │
31 │ sqlite │
32 │ (Desktop) │
33 └──────────────────┘
34 ```
35
36 ## Workspace Structure
37
38 ```
39 goingson/
40 ├── crates/
41 │ ├── core/ # Domain models, traits, business logic
42 │ └── db-sqlite/ # SQLite repository implementations
43 ├── src-tauri/ # Tauri desktop app (single-user)
44 └── migrations/
45 └── sqlite/ # SQLite schema migrations (33 files)
46 ```
47
48 ## Crate Dependencies
49
50 ```
51 goingson-desktop (src-tauri)
52 └── goingson-db-sqlite
53 └── goingson-core
54 ```
55
56 ## Core Crate (`crates/core/`)
57
58 The core crate defines domain models and repository traits, independent of persistence.
59
60 ### Modules
61
62 | Module | Purpose |
63 |--------|---------|
64 | `models/` | Domain types (17 model files) |
65 | `repository.rs` | Repository traits (data access contracts) |
66 | `urgency.rs` | TaskWarrior-inspired urgency calculation algorithm |
67 | `parser.rs` | Quick-add natural language parser |
68 | `recurrence.rs` | Task/event recurrence logic |
69 | `validation.rs` | Input validation trait |
70 | `constants.rs` | Named constants for thresholds, formats |
71 | `error.rs` | Unified CoreError type |
72
73 ### Key Types
74
75 ```rust
76 // Domain entities
77 Project, Task, Event, Email, EmailAccount, User
78 Contact, ContactEmail, ContactPhone, SocialHandle, ContactCustomField
79 SavedView, Annotation, Subtask, Milestone
80 WeeklyReview, BackupSettings
81
82 // Enums with display/parse support
83 ProjectType, ProjectStatus, TaskStatus, Priority, Recurrence
84 SortDirection, SortField, TaskSortColumn
85 ViewType, ViewFilters, BlockType
86 EmailAuthType, MilestoneStatus
87
88 // DTOs for creation/updates
89 NewProject, NewTask, NewEvent, NewEmail
90 UpdateProject, UpdateTask, UpdateEvent
91
92 // Newtype IDs
93 ProjectId, TaskId, EventId, EmailId, ContactId
94 EmailAccountId, AnnotationId, SubtaskId, SavedViewId
95 MilestoneId, CustomFieldId
96 ```
97
98 ### Repository Traits
99
100 ```rust
101 ProjectRepository, TaskRepository, EventRepository
102 EmailRepository, EmailAccountRepository, ContactRepository
103 SearchRepository, StatsRepository, SavedViewRepository
104 AnnotationRepository, SubtaskRepository, MilestoneRepository
105 WeeklyReviewRepository, BackupSettingsRepository
106 UserRepository
107 ```
108
109 ## Database Layer (`crates/db-sqlite/`)
110
111 SQLite persistence for the desktop app. Single-user, local storage. 50 migrations in `migrations/sqlite/`.
112
113 ```
114 src/
115 ├── lib.rs # SQLite pool initialization
116 ├── utils.rs # format_datetime, parse_uuid, email validation
117 └── repository/
118 ├── mod.rs # Re-exports all repositories
119 ├── project_repo.rs
120 ├── task_repo.rs
121 ├── event_repo.rs
122 ├── email_repo.rs
123 ├── email_account_repo.rs
124 ├── contact_repo.rs
125 ├── user_repo.rs
126 ├── search_repo.rs # FTS5 full-text search
127 ├── stats_repo.rs # Dashboard aggregations
128 ├── saved_view_repo.rs
129 ├── annotation_repo.rs
130 ├── subtask_repo.rs
131 ├── milestone_repo.rs
132 ├── weekly_review_repo.rs
133 └── backup_settings_repo.rs
134 ```
135
136 ## Tauri Desktop App (`src-tauri/`)
137
138 Single-user desktop application.
139
140 ```
141 src/
142 ├── main.rs # Tauri app setup, command registration
143 ├── state.rs # AppState with repository instances
144 ├── notifications.rs # Snooze watcher, native notifications
145 ├── email/ # IMAP/SMTP client
146 └── commands/
147 ├── mod.rs # Re-exports all commands
148 ├── error.rs # Error type definitions
149 ├── task.rs # Task CRUD, annotations, subtasks, snoozing, waiting
150 ├── project.rs # Project management
151 ├── event.rs # Calendar events
152 ├── email.rs # Email CRUD, threading, archive
153 ├── email_account.rs # Email account setup, sync interval
154 ├── email_sync.rs # IMAP/SMTP sync orchestration
155 ├── contact.rs # Contact CRUD, emails, phones, social handles
156 ├── search.rs # Full-text search across all entities
157 ├── stats.rs # Dashboard statistics
158 ├── day_planning.rs # Time blocking
159 ├── weekly_review.rs # Weekly review workflow
160 ├── saved_views.rs # Custom filter views
161 ├── milestone.rs # Milestone CRUD and reordering
162 ├── import.rs # Native CSV/TSV import (preview + execute)
163 ├── oauth.rs # OAuth2 flows (Fastmail, Google, Microsoft)
164 ├── export.rs # JSON, CSV, ICS export; backup/restore
165 ├── sync.rs # Cloud sync via SyncKit
166 ├── themes.rs # Theme list and color queries
167 └── window.rs # Window management, compose window
168 ```
169
170 ### Command Pattern
171
172 Tauri commands are async functions that:
173 1. Accept `State<Arc<AppState>>` for repository access
174 2. Deserialize input from frontend via `#[serde(rename_all = "camelCase")]`
175 3. Call repository methods
176 4. Serialize response types back to frontend
177
178 ```rust
179 #[tauri::command]
180 pub async fn create_task(
181 state: State<'_, Arc<AppState>>,
182 input: TaskInput,
183 ) -> Result<TaskResponse, String> {
184 state.tasks
185 .create(DESKTOP_USER_ID, new_task)
186 .await
187 .map(TaskResponse::from)
188 .map_err(|e| e.to_string())
189 }
190 ```
191
192 ## Frontend Architecture (Tauri Desktop)
193
194 The desktop frontend uses vanilla JavaScript organized under the `GoingsOn` global namespace. 66 source files.
195
196 ### Namespace Organization
197
198 ```
199 window.GoingsOn = {
200 api: { ... }, // Tauri IPC abstraction layer
201 state: { ... }, // Centralized state with pub/sub
202 ui: { ... }, // Modal, toast, form utilities
203 utils: { ... }, // HTML escaping, validation
204
205 // Domain modules (IIFE-wrapped)
206 projects: { ... },
207 tasks: { ... },
208 events: { ... },
209 emails: { ... },
210 contacts: { ... },
211
212 // Feature modules
213 savedViews: { ... },
214 snooze: { ... },
215 navigation: { ... },
216 settings: { ... },
217 app: { ... },
218
219 // Infrastructure
220 VirtualScroller, // Virtual scrolling for large lists
221 SelectionManager, // Multi-select with shift/ctrl
222 PaginationManager, // Page navigation
223 };
224 ```
225
226 ### Module Pattern
227
228 Each domain module is wrapped in an IIFE and exposes its public API through the namespace:
229
230 ```javascript
231 (function() {
232 'use strict';
233 // Private state and helpers
234 async function load() { ... }
235 function openNew() { ... }
236
237 // Public API
238 GoingsOn.myModule = { load, openNew };
239 })();
240 ```
241
242 ### Pre-computed Response Fields
243
244 Rust response types include pre-computed display values so JS never calculates dates, formatting, or derived state:
245
246 | Response Type | Pre-computed Fields |
247 |--------------|---------------------|
248 | TaskResponse | `dueFormatted`, `urgencyClass`, `isOverdue`, `isSnoozed`, `subtaskCount`, `subtaskCompleted`, `subtaskProgress` |
249 | EventResponse | `timeFormatted`, `dateFormatted`, `isPast`, `proximityClass`, `proximityLabel` |
250 | EmailResponse | `receivedFormatted` |
251 | EmailAccountResponse | `lastSyncFormatted` |
252
253 ### Centralized State
254
255 All shared data lives in `GoingsOn.state` with reactive pub/sub:
256
257 ```javascript
258 GoingsOn.state.set('tasks', updatedTasks); // Triggers subscribers
259 GoingsOn.state.subscribe('tasks', (newVal, oldVal) => { ... });
260 ```
261
262 ### File Organization
263
264 ```
265 src-tauri/frontend/
266 ├── css/
267 │ └── styles.css # Design system + all components
268 ├── fonts/
269 │ └── Reglo-Bold.woff2 # Display font
270 ├── js/
271 │ ├── goingson.js # Namespace root (window.GoingsOn)
272 │ ├── api.js # Tauri IPC abstraction
273 │ ├── state.js # Centralized state + pub/sub
274 │ ├── utils.js # Escaping, validation, debounce
275 │ ├── router.js # View routing
276 │ ├── app.js # App initialization, menu listeners
277 │ │
278 │ ├── components.js # Toast, confirm dialog
279 │ ├── components-modal.js # Modal system
280 │ ├── form-modal.js # Form modal (openFormModal)
281 │ ├── navigation.js # View switching, sidebar
282 │ ├── keyboard.js # Keyboard shortcuts
283 │ ├── selection-manager.js # Multi-select with shift/ctrl
284 │ ├── pagination-manager.js # Page navigation
285 │ ├── virtual-scroller.js # Virtual scrolling for large lists
286 │ ├── context-menus.js # Right-click context menus
287 │ ├── bulk-actions.js # Multi-select bulk operations
288 │ ├── touch.js # Touch event handling
289 │ ├── mobile.js # Mobile-specific behavior
290 │ │
291 │ ├── tasks.js # Task list, CRUD
292 │ ├── tasks-render.js # Task rendering
293 │ ├── tasks-kanban.js # Kanban board view
294 │ ├── projects.js # Project list, detail, CRUD
295 │ ├── projects-render.js # Project rendering
296 │ ├── events.js # Event list, CRUD
297 │ ├── emails.js # Email list, threading, CRUD
298 │ ├── email-accounts.js # Email account management
299 │ ├── contacts.js # Contact CRUD
300 │ ├── contacts-render.js # Contact rendering
301 │ │
302 │ ├── day-planning.js # Time-blocking day planner
303 │ ├── day-planning-render.js # Day plan rendering
304 │ ├── weekly-review.js # Weekly review workflow
305 │ ├── weekly-review-render.js # Weekly review rendering
306 │ ├── snooze.js # Snooze modal + actions
307 │ ├── settings.js # Settings, export
308 │ ├── settings-sync.js # Cloud sync settings
309 │ ├── themes.js # Theme switching
310 │ ├── export.js # Data export
311 │ ├── import.js # Data import from JSON
312 │ ├── seed-data.js # Demo data seeding
313 │ │
314 │ └── tests/
315 │ ├── test-runner.js # Test framework
316 │ └── run.js # Test execution
317 └── index.html # Entry point
318 ```
319
320 ## Data Flow
321
322 ```
323 Frontend (JS)
324 → invoke("command_name", { args })
325 → Tauri IPC
326 → commands/module.rs
327 → Repository trait method
328 → SQLite query
329 → Response (with pre-computed display fields) → Frontend
330 → JS renders pre-computed values directly to DOM
331 ```
332
333 ## Key Design Decisions
334
335 ### Clean Architecture
336 - Core domain models have no dependencies on persistence
337 - Repository traits define contracts, implementations are separate crates
338 - Easy to swap databases or add new ones
339
340 ### Vanilla Frontend
341 - No JavaScript framework: vanilla JS with IIFE modules
342 - All code under `GoingsOn` global namespace (no `window.*` exports)
343 - Centralized state via `GoingsOn.state` with pub/sub reactivity
344 - IPC via Tauri invoke
345 - Virtual scrolling for large lists (`GoingsOn.VirtualScroller`)
346 - Optimized for desktop-class performance
347
348 ### TaskWarrior-Inspired Features
349 - Urgency calculation algorithm
350 - Quick-add parser with natural language
351 - Annotations and recurring tasks
352
353 ## Testing Strategy
354
355 - 658 Rust tests + 48 JS tests
356 - Unit tests in core crate for business logic
357 - Integration tests for repository implementations
358 - Tauri command tests
359 - JS tests in `frontend/js/tests/`
360