Skip to content

Tasks

Tasks are the primary work unit in Planner. They support a full lifecycle with status workflow, priorities, assignments, due dates, subtasks, threaded comments, change history, and a dedicated task chat.

Model

Task
├── title, description
├── status: todo | in_progress | in_review | done | cancelled | overdue
├── priority: low | medium | high | urgent
├── assigneeId?, dueDate?
├── parentId? (subtasks)
├── projectId (required, cascade delete)
├── comments (threaded with replies)
├── history (audit log)
└── chat (create or get task conversation)

API Endpoints

Task CRUD (/projects/:id/tasks)

MethodPathDescription
GET/api/projects/:id/tasksList project tasks
POST/api/projects/:id/tasksCreate task
GET/api/projects/:id/tasks/:taskIdGet task with details
PATCH/api/projects/:id/tasks/:taskIdUpdate task
PATCH/api/projects/:id/tasks/:taskId/statusUpdate status only
DELETE/api/projects/:id/tasks/:taskIdDelete task

My Tasks

MethodPathDescription
GET/api/tasks/myTasks assigned to current user (dashboard)
GET/api/tasks/my/calendarTasks in date range (?from=&to=)

Team Task Board

MethodPathDescription
GET/api/teams/by-slug/:teamSlug/tasksConvenience team endpoint

Task Comments (/projects/:id/tasks/:taskId/comments)

MethodPathDescription
GET/api/projects/:id/tasks/:taskId/commentsList comments (flat, with parentId for threading)
POST/api/projects/:id/tasks/:taskId/commentsCreate comment (optional parentId for reply)
PATCH/api/projects/:id/tasks/:taskId/comments/:commentIdEdit comment
DELETE/api/projects/:id/tasks/:taskId/comments/:commentIdDelete comment (blocked if has replies)

Task History (/projects/:id/tasks/:taskId/history)

MethodPathDescription
GET/api/projects/:id/tasks/:taskId/historyGet task audit log

Task Chat

MethodPathDescription
POST/api/chats/task/:taskIdCreate or get task conversation

Reorder & Bulk Operations

MethodPathDescription
POST/api/projects/:id/tasks/reorderReorder tasks (drag-and-drop)
POST/api/projects/:id/tasks/bulkBulk operations (status, assign, delete, priority)

Task Attachments

MethodPathDescription
POST/api/projects/:id/tasks/:taskId/attachmentsUpload task attachments (up to 50MB)
POST/api/projects/:id/tasks/:taskId/attachments/removeRemove attachment
POST/api/projects/:id/tasks/:taskId/comments/attachmentsUpload comment attachments

Task Dependencies (/tasks/:taskId/dependencies)

MethodPathDescription
GET/api/tasks/:taskId/dependenciesList task dependencies
POST/api/tasks/:taskId/dependenciesCreate dependency (dependsOnId, type?: blocks | relates_to)
DELETE/api/tasks/:taskId/dependencies/:idRemove dependency

Tags (/tags)

MethodPathDescription
GET/api/orgs/:orgId/tagsList organization tags
GET/api/teams/:teamId/tagsList team tags
GET/api/tasks/:taskId/tagsList task tags
POST/api/tagsCreate tag (name, color?, orgId?, teamId?)
PATCH/api/tags/:idUpdate tag
DELETE/api/tags/:idDelete tag
POST/api/tasks/:taskId/tagsAssign tags to task (tagIds: string[])

Status Workflow

todo ──► in_progress ──► in_review ──► done
  │                        │
  └────────────────────────┘
       cancelled

overdue (automatic, when due date passes)

Task History (Audit Log)

Every change is automatically logged:

ActionTriggerData
CREATEDTask creationWho created, when
UPDATEDField changeField name, old value, new value
STATUS_CHANGEDStatus updateOld status, new status
ASSIGNEDAssignee changeOld assignee, new assignee
DELETEDTask deletionSnapshot of deleted task

History is displayed as a color-coded timeline.

Threaded Comments

Comments support replies via parentId:

  • Top-level comment: parentId is null
  • Reply: parentId references the parent comment
  • Nesting: Unlimited (displayed with indentation)
  • Deletion: Cannot delete a comment that has replies — delete replies first
  • Notifications: Replying to a comment notifies the parent comment author

Frontend Component

The TaskComments.vue component builds a comment tree from the flat API response and renders it recursively via CommentNode.vue. Each comment has:

  • Reply button (opens inline form)
  • Edit button (own comments only)
  • Delete button (own comments only, hidden if has replies)

Frontend Store

Tasks Store

typescript
const store = useTasksStore()
const { tasks, currentTask } = storeToRefs(store)

await store.fetchTasks(projectId)
await store.createTask(projectId, { title, status, priority, assigneeId, dueDate, parentId })
await store.updateTask(projectId, taskId, { title, status, priority, assigneeId, dueDate })
await store.updateTaskStatus(projectId, taskId, status)
await store.deleteTask(projectId, taskId)

Comments Store

typescript
const store = useCommentsStore()
const { comments } = storeToRefs(store)

await store.fetchComments(projectId, taskId)
await store.createComment(projectId, taskId, { body, parentId, attachments })
await store.updateComment(projectId, taskId, commentId, { body })
await store.deleteComment(projectId, taskId, commentId)
await store.uploadAttachments(projectId, taskId, files)

Task History Store

typescript
const store = useTaskHistoryStore()
const { history, loading } = storeToRefs(store)

await store.fetchHistory(projectId, taskId)

Key Implementation Details

  • Task chat is separate from comments — use POST /api/chats/task/:taskId to create or get a conversation
  • Chat automatically adds the requesting user as a participant
  • Task history is served by a separate TaskHistoryController (not embedded in task response)
  • Attachments are uploaded before creating a comment, then referenced by URL in the comment
  • Tags are scoped to organizations or teams — assign via POST /api/tasks/:taskId/tags with { tagIds: [] }
  • Task dependencies use blocks type by default — a blocking task prevents the dependent task from being marked done
  • Reorder items use { taskId, position } pairs for drag-and-drop persistence
  • Bulk operations support actions: status, assignee, delete, priority