Boards & Tasks

Last updated on 2026-09-07

The board and task system is the centerpiece of the kit. Tasks live in the tasks table in Supabase and can be viewed through five different layouts -- board, list, calendar, timeline, and backlog. All mutations use Server Actions and every drag-and-drop is persisted to the database.

Kanban Board

Route: /projects/[id]/board

The Kanban board provides a visual, drag-and-drop interface for managing tasks across status columns -- with every drag persisted to Supabase.

  • Drag-and-drop -- powered by @hello-pangea/dnd, task cards can be dragged between columns to update their status
  • Database persistence -- when a card is dropped, the updateTaskStatus Server Action writes the new status to Supabase and revalidatePath() refreshes the page data
  • Six status columns -- Backlog, Todo, In Progress, In Review, Done, and Cancelled, each with a distinct color indicator
  • WIP limits -- Todo (8), In Progress (5), and In Review (3) columns have work-in-progress limits displayed in the column header
  • Task cards -- each card shows the task ID badge (e.g., PRJ-42), title, priority indicator, assignee avatar, due date, label pills, and subtask progress
  • Column totals -- each column header displays the task count
  • Filter popover -- filter tasks by priority (Urgent, High, Medium, Low) and assignee using checkboxes
  • Optimistic UI -- columns update instantly on drag; the Server Action runs in the background
  • Toast notifications -- a success toast confirms the move (e.g., 'Moved "Fix login bug" to In Progress')

Status Columns

Status Color WIP Limit
Backlog #6b7280 (gray) --
Todo #8b5cf6 (violet) 8
In Progress #f59e0b (amber) 5
In Review #3b82f6 (blue) 3
Done #22c55e (green) --
Cancelled #ef4444 (red) --

How Data Flows

1. Server Component fetches tasks from Supabase via getTasksByProject()
2. Passes tasks, members, labels to BoardPageClient
3. BoardPageClient renders KanbanBoard with grouped-by-status columns
4. User drags a card to a new column
5. onDragEnd fires -> optimistic UI update via setColumns()
6. Server Action updateTaskStatus() writes new status to Supabase
7. Toast confirms the move
8. revalidatePath() refreshes server data

Kanban Board Architecture

KanbanBoard (DragDropContext)
├── Filter bar (priority + assignee popover)
├── KanbanColumn (Droppable) x 6 statuses
│   ├── Column header (title, count, WIP limit indicator)
│   ├── KanbanCard (Draggable) x N tasks
│   │   ├── Task ID badge (prefix-number)
│   │   ├── Title
│   │   ├── Priority indicator
│   │   ├── Assignee avatar
│   │   ├── Due date
│   │   ├── Label pills
│   │   └── Subtask progress
│   └── Column footer
└── onDragEnd handler
    ├── Optimistic state update
    ├── Toast notification
    └── Server Action -> Supabase write
// kanban-board.tsx (simplified)
import { DragDropContext, type DropResult } from "@hello-pangea/dnd"
import { updateTaskStatus } from "@/lib/actions/tasks"

function KanbanBoard({ tasks, members, labels, projectPrefix, projectId }: KanbanBoardProps) {
  const [columns, setColumns] = useState(groupTasksByStatus(tasks))

  function onDragEnd(result: DropResult) {
    const { source, destination } = result
    if (!destination) return
    if (source.droppableId === destination.droppableId
        && source.index === destination.index) return

    const sourceStatus = source.droppableId as TaskStatusType
    const destStatus = destination.droppableId as TaskStatusType
    const movedTask = columns[sourceStatus][source.index]

    // Optimistic UI update
    setColumns(prev => {
      const next = { ...prev }
      const sourceTasks = [...prev[sourceStatus]]
      const [moved] = sourceTasks.splice(source.index, 1)
      const updatedTask = { ...moved, status: destStatus }
      const destTasks = [...prev[destStatus]]
      destTasks.splice(destination.index, 0, updatedTask)
      next[sourceStatus] = sourceTasks
      next[destStatus] = destTasks
      return next
    })

    // Persist to database
    toast.success(`Moved "${movedTask.title}" to ${destStatus}`)
    void updateTaskStatus(movedTask.id, destStatus)
  }

  return (
    <DragDropContext onDragEnd={onDragEnd}>
      {COLUMN_ORDER.map(({ status, color, wipLimit }) => (
        <KanbanColumn key={status} id={status} title={status}
          tasks={columns[status]} color={color} wipLimit={wipLimit}
          members={members} labels={labels}
          projectPrefix={projectPrefix} projectId={projectId} />
      ))}
    </DragDropContext>
  )
}

