Skip to content

v0.11.0 — Collaboration, Reports & Hardening

Latest

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