Skip to content

v0.10.0 — Stability & Quick Add

Choose a tag to compare

@andybochmann andybochmann released this 30 Mar 03:28
· 27 commits to main since this release

This release delivers a major stability overhaul with 120+ bug fixes across 8 focused passes, plus a new Quick Add Task dialog for faster task creation.

✨ New Features

Quick Add Task Dialog

  • Global quick-add dialog accessible from sidebar, mobile topbar, and q keyboard shortcut
  • Smart project defaulting: current URL → last-used → first non-archived
  • Main form: Title, Project, Due Date, Reminder
  • Expandable "More Options": Priority, Labels, Assignee, Description
  • Inline kanban task creation now auto-opens the full task sheet immediately

🔒 Security Fixes

  • IDOR via backup restore: skip unmapped foreign IDs to prevent cross-user data injection
  • Label IDOR: validate label ownership on task create, update, and bulk add-label
  • Editor privilege escalation: PATCH /api/projects now requires owner role for all settings
  • Time session ownership: ownership check on DELETE prevents cross-user session deletion
  • MCP categoryId validation: ownership check prevents unauthorized category access
  • Push subscription scoping: upsert scoped to userId prevents cross-user push registration
  • AI prompt injection: separate system prompt from user content in AI endpoints
  • AI input validation: Zod schema caps input lengths on generate-subtasks
  • AI error leak: only forward expected 403/404 messages; generic message for all others
  • AI rate limiting: 10 req/min per-user sliding window on AI endpoints
  • Backup export scoping: restrict to owned projects only, preventing shared project data leakage
  • Member enumeration: member DELETE returns 404 (not 403)
  • User search restriction: restricted to project owners only
  • MCP role enforcement: update_project requires owner role (was editor)

🛠 Bug Fixes — Data Integrity

  • MongoDB operator mixing: wrap bare fields in $set alongside $push/$unset in task PATCH and complete routes
  • OAuth race condition: guard User.create and Account.create against E11000 duplicate-key errors
  • Backup restore: split prepare/insert phases with flag-based compensating rollback
  • Backup restore: create ProjectMember records and clean up orphaned ones
  • Account deletion cascade: fix shared project tasks/members/notes cleanup
  • Merge $unset reminderAt into single DB write to prevent stale SSE events
  • Fix recurring task order userId scoping
  • Cascade-delete Notification records on all 6 task deletion paths
  • Cascade-delete Notes and Notifications in MCP delete handlers
  • Remap orphaned tasks before updating columns to prevent phantom column state
  • Label DELETE cleanup no longer incorrectly scoped by userId (fixes shared projects)
  • Preserve assigneeId when creating recurring task successor
  • MCP notes: wrap update in $set to prevent document replacement
  • statusHistory push conditional on actual column change
  • Recurring task order uses max(order)+1 instead of countDocuments

🛠 Bug Fixes — State Machines & Rendering

  • Bulk move sets/clears completedAt based on last column
  • Recurrence only spawns child on incomplete→complete transition
  • completedAt clearing on reopen fixed (undefined→null)
  • DnD cancel reverts optimistic column change on drop-outside/Escape
  • DnD cross-column + reorder concurrent write resolution
  • Task sheet syncs selectedTask after DnD column move
  • Task title/description SSE sync with useEffect guards and debounce cleanup
  • Flush title+description as single update on unmount
  • NoteEditorDialog: flush pending auto-save on dialog close
  • Sync TaskSheet form state from prop changes
  • selectedTask syncs with tasks array via useEffect
  • handleDragEnd reads from tasksRef for latest state
  • Bulk action selects controlled with post-action reset
  • Priority sort uses find().lean() instead of aggregate() (fixes ObjectId serialization)
  • Command palette deep links auto-open task sheet via openTaskId prop
  • Command palette saves recent searches only on result selection
  • Archived tasks sheet hides mutation buttons for viewer role
  • Calendar task creation uses offlineFetch for offline support

🛠 Bug Fixes — Background Jobs & Offline

  • Offline sync: permanent 4xx failures removed from queue instead of infinite retry
  • Offline queue: navigator.locks prevents double-replay race with Background Sync
  • Dual sync paths: app-level sync defers to Background Sync when available
  • SSE reconnect: reset retry counter on online event
  • SSE stream cancel() callback for cleanup on dropped connections
  • Service worker notification actions include X-Session-Id header
  • Store tab sessionId with offline mutations for correct SSE echo suppression
  • Badge API feature detection in service worker
  • Notification worker: filter dismissed:false in dedup query
  • Reminder dedup: unique compound index prevents duplicate notifications
  • scheduleNextReminder uses retry + reminderAt restore on failure
  • Preserve reminderAt during preference recalculation
  • Overdue notifications dismissed when task rescheduled to future date
  • Compensating delete on ProjectMember.create failure during project creation
  • Active timer guard before bulk archive
  • Always update local state after deleteSession regardless of navigator.onLine
  • markSaved() moved out of finally block to reflect actual success
  • Atomic timer start with $not/$elemMatch precondition
  • Owner membership creation uses atomic upsert (fixes race condition)

🎨 Style

  • Updated app icons to pillar column design with purple-to-cyan gradient squircle

📊 Stats

  • 87 files changed, 3,526 insertions, 504 deletions
  • 120+ individual bug fixes across 8 focused passes
  • All 2,013 tests pass across 184 test files