List View

Route: /projects/[id]/list

A tabular view of all tasks in the project, grouped by status, with inline editing and bulk actions.

  • Grouped by status -- tasks are organized under collapsible status group headers
  • Columns -- task ID, title, status select, priority select, assignee, due date, labels
  • Inline editing -- status and priority can be changed via select dropdowns that call updateTask Server Action
  • Bulk actions -- select multiple tasks via checkboxes for batch operations
  • Row actions -- hover to reveal edit, assign, move, and delete actions via a dropdown menu
  • Pagination -- previous/next controls for large task sets
  • Sorting -- sortable column headers

Calendar View

Route: /projects/[id]/calendar

A monthly calendar showing tasks as color-coded pills on their due dates.

  • Monthly grid -- standard calendar layout with navigation (previous/next month)
  • Task pills -- tasks appear as colored pills on their due date, color-coded by priority
  • Today highlight -- the current date cell is visually highlighted
  • Quick create -- click the "+" button on any day to create a task pre-set to that date
  • Task creation -- creates tasks via the createTask Server Action with the selected date as due_date
  • Day cells -- cells for days outside the current month are dimmed

Timeline View

Route: /projects/[id]/timeline

A Gantt-chart-style timeline showing tasks as horizontal bars across a date range.

  • Zoom levels -- switch between day, week, and month granularity
  • Task bars -- horizontal bars spanning from start_date to due_date, color-coded by status
  • Status colors -- Backlog (gray), Todo (violet), In Progress (amber), In Review (blue), Done (green), Cancelled (red)
  • Date headers -- column headers showing the date range at the current zoom level
  • Today marker -- a vertical red line marking the current date

Backlog View

Route: /projects/[id]/backlog

A triage view focused on unscheduled tasks that need to be prioritized and assigned to sprints.

  • Backlog tasks -- tasks not assigned to any cycle, filterable by priority
  • Sprint assignment -- button to move tasks into the active or upcoming cycle via addTaskToCycle Server Action
  • Task table -- tabular format with task ID, title, priority, assignee, due date, and labels
  • Subtask progress -- progress bar showing completed subtasks
  • Summary cards -- KPI cards showing total backlog count, unassigned tasks, and overdue tasks

Task Detail

Route: /projects/[id]/tasks/[taskId]

A comprehensive view of an individual task with breadcrumb navigation, a content area, and a property sidebar.

  • Breadcrumb -- navigates from project name to board to task ID (e.g., PRJ-42)
  • Task ID badge -- monospace badge with the project prefix and task number
  • Title -- heading-styled task title
  • Description -- task description text
  • Subtasks -- rendered via the SubtaskList component, showing each subtask with a checkbox, title, assignee, and due date; toggle completion via updateSubtask Server Action
  • Comments and activity -- rendered via the CommentThread component, showing comments and task activity in chronological order; add comments via addComment Server Action

Task Detail Sidebar

The right sidebar (TaskDetailSidebar) displays and allows editing of task properties:

  • Status -- select dropdown to change status (calls updateTask)
  • Priority -- select dropdown to change priority
  • Assignee -- select dropdown with team member avatars
  • Labels -- multi-select label picker with color indicators
  • Due date -- date picker
  • Start date -- date picker
  • Cycle -- select dropdown to assign to a sprint cycle
  • Module -- select dropdown to assign to a module
  • Estimate -- numeric input for story point estimate

Task CRUD Operations

Operation Server Action Description
Create task createTask Auto-generates next task number per project; writes to tasks and task_labels tables
Read task getTask Fetches task with subtasks and comments via parallel queries
Update task updateTask Updates task fields and syncs label associations
Update status updateTaskStatus Updates only the status field (used by drag-and-drop)
Delete task deleteTask Deletes task and revalidates project path
Create subtask createSubtask Adds subtask linked to parent task
Update subtask updateSubtask Toggle completion or edit title/assignee
Delete subtask deleteSubtask Removes subtask
Add comment addComment Creates comment with authenticated user as author
Update comment updateComment Edits comment content
Delete comment deleteComment Removes comment
Add label addTaskLabel Creates task-label association
Remove label removeTaskLabel Removes task-label association
Search tasks searchTasks Full-text search on title and description via ilike

Data Sources

Data Source How
Tasks tasks table Server Component query with subtask joins
Team members profiles table Via project_members join
Labels labels table Ordered by group and name
Comments task_comments table Filtered by task_id, ordered by created_at
Subtasks subtasks table Joined on tasks via tasks(*, subtasks(*))

Next Steps