Skip to content

Releases

v0.11.0 — Collaboration, Reports & Hardening

Choose a tag to compare

@andybochmann andybochmann released this 12 Jul 22:31

This release adds a wave of collaboration and reporting features — task comments with @mentions, task dependencies, a cross-project My Work view, time-tracking reports, and a subscribable iCal calendar feed — on top of a large security and stability hardening pass that resolves ~60 findings from a full-repo code review ahead of going public.

✨ New Features

💬 Task comments with @mentions (#5)

  • Per-task discussion thread visible to all project members (viewers can read and post)
  • @mentions validated as project members, each firing a new mention notification
  • Realtime via SSE comment events; offline-aware via offlineFetch
  • Author or project owner can delete; mention matching is word-boundary/span-masked so a short name won't match inside a longer name or email

🔗 Task dependencies — "blocked by" (#6)

  • A task can be blocked by other tasks in the same project and can't be completed while any blocker is open
  • Cycle detection (3-colour DFS) on update; completion guard enforced across REST PATCH, /complete, MCP complete_task/update_task, and bulk move-to-done
  • Blocked badge (open-blocker count) on the card + a cycle-aware "Blocked by" picker in the task sheet
  • Deleting a task prunes its id from every other task's blockedBy on all delete paths — no phantom blockers

🗓 iCal (.ics) calendar feed (#9)

  • Subscribe to your task due dates from Apple / Google / Outlook Calendar
  • Public feed GET /api/calendar/[token]/feed.ics authenticated by a high-entropy (256-bit) secret URL token (Google "secret address" model)
  • Per-user revocable calendarFeedToken; settings API to enable / regenerate / disable
  • Exposes only your own non-archived tasks with a due date; RFC-5545 builder with ICS-injection-safe escaping, UTC all-day dates, and 75-octet line folding

🧭 "My Work" cross-project view (#8)

  • Open tasks assigned to you across all accessible projects, grouped by project or by due-date bucket (Overdue / Today / This week / Later / No date)
  • Reuses the existing access-enforced tasks API (no backend change); deep-links to the task in its project
  • Overdue conveyed via text (not color alone); dark-mode-safe

📊 Time-tracking reports (#7)

  • Turns captured task time sessions into a summary: total, per-project bars, and a weekly trend over a trailing window of N ISO weeks
  • GET /api/stats/time-report: access-scoped aggregation counting only your own sessions; range selector (1–52 weeks, default 8)
  • No chart dependencies — CSS/inline bars with empty/error/loading states and a11y labels

🎯 Per-column WIP limits (#2)

  • Optional per-column work-in-progress limit set in the column manager (empty = no limit)
  • Header shows count / limit; over-limit columns get a destructive ring + badge and an aria-label
  • Soft limit — drag is flagged, not blocked; count uses true column size so board filters can't mask an over-limit column

📅 Quick-select chips in the date picker (#4)

  • Today / Tomorrow / Next week / Clear chips in the date picker popover for one-click due dates
  • Chips resolve to a local calendar date reusing the same yyyy-MM-dd formatting as the calendar — no timezone shift; purely additive

🔒 Security Fixes (#1)

  • User enumeration: users/search returns exact-email matches only — no directory enumeration
  • OAuth pre-hijack: refuse silent OAuth linking to an unverified credentials account
  • Cross-user data deletion: scope backup-restore task/notification deletion to owned projects only (previously deleted tasks in shared projects the user only viewed)
  • Secrets/config: fail-fast on missing AUTH_SECRET; lock down mongo-express in the dev compose
  • Token lifetime: access tokens get a bounded expiry (default 90d, max 365d); JWTs voided after password change / account deletion; shorter session maxAge
  • Rate limiting & password policy: in-memory rate limiting on register/login/password-change + a stronger password policy
  • Error/CSP hardening: map duplicate-key to 409 and stop leaking internal error messages; 400 for malformed ObjectId params; drop unsafe-eval from the production CSP
  • SSE: re-validate the session on heartbeat + a 1h max stream lifetime
  • Account deletion: unset dangling assignee refs and notify affected members

🛠 Bug Fixes (#1)

Data integrity

  • Replace a mis-declared sparse compound unique index with a partial index; move overdue dedup to a generation-based key and swallow E11000 on summary/digest
  • Reset the cached Mongoose connection promise on rejection; syncIndexes() on worker boot so the dedup index actually replaces the old one on existing deployments
  • Add an isRunning overlap guard to the worker interval; restore NotificationPreference on backup rollback

Recurrence & tasks

  • Claim completion atomically (findOneAndUpdate on completedAt:null) to stop duplicate recurring spawns; emit the spawned occurrence's created event to the originating tab
  • Validate columnId against project.columns on REST create/update and per-project on bulk move; remap orphaned tasks on MCP column changes
  • Unify recurrence math on date-utils and anchor monthly recurrence (no drift); schedule a reminder for the spawned occurrence; two-pass DST correction in computeReminderDate
  • Exclude archived tasks from stats counts; flag overdue only after the due day passes in the user's timezone

Offline & sync

  • Offline PATCH echoes the real id and hooks merge it — no more blank/corrupted entities; tempId → realId replay mapping and stable replay order with an idempotency key
  • Treat auth redirects as transient (keep the queue), skip caching /api/events, clear page cache on logout, guard cache.put on redirects
  • SSE reconnect retries indefinitely and recovers on focus/visibility; guard against duplicate EventSource connections; refetch notes/presets/members/archived on reconnect
  • Fix the stuck user-search spinner + out-of-order results; roll back dismissAll on failure
  • Auth: fail open in the JWT session-revocation check so a transient DB error can't force-log-out every user

UI & accessibility

  • Store due dates at UTC midnight from the card popover, bulk bar & calendar drag (timezone fix); clear ?taskId= after first open so a closed sheet stays closed
  • Don't overwrite an in-progress title/description edit on SSE update
  • Confirm bulk delete and list-item delete; block deleting a column that still holds archived tasks
  • Surface errors on subtask add, project settings, column save, calendar create, and bulk-create
  • Dark-mode chips, keyboard-openable rows, aria-labels, truncation, Cmd/Ctrl+K, calendar project selector, locale-correct labels
  • Share dialog falls back to email when a non-collaborator has no name to show

📓 Docs & Internal

  • Added interaction coverage for the bulk-actions bar — assign/unassign, add-label, priority, move, and archive now assert the right callbacks fire (#3)
  • Added a full-repo code review & bug-hunt report (4 critical / ~14 high / ~20 medium / ~20 low) with a phased remediation plan
  • Cleaned up internal development artifacts and fixed docs conventions before going public

v0.10.1 — Icon Refresh

Choose a tag to compare

@andybochmann andybochmann released this 30 Mar 04:01

Updated all application icons to match the unified purple-to-cyan gradient theme used across Calcflux, Regex-Lab, and Home-Maintenance.

🎨 Style

  • Full-bleed maskable icons (no built-in rounded corners — OS applies its own mask)
  • Added icon.svg for scalable display
  • Set "purpose": "any maskable" on PWA icons in manifest
  • Updated theme/background colors to dark (#0F172A)
  • Renamed icon files to match cross-project convention (icon-192.png, icon-512.png)
  • Updated all references in service worker, notification settings, and manifest

v0.10.0 — Stability & Quick Add

Choose a tag to compare

@andybochmann andybochmann released this 30 Mar 03:28

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

v0.9.2

Choose a tag to compare

@andybochmann andybochmann released this 02 Mar 00:41

What's Changed

  • ci: Simplify Docker build workflow to amd64-only — removes matrix strategy, artifact passing, and merge job (113 → 46 lines)

v0.9.1

Choose a tag to compare

@andybochmann andybochmann released this 02 Mar 00:37

What's Changed

  • fix: Replace QEMU emulation with native ARM runners in Docker build workflow — resolves arm64 builds hanging due to illegal instruction crashes under QEMU
  • docs: Update README, CLAUDE.md, and marketing page for recent features
  • feat: Close TaskSheet on Mark Complete with undo toast
  • feat: Implement 5 quick-win features with tests and E2E coverage
  • feat: Pin Complete & Delete actions to sticky footer in TaskSheet
  • fix: Replace hidden md:* with max-md:hidden for Tailwind v4 compatibility

v0.9.0

Choose a tag to compare

@andybochmann andybochmann released this 01 Mar 23:07

What's New

Features

  • Filter presets — Save and load filter configurations per project
  • Global search API — Search across tasks, projects, and categories from the command palette
  • Enhanced command palette — Recent searches, improved results, keyboard-driven workflow
  • Inline task editing — Edit task titles directly on Kanban cards without opening the sheet
  • Kanban keyboard navigation — Navigate and manage tasks with arrow keys and shortcuts
  • Bulk task operations — Enhanced bulk actions bar with more operations
  • Context menu — Right-click context menu on task cards
  • TaskSheet Mark Complete — Closes the sheet with an undo toast for quick completion
  • shadcn Calendar pickers — Replaced native date inputs with polished Calendar and DateTimePicker components
  • Auto-save indicator — Visual feedback in TaskSheet when changes are being saved
  • Dashboard hover animations — Scale animation on metric cards

Bug Fixes

  • Fixed Android PWA notification actions both triggering snooze instead of complete
  • Fixed reminderAt missing from server-side task serialization
  • Hardened service worker notification actions with credentials and error logging
  • Fixed Tailwind v4 compatibility (hidden md:* → max-md:hidden)

Docs

  • Updated README, CLAUDE.md, and marketing landing page to reflect all new features
  • Added Command Palette and AI Subtasks cards to the marketing features section
  • Fixed test count (184 files, 2013 tests) and AI provider reference in CLAUDE.md

v0.8.1 — Sticky task action footer

Choose a tag to compare

@andybochmann andybochmann released this 01 Mar 20:54

What's New

Sticky footer for task actions

The Mark Complete / Reopen button and secondary actions are now pinned to the bottom of the task sheet, accessible from any scroll position.

Before: Complete and Delete buttons were buried at the bottom of 12+ scrollable form sections — on mobile, users had to scroll through everything to reach them.

After:

  • Mark Complete / Reopen button is always visible in a sticky footer bar
  • Three-dot overflow menu contains Archive, Duplicate, Share, and Delete
  • Form content scrolls independently above the footer
  • Destructive actions (Delete) are tucked behind the menu for intentional friction

Details

  • Restructured SheetContent layout: overflow-hidden outer container with flex-1 overflow-y-auto scrollable area + pinned footer
  • Replaced stacked full-width action buttons with compact footer bar + DropdownMenu
  • Overflow menu opens upward (side="top") so it doesn't get clipped by the viewport
  • Conditional menu items: Archive (only when completed), Duplicate, Share
  • All 1861 tests passing across 175 test files

v0.8.0

Choose a tag to compare

@andybochmann andybochmann released this 01 Mar 19:24

What's New

Features

  • Calendar date pickers — Replaced native <input type="date"> and <input type="datetime-local"> with shadcn Calendar-based pickers (DatePicker and DateTimePicker) for consistent cross-browser styling on due date, reminder, and recurrence end date fields
  • Auto-save indicator — TaskSheet now shows a save status indicator
  • Dashboard hover animation — Metric cards on the dashboard animate on hover

Bug Fixes

  • Empty task rows on Overview page — Fixed Tailwind CSS v4 source-order issue where hidden md:grid failed to show desktop layouts; replaced with max-md:hidden pattern across 8 components
  • Android PWA notification actions — Fixed both notification actions triggering snooze instead of distinguishing between snooze and complete

v0.7.5

Choose a tag to compare

@andybochmann andybochmann released this 23 Feb 16:43

Fixes

  • Reminder persistence: Include reminderAt in server-side task serialization so the bell icon and reminder data persist after page refresh
  • Cleanup: Remove stale Google Calendar references from backup test

v0.7.4

Choose a tag to compare

@andybochmann andybochmann released this 23 Feb 04:38

Fixes

  • SW notification actions: Added explicit credentials: "same-origin" to service worker fetch calls ensuring session cookies are sent for Mark Complete and Snooze actions
  • Error visibility: Added handleActionError() helper with console.error() logging and detailed error response body reading for easier debugging

Tests

  • Added 3 E2E Playwright tests verifying complete, snooze, and auth redirect detection through the real HTTP stack
  • Added 4 integration tests verifying the full notification-worker → snooze/complete flow with real MongoDB