| 1 |
1 |
|
# GoingsOn Database Schema
|
| 2 |
2 |
|
|
| 3 |
|
- |
SQLite schema reference. 50 migrations. Migrations live in `migrations/sqlite/` and auto-run on first launch.
|
|
3 |
+ |
SQLite schema reference. Migrations live in `migrations/sqlite/` and auto-run on first launch.
|
| 4 |
4 |
|
|
| 5 |
5 |
|
## Domain Map
|
| 6 |
6 |
|
|
| 24 |
24 |
|
| Column | Type | Notes |
|
| 25 |
25 |
|
|--------|------|-------|
|
| 26 |
26 |
|
| `id` | TEXT PK | |
|
| 27 |
|
- |
| `user_id` | TEXT FK | -> users (CASCADE). Added migration 002 |
|
|
27 |
+ |
| `user_id` | TEXT FK | -> users (CASCADE) |
|
| 28 |
28 |
|
| `name` | TEXT | NOT NULL |
|
| 29 |
29 |
|
| `description` | TEXT | Default '' |
|
| 30 |
30 |
|
| `project_type` | TEXT | Default 'Other' |
|
| 39 |
39 |
|
| Column | Type | Notes |
|
| 40 |
40 |
|
|--------|------|-------|
|
| 41 |
41 |
|
| `id` | TEXT PK | |
|
| 42 |
|
- |
| `user_id` | TEXT FK | -> users (CASCADE). Migration 002 |
|
|
42 |
+ |
| `user_id` | TEXT FK | -> users (CASCADE) |
|
| 43 |
43 |
|
| `project_id` | TEXT FK | -> projects (SET NULL) |
|
| 44 |
44 |
|
| `description` | TEXT | NOT NULL |
|
| 45 |
45 |
|
| `status` | TEXT | Default 'Pending' |
|
| 48 |
48 |
|
| `tags` | TEXT | JSON array string, default '[]' |
|
| 49 |
49 |
|
| `urgency` | REAL | Computed score, default 0.0 |
|
| 50 |
50 |
|
| `recurrence` | TEXT | Default 'None' |
|
| 51 |
|
- |
| `recurrence_parent_id` | TEXT FK | -> tasks (SET NULL). Migration 003 |
|
| 52 |
|
- |
| `source_email_id` | TEXT FK | -> emails (SET NULL). Migration 009 |
|
| 53 |
|
- |
| `snoozed_until` | TEXT | Migration 010 |
|
| 54 |
|
- |
| `waiting_for_response` | INTEGER | Boolean, default 0. Migration 012 |
|
| 55 |
|
- |
| `waiting_since` | TEXT | Migration 012 |
|
| 56 |
|
- |
| `expected_response_date` | TEXT | Migration 012 |
|
| 57 |
|
- |
| `scheduled_start` | TEXT | Migration 013 |
|
| 58 |
|
- |
| `scheduled_duration` | INTEGER | Minutes. Migration 013 |
|
| 59 |
|
- |
| `is_focus` | INTEGER | Boolean, default 0. Migration 018 |
|
| 60 |
|
- |
| `focus_set_at` | TEXT | Migration 018 |
|
| 61 |
|
- |
| `contact_id` | TEXT FK | -> contacts (SET NULL). Migration 025 |
|
| 62 |
|
- |
| `milestone_id` | TEXT FK | -> milestones (SET NULL). Migration 028 |
|
| 63 |
|
- |
| `completed_at` | TEXT | Backfilled from created_at. Migration 031 |
|
|
51 |
+ |
| `recurrence_parent_id` | TEXT FK | -> tasks (SET NULL) |
|
|
52 |
+ |
| `source_email_id` | TEXT FK | -> emails (SET NULL) |
|
|
53 |
+ |
| `snoozed_until` | TEXT | |
|
|
54 |
+ |
| `waiting_for_response` | INTEGER | Boolean, default 0 |
|
|
55 |
+ |
| `waiting_since` | TEXT | |
|
|
56 |
+ |
| `expected_response_date` | TEXT | |
|
|
57 |
+ |
| `scheduled_start` | TEXT | |
|
|
58 |
+ |
| `scheduled_duration` | INTEGER | Minutes |
|
|
59 |
+ |
| `is_focus` | INTEGER | Boolean, default 0 |
|
|
60 |
+ |
| `focus_set_at` | TEXT | |
|
|
61 |
+ |
| `contact_id` | TEXT FK | -> contacts (SET NULL) |
|
|
62 |
+ |
| `milestone_id` | TEXT FK | -> milestones (SET NULL) |
|
|
63 |
+ |
| `completed_at` | TEXT | |
|
| 64 |
64 |
|
| `created_at` | TEXT | `datetime('now')` |
|
| 65 |
65 |
|
|
| 66 |
66 |
|
Indexes: `project_id`, `status`, `priority`, `due`, `urgency DESC`, `user_id`, `recurrence_parent_id`, `source_email_id`, `snoozed_until`, `scheduled_start`, `contact_id`. Partial indexes: `waiting_for_response WHERE = 1`, `is_focus WHERE = 1`, `completed_at WHERE NOT NULL`.
|
| 75 |
75 |
|
| `text` | TEXT | NOT NULL |
|
| 76 |
76 |
|
| `is_completed` | INTEGER | Boolean, default 0 |
|
| 77 |
77 |
|
| `position` | INTEGER | Sort order, default 0 |
|
| 78 |
|
- |
| `linked_task_id` | TEXT FK | -> tasks (SET NULL). Migration 022 |
|
|
78 |
+ |
| `linked_task_id` | TEXT FK | -> tasks (SET NULL) |
|
| 79 |
79 |
|
| `created_at` | TEXT | `datetime('now')` |
|
| 80 |
80 |
|
|
| 81 |
81 |
|
Indexes: `task_id`, `linked_task_id`.
|
| 93 |
93 |
|
Index: `task_id`.
|
| 94 |
94 |
|
|
| 95 |
95 |
|
### milestones
|
| 96 |
|
- |
Scope boundaries within a project. "When these tasks are done, ship it." Migration 028.
|
|
96 |
+ |
Scope boundaries within a project. "When these tasks are done, ship it."
|
| 97 |
97 |
|
|
| 98 |
98 |
|
| Column | Type | Notes |
|
| 99 |
99 |
|
|--------|------|-------|
|
| 114 |
114 |
|
## Email
|
| 115 |
115 |
|
|
| 116 |
116 |
|
### email_accounts
|
| 117 |
|
- |
IMAP/SMTP and OAuth2/JMAP account configuration. Credentials excluded from sync (migration 033).
|
|
117 |
+ |
IMAP/SMTP and OAuth2/JMAP account configuration. Credentials excluded from sync.
|
| 118 |
118 |
|
|
| 119 |
119 |
|
| Column | Type | Notes |
|
| 120 |
120 |
|
|--------|------|-------|
|
| 129 |
129 |
|
| `username` | TEXT | |
|
| 130 |
130 |
|
| `password` | TEXT | IMAP/SMTP credential |
|
| 131 |
131 |
|
| `use_tls` | INTEGER | Boolean, default 1 |
|
| 132 |
|
- |
| `auth_type` | TEXT | 'password' or 'oauth2_fastmail'. Migration 017 |
|
| 133 |
|
- |
| `oauth2_access_token` | TEXT | Migration 017 |
|
| 134 |
|
- |
| `oauth2_refresh_token` | TEXT | Migration 017 |
|
| 135 |
|
- |
| `oauth2_token_expires_at` | TEXT | Migration 017 |
|
| 136 |
|
- |
| `jmap_session_url` | TEXT | Fastmail JMAP. Migration 017 |
|
| 137 |
|
- |
| `jmap_account_id` | TEXT | Migration 017 |
|
| 138 |
|
- |
| `archive_folder_name` | TEXT | Default 'Archive'. Migration 006 |
|
| 139 |
|
- |
| `sync_interval_minutes` | INTEGER | Default 15, NULL = disabled. Migration 021 |
|
|
132 |
+ |
| `auth_type` | TEXT | 'password' or 'oauth2_fastmail' |
|
|
133 |
+ |
| `oauth2_access_token` | TEXT | |
|
|
134 |
+ |
| `oauth2_refresh_token` | TEXT | |
|
|
135 |
+ |
| `oauth2_token_expires_at` | TEXT | |
|
|
136 |
+ |
| `jmap_session_url` | TEXT | Fastmail JMAP |
|
|
137 |
+ |
| `jmap_account_id` | TEXT | |
|
|
138 |
+ |
| `archive_folder_name` | TEXT | Default 'Archive' |
|
|
139 |
+ |
| `sync_interval_minutes` | INTEGER | Default 15, NULL = disabled |
|
| 140 |
140 |
|
| `last_sync_at` | TEXT | Device-local, excluded from sync |
|
| 141 |
141 |
|
| `created_at` | TEXT | `datetime('now')` |
|
| 142 |
142 |
|
|
| 148 |
148 |
|
| Column | Type | Notes |
|
| 149 |
149 |
|
|--------|------|-------|
|
| 150 |
150 |
|
| `id` | TEXT PK | |
|
| 151 |
|
- |
| `user_id` | TEXT FK | -> users (CASCADE). Migration 002 |
|
|
151 |
+ |
| `user_id` | TEXT FK | -> users (CASCADE) |
|
| 152 |
152 |
|
| `project_id` | TEXT FK | -> projects (SET NULL) |
|
| 153 |
|
- |
| `email_account_id` | TEXT FK | -> email_accounts (SET NULL). Migration 004 |
|
|
153 |
+ |
| `email_account_id` | TEXT FK | -> email_accounts (SET NULL) |
|
| 154 |
154 |
|
| `from_address` | TEXT | |
|
| 155 |
155 |
|
| `to_address` | TEXT | |
|
| 156 |
156 |
|
| `subject` | TEXT | |
|
| 157 |
157 |
|
| `body` | TEXT | Plain text, default '' |
|
| 158 |
|
- |
| `html_body` | TEXT | Original HTML for browser view. Migration 020 |
|
| 159 |
|
- |
| `message_id` | TEXT | RFC 2822 Message-ID. Migration 004 |
|
| 160 |
|
- |
| `in_reply_to` | TEXT | Threading header. Migration 016 |
|
| 161 |
|
- |
| `thread_id` | TEXT | Conversation grouping. Migration 016 |
|
|
158 |
+ |
| `html_body` | TEXT | Original HTML for browser view |
|
|
159 |
+ |
| `message_id` | TEXT | RFC 2822 Message-ID |
|
|
160 |
+ |
| `in_reply_to` | TEXT | Threading header |
|
|
161 |
+ |
| `thread_id` | TEXT | Conversation grouping |
|
| 162 |
162 |
|
| `is_read` | INTEGER | Boolean, default 0 |
|
| 163 |
|
- |
| `is_archived` | INTEGER | Boolean, default 0. Migration 005 |
|
| 164 |
|
- |
| `is_outgoing` | INTEGER | Boolean, default 0. Migration 004 |
|
| 165 |
|
- |
| `imap_uid` | INTEGER | IMAP UID for sync. Migration 006 |
|
| 166 |
|
- |
| `source_folder` | TEXT | IMAP folder. Migration 006 |
|
| 167 |
|
- |
| `snoozed_until` | TEXT | Migration 010 |
|
| 168 |
|
- |
| `waiting_for_response` | INTEGER | Boolean, default 0. Migration 012 |
|
| 169 |
|
- |
| `waiting_since` | TEXT | Migration 012 |
|
| 170 |
|
- |
| `expected_response_date` | TEXT | Migration 012 |
|
|
163 |
+ |
| `is_archived` | INTEGER | Boolean, default 0 |
|
|
164 |
+ |
| `is_outgoing` | INTEGER | Boolean, default 0 |
|
|
165 |
+ |
| `imap_uid` | INTEGER | IMAP UID for sync |
|
|
166 |
+ |
| `source_folder` | TEXT | IMAP folder |
|
|
167 |
+ |
| `snoozed_until` | TEXT | |
|
|
168 |
+ |
| `waiting_for_response` | INTEGER | Boolean, default 0 |
|
|
169 |
+ |
| `waiting_since` | TEXT | |
|
|
170 |
+ |
| `expected_response_date` | TEXT | |
|
| 171 |
171 |
|
| `received_at` | TEXT | `datetime('now')` |
|
| 172 |
172 |
|
|
| 173 |
173 |
|
Indexes: `project_id`, `is_read`, `received_at DESC`, `user_id`, `message_id`, `email_account_id`, `(email_account_id, imap_uid, source_folder)`, `is_archived`, `snoozed_until`. Partial indexes: `thread_id WHERE NOT NULL`, `in_reply_to WHERE NOT NULL`, `waiting_for_response WHERE = 1`.
|
| 177 |
177 |
|
## Contacts
|
| 178 |
178 |
|
|
| 179 |
179 |
|
### contacts
|
| 180 |
|
- |
People with structured metadata. Migration 023.
|
|
180 |
+ |
People with structured metadata.
|
| 181 |
181 |
|
|
| 182 |
182 |
|
| Column | Type | Notes |
|
| 183 |
183 |
|
|--------|------|-------|
|
| 197 |
197 |
|
Indexes: `user_id`, `(user_id, display_name)`.
|
| 198 |
198 |
|
|
| 199 |
199 |
|
### contact_emails
|
| 200 |
|
- |
Multiple email addresses per contact. Migration 023.
|
|
200 |
+ |
Multiple email addresses per contact.
|
| 201 |
201 |
|
|
| 202 |
202 |
|
- FK `contact_id` -> contacts (CASCADE)
|
| 203 |
203 |
|
- `address`, `label` (default ''), `is_primary` (boolean)
|
| 204 |
204 |
|
- Indexes: `contact_id`, `address`
|
| 205 |
205 |
|
|
| 206 |
206 |
|
### contact_phones
|
| 207 |
|
- |
Multiple phone numbers per contact. Migration 023.
|
|
207 |
+ |
Multiple phone numbers per contact.
|
| 208 |
208 |
|
|
| 209 |
209 |
|
- FK `contact_id` -> contacts (CASCADE)
|
| 210 |
210 |
|
- `number`, `label` (default ''), `is_primary` (boolean)
|
| 211 |
211 |
|
- Index: `contact_id`
|
| 212 |
212 |
|
|
| 213 |
213 |
|
### contact_social_handles
|
| 214 |
|
- |
Social platform handles per contact. Migration 023.
|
|
214 |
+ |
Social platform handles per contact.
|
| 215 |
215 |
|
|
| 216 |
216 |
|
- FK `contact_id` -> contacts (CASCADE)
|
| 217 |
217 |
|
- `platform`, `handle`, `url` (optional)
|
| 218 |
218 |
|
- Index: `contact_id`
|
| 219 |
219 |
|
|
| 220 |
220 |
|
### contact_custom_fields
|
| 221 |
|
- |
Arbitrary label/value pairs with optional URL. Migration 024.
|
|
221 |
+ |
Arbitrary label/value pairs with optional URL.
|
| 222 |
222 |
|
|
| 223 |
223 |
|
- FK `contact_id` -> contacts (CASCADE)
|
| 224 |
224 |
|
- `label`, `value`, `url` (optional)
|
| 234 |
234 |
|
| Column | Type | Notes |
|
| 235 |
235 |
|
|--------|------|-------|
|
| 236 |
236 |
|
| `id` | TEXT PK | |
|
| 237 |
|
- |
| `user_id` | TEXT FK | -> users (CASCADE). Migration 002 |
|
|
237 |
+ |
| `user_id` | TEXT FK | -> users (CASCADE) |
|
| 238 |
238 |
|
| `project_id` | TEXT FK | -> projects (SET NULL) |
|
| 239 |
239 |
|
| `title` | TEXT | NOT NULL |
|
| 240 |
240 |
|
| `description` | TEXT | Default '' |
|
| 241 |
241 |
|
| `start_time` | TEXT | ISO datetime |
|
| 242 |
242 |
|
| `end_time` | TEXT | Nullable |
|
| 243 |
243 |
|
| `location` | TEXT | |
|
| 244 |
|
- |
| `linked_task_id` | TEXT FK | -> tasks (SET NULL). Migration 008 |
|
| 245 |
|
- |
| `recurrence` | TEXT | Default 'None'. Migration 008 |
|
| 246 |
|
- |
| `recurrence_parent_id` | TEXT FK | -> events (SET NULL). Migration 008 |
|
| 247 |
|
- |
| `contact_id` | TEXT FK | -> contacts (SET NULL). Migration 025 |
|
| 248 |
|
- |
| `block_type` | TEXT | Time block category. Migration 026 |
|
|
244 |
+ |
| `linked_task_id` | TEXT FK | -> tasks (SET NULL) |
|
|
245 |
+ |
| `recurrence` | TEXT | Default 'None' |
|
|
246 |
+ |
| `recurrence_parent_id` | TEXT FK | -> events (SET NULL) |
|
|
247 |
+ |
| `contact_id` | TEXT FK | -> contacts (SET NULL) |
|
|
248 |
+ |
| `block_type` | TEXT | Time block category |
|
| 249 |
249 |
|
|
| 250 |
250 |
|
Indexes: `project_id`, `start_time`, `user_id`, `linked_task_id`, `recurrence_parent_id`.
|
| 251 |
251 |
|
|
| 252 |
252 |
|
### weekly_reviews
|
| 253 |
|
- |
Weekly review completion tracking. Migration 018.
|
|
253 |
+ |
Weekly review completion tracking.
|
| 254 |
254 |
|
|
| 255 |
255 |
|
| Column | Type | Notes |
|
| 256 |
256 |
|
|--------|------|-------|
|
| 259 |
259 |
|
| `week_start_date` | TEXT | ISO week Monday (YYYY-MM-DD) |
|
| 260 |
260 |
|
| `completed_at` | TEXT | `datetime('now')` |
|
| 261 |
261 |
|
| `notes` | TEXT | Default '' |
|
| 262 |
|
- |
| `vacation_days` | TEXT | Comma-separated day indices. Migration 027 |
|
|
262 |
+ |
| `vacation_days` | TEXT | Comma-separated day indices |
|
| 263 |
263 |
|
|
| 264 |
264 |
|
Unique: `(user_id, week_start_date)`. Index: `(user_id, week_start_date)`.
|
| 265 |
265 |
|
|
| 266 |
266 |
|
### saved_views
|
| 267 |
|
- |
Persisted filter/sort configurations for quick access. Migration 015.
|
|
267 |
+ |
Persisted filter/sort configurations for quick access.
|
| 268 |
268 |
|
|
| 269 |
269 |
|
| Column | Type | Notes |
|
| 270 |
270 |
|
|--------|------|-------|
|
| 286 |
286 |
|
|
| 287 |
287 |
|
## Search
|
| 288 |
288 |
|
|
| 289 |
|
- |
FTS5 virtual tables with automatic sync triggers (INSERT/UPDATE/DELETE). Created in migration 011, contacts FTS in migration 023.
|
|
289 |
+ |
FTS5 virtual tables with automatic sync triggers (INSERT/UPDATE/DELETE).
|
| 290 |
290 |
|
|
| 291 |
291 |
|
| FTS Table | Source Table | Indexed Columns |
|
| 292 |
292 |
|
|-----------|-------------|-----------------|
|
| 303 |
303 |
|
## Sync
|
| 304 |
304 |
|
|
| 305 |
305 |
|
### sync_state
|
| 306 |
|
- |
Key-value store for SyncKit configuration and state. Migration 030.
|
|
306 |
+ |
Key-value store for SyncKit configuration and state.
|
| 307 |
307 |
|
|
| 308 |
308 |
|
Seeded keys: `device_id`, `pull_cursor`, `auto_sync_enabled`, `sync_interval_minutes`, `applying_remote`, `last_sync_at`, `initial_snapshot_done`.
|
| 309 |
309 |
|
|
| 310 |
310 |
|
### sync_changelog
|
| 311 |
|
- |
Local change log captured by triggers, pushed to MNW server. Migration 030.
|
|
311 |
+ |
Local change log captured by triggers, pushed to MNW server.
|
| 312 |
312 |
|
|
| 313 |
313 |
|
| Column | Type | Notes |
|
| 314 |
314 |
|
|--------|------|-------|
|
| 322 |
322 |
|
|
| 323 |
323 |
|
Partial index: `pushed WHERE pushed = 0`.
|
| 324 |
324 |
|
|
| 325 |
|
- |
Sync triggers exist on 11 tables: projects, tasks, events, contacts, contact_emails, contact_phones, contact_social_handles, contact_custom_fields, annotations, subtasks, milestones. Each trigger checks the `applying_remote` flag to prevent echo during pull. Email accounts sync config only (credentials excluded per migration 033).
|
|
325 |
+ |
Sync triggers exist on 11 tables: projects, tasks, events, contacts, contact_emails, contact_phones, contact_social_handles, contact_custom_fields, annotations, subtasks, milestones. Each trigger checks the `applying_remote` flag to prevent echo during pull. Email accounts sync config only (credentials excluded).
|
| 326 |
326 |
|
|
| 327 |
327 |
|
---
|
| 328 |
328 |
|
|
| 343 |
343 |
|
Index: `email`.
|
| 344 |
344 |
|
|
| 345 |
345 |
|
### llm_settings (unused - tables retained for migration compatibility)
|
| 346 |
|
- |
Per-user LLM provider configuration. Migration 014.
|
|
346 |
+ |
Per-user LLM provider configuration.
|
| 347 |
347 |
|
|
| 348 |
348 |
|
| Column | Type | Notes |
|
| 349 |
349 |
|
|--------|------|-------|
|
| 361 |
361 |
|
| `updated_at` | TEXT | |
|
| 362 |
362 |
|
|
| 363 |
363 |
|
### llm_cache (unused - tables retained for migration compatibility)
|
| 364 |
|
- |
Prompt-response cache with date-aware invalidation. Migration 014.
|
|
364 |
+ |
Prompt-response cache with date-aware invalidation.
|
| 365 |
365 |
|
|
| 366 |
366 |
|
| Column | Type | Notes |
|
| 367 |
367 |
|
|--------|------|-------|
|
| 376 |
376 |
|
Unique: `(user_id, prompt_hash, context_date)`. Index: `(user_id, prompt_hash, context_date)`.
|
| 377 |
377 |
|
|
| 378 |
378 |
|
### backup_settings
|
| 379 |
|
- |
Automated local backup configuration. Migration 019, revised migration 029.
|
|
379 |
+ |
Automated local backup configuration.
|
| 380 |
380 |
|
|
| 381 |
381 |
|
| Column | Type | Notes |
|
| 382 |
382 |
|
|--------|------|-------|
|
| 383 |
383 |
|
| `id` | TEXT PK | |
|
| 384 |
384 |
|
| `user_id` | TEXT FK | -> users. Unique |
|
| 385 |
385 |
|
| `auto_backup_enabled` | INTEGER | Boolean, default 1 |
|
| 386 |
|
- |
| `backup_frequency_minutes` | INTEGER | Default 15 (was hours, converted in 029) |
|
| 387 |
|
- |
| `max_backups_to_keep` | INTEGER | Default 1 (was 7, changed in 029) |
|
|
386 |
+ |
| `backup_frequency_minutes` | INTEGER | Default 15 |
|
|
387 |
+ |
| `max_backups_to_keep` | INTEGER | Default 1 |
|
| 388 |
388 |
|
| `last_backup_at` | TEXT | |
|
| 389 |
389 |
|
| `created_at` | TEXT | |
|
| 390 |
390 |
|
| `updated_at` | TEXT | |
|
| 399 |
399 |
|
- **Boolean as INTEGER:** SQLite has no native boolean; 0/1 INTEGER used throughout
|
| 400 |
400 |
|
- **FTS5 content tables:** Virtual tables with `content=` pointing to source table; triggers keep indexes in sync
|
| 401 |
401 |
|
- **Sync echo prevention:** All sync triggers check `sync_state.applying_remote` to avoid logging changes pulled from the server
|
| 402 |
|
- |
- **Credential isolation:** Email account sync triggers exclude passwords and OAuth tokens (migration 033)
|
|
402 |
+ |
- **Credential isolation:** Email account sync triggers exclude passwords and OAuth tokens
|
| 403 |
403 |
|
- **Recurrence via parent links:** Both tasks and events use `recurrence_parent_id` self-referential FK for recurring series
|
| 404 |
404 |
|
- **Multi-entity linking:** Tasks can link to emails (`source_email_id`), contacts (`contact_id`), milestones (`milestone_id`), and events (`linked_task_id` on events)
|
| 405 |
405 |
|
- **Subtask-to-task links:** Subtasks can reference another full task via `linked_task_id` for multi-phase work
|
| 410 |
410 |
|
- **Partial** on tasks (`waiting_for_response WHERE = 1`, `is_focus WHERE = 1`, `completed_at WHERE NOT NULL`), emails (`waiting_for_response WHERE = 1`, `thread_id WHERE NOT NULL`, `in_reply_to WHERE NOT NULL`), saved_views (`is_pinned WHERE = 1`)
|
| 411 |
411 |
|
- **Composite** on emails `(email_account_id, imap_uid, source_folder)` for IMAP sync, contacts `(user_id, display_name)`, weekly_reviews `(user_id, week_start_date)`
|
| 412 |
412 |
|
- **Sort** on tasks `(urgency DESC)`, emails `(received_at DESC)`
|
| 413 |
|
- |
|
| 414 |
|
- |
## Schema Evolution
|
| 415 |
|
- |
|
| 416 |
|
- |
Major milestones across 50 migrations:
|
| 417 |
|
- |
|
| 418 |
|
- |
| Migration | Change |
|
| 419 |
|
- |
|-----------|--------|
|
| 420 |
|
- |
| 001 | Initial schema (projects, tasks, annotations, events, emails) |
|
| 421 |
|
- |
| 002 | Users table, user_id FK on all data tables |
|
| 422 |
|
- |
| 003 | Task recurrence parent links |
|
| 423 |
|
- |
| 004 | Email accounts (IMAP/SMTP config), email message tracking |
|
| 424 |
|
- |
| 007 | Subtasks (checkbox items on tasks) |
|
| 425 |
|
- |
| 008 | Task-event linking, event recurrence |
|
| 426 |
|
- |
| 009 | Email-to-task linking |
|
| 427 |
|
- |
| 010 | Snooze/defer for tasks and emails |
|
| 428 |
|
- |
| 011 | FTS5 full-text search (emails, tasks, projects, events) |
|
| 429 |
|
- |
| 012 | Follow-up / waiting-for tracking |
|
| 430 |
|
- |
| 013 | Time blocking (scheduled_start, scheduled_duration) |
|
| 431 |
|
- |
| 014 | LLM settings and prompt cache |
|
| 432 |
|
- |
| 015 | Saved views / filters |
|
| 433 |
|
- |
| 016 | Email threading (in_reply_to, thread_id) |
|
| 434 |
|
- |
| 017 | OAuth2/JMAP support for email accounts (Fastmail) |
|
| 435 |
|
- |
| 018 | Weekly reviews, task focus mode |
|
| 436 |
|
- |
| 019 | Backup settings |
|
| 437 |
|
- |
| 022 | Subtask-to-task links (multi-phase work) |
|
| 438 |
|
- |
| 023 | Contacts (people, emails, phones, social handles, FTS) |
|
| 439 |
|
- |
| 024 | Contact custom fields |
|
| 440 |
|
- |
| 025 | Contact linking to tasks and events |
|
| 441 |
|
- |
| 026 | Time block types on events |
|
| 442 |
|
- |
| 027 | Vacation days on weekly reviews |
|
| 443 |
|
- |
| 028 | Milestones (scope boundaries within projects) |
|
| 444 |
|
- |
| 029 | Backup frequency: hours to minutes |
|
| 445 |
|
- |
| 030 | SyncKit changelog + state + 33 sync triggers (11 tables) |
|
| 446 |
|
- |
| 031 | completed_at on tasks, updated sync triggers |
|
| 447 |
|
- |
| 032 | Email account sync triggers |
|
| 448 |
|
- |
| 033 | Credential isolation (exclude passwords/tokens from sync) |
|