Tasks Module
Task management, AI reprioritization, and seed data
The Tasks module manages cross-workspace tasks. Source: packages/server/src/modules/tasks/.
REST Endpoints
All endpoints are prefixed with /api/v1/tasks and require ClerkAuthGuard.
| Method | Path | Description |
|---|---|---|
| POST | /tasks | Create a task |
| GET | /tasks | List tasks with filters |
| GET | /tasks/:id | Get a single task |
| PATCH | /tasks/:id | Update task fields |
| DELETE | /tasks/:id | Delete a task |
| POST | /tasks/reorder | Bulk reorder by sort order |
| POST | /tasks/reprioritize | Apply AI-driven priority changes |
| POST | /tasks/seed | Seed onboarding tasks |
Filters for GET /tasks
| Param | Type | Description |
|---|---|---|
status | TaskStatus | Filter by status |
priority | TaskPriority | Filter by priority |
assigneeId | string | Filter by assignee |
workspaceId | string | Filter by workspace |
tags | string[] | Filter by tags (any match) |
dueBefore | ISO date | Tasks due before this date |
dueAfter | ISO date | Tasks due after this date |
Visibility
A task is visible only to its creator and, once assigned, its assignee — both parties to an assignment can see it, nobody else can. GET /tasks and GET /tasks/:id only ever return tasks the caller is one of those two parties to. This applies to every org role, including OWNER/ADMIN — no role has elevated, org-wide visibility.
List/get responses include assigneeName/creatorName (falling back to email when the user has no display name) so a client can render "Assigned by <creatorName>" for the assignee and "Assigned to <assigneeName>" for the creator.
A task outside the caller's visibility is reported as 404 Not Found (not 403) from GET /tasks/:id, so its existence isn't leaked to someone who can't see it.
Task Service (services/tasks.service.ts)
create(orgId, userId, dto)
Creates a new task. Fields:
| Field | Required | Description |
|---|---|---|
title | Yes | Task title |
description | No | Detailed description |
status | No | Default: TODO |
priority | No | Default: MEDIUM |
assigneeId | No | Assignee user ID (null = unassigned) |
workspaceId | No | Workspace (null = org-level) |
dueDate | No | ISO date string |
tags | No | String array |
metadata | No | JSON object |
An unassigned task (assigneeId: null) is visible only to its creator. Once assigned, it's visible to both the creator and the assignee.
update(orgId, taskId, dto)
Partial update. When status is set to DONE, completedAt is automatically set to now(). When status changes away from DONE, completedAt is cleared.
reorder(orgId, taskIds)
Accepts an ordered array of task IDs. Updates sortOrder for each task to reflect the new order. Used for drag-and-drop reordering in the Hub.
reprioritize(orgId, changes)
Applies AI-driven priority and sort order changes to multiple tasks in one call. Each change specifies:
{
taskId: string;
priority?: TaskPriority;
sortOrder?: number;
reason: string; // required — why the AI changed the priority
}Changes are applied sequentially via individual repository updates.
seedOnboardingTasks(orgId, userId, workspaceId?)
Creates 6 sample tasks to demonstrate the workspace functionality during onboarding. Called by POST /tasks/seed. These are created unassigned, so — per the visibility rule above — they're only visible to whoever triggered the seed, not to other org members, until assigned.
Task Status & Priority
TaskStatus
| Value | Description |
|---|---|
TODO | Not started |
IN_PROGRESS | Being worked on |
DONE | Completed (sets completedAt) |
CANCELLED | Cancelled (does not set completedAt) |
TaskPriority
| Value | Description |
|---|---|
LOW | Low urgency |
MEDIUM | Default priority |
HIGH | High urgency |
URGENT | Needs immediate attention |
Unassigned Tasks
Tasks with assigneeId = null are private to their creator (see Visibility above) until assigned. The Hub's task filter has an Unassigned view for these — it shows only the current user's own not-yet-assigned tasks, not every unassigned task in the org.