Server Actions

Last updated on 2026-09-07

Every mutation in the kit uses Next.js Server Actions. They run server-side, use the Supabase server client for reads and writes, and call revalidatePath() to refresh page data.

Architecture

Client Component --> Server Action --> Supabase Client --> Database
                                   --> revalidatePath() --> Page Refresh

All Server Actions are in lib/actions/ and marked with "use server" at the top of each file.

Auth Actions (lib/actions/auth.ts)

Action Parameters Description
signIn email, password Sign in with email/password
signUp email, password, fullName Create account; sets full_name in user metadata
signOut -- Clear session and redirect to /login
resetPassword email Send password reset email with redirect to /settings/password
updatePassword newPassword Update password for authenticated user
signInWithProvider provider ("google" or "github") Redirect to OAuth provider via Supabase Auth

Project Actions (lib/actions/projects.ts)

Action Parameters Description
getProjects -- All projects ordered by created_at desc
getProject id Single project by ID
getProjectMembers projectId Team members linked via project_members join table
createProject name, prefix, emoji?, color?, description?, status?, default_view?, lead_id?, features? Create project; maps features object to feat_cycles, feat_modules, etc. columns
updateProject id, data Update project details and feature flags
deleteProject id Delete project (cascades to tasks, cycles, modules, pages)
addProjectMember projectId, memberId Insert into project_members junction table
removeProjectMember projectId, memberId Delete from project_members junction table

Task Actions (lib/actions/tasks.ts)

Action Parameters Description
getTasks filters (status?, priority?, assigneeId?, projectId?, cycleId?, moduleId?, limit?, offset?) Paginated tasks with subtask joins and count
getTask id Single task with subtasks and comments (parallel queries)
getTasksByProject projectId All tasks for a project with subtasks
getTasksByAssignee assigneeId Open tasks for a user, ordered by priority then due_date
createTask project_id, title, description?, status?, priority?, assignee_id?, labels?, due_date?, start_date?, cycle_id?, module_id?, estimate?, parent_id? Auto-generates task number; writes to tasks and task_labels
updateTask id, data (title?, description?, status?, priority?, assignee_id?, labels?, due_date?, start_date?, cycle_id?, module_id?, estimate?, parent_id?, project_id?) Update task fields and sync label associations (delete + re-insert)
updateTaskStatus id, status Update only status (used by Kanban drag-and-drop)
deleteTask id Fetch project_id first, delete task, revalidate paths
createSubtask taskId, data (title, completed?, assignee_id?, due_date?) Create subtask linked to parent task
updateSubtask id, data (title?, completed?, assignee_id?, due_date?) Update subtask fields
deleteSubtask id Delete subtask
addComment taskId, content Create comment with authenticated user as author
updateComment id, content Update comment content
deleteComment id Delete comment
addTaskLabel taskId, labelId Insert into task_labels junction table
removeTaskLabel taskId, labelId Delete from task_labels junction table
searchTasks query Search tasks by title and description via ilike, limit 50

Cycle Actions (lib/actions/cycles.ts)

Action Parameters Description
getCycles projectId All cycles for a project with task IDs, ordered by start_date desc
getCycle id Single cycle with task IDs
getActiveCycle projectId The active cycle for a project (status = 'Active')
createCycle projectId, name, description?, startDate, endDate Server-side date validation; inserts with status Upcoming, velocity 0
updateCycle id, data (name?, description?, startDate?, endDate?, status?, velocity?, plannedPoints?, completedPoints?) Update cycle fields
deleteCycle id Delete cycle
addTaskToCycle cycleId, taskId Insert into cycle_tasks and set task's cycle_id
removeTaskFromCycle cycleId, taskId Delete from cycle_tasks and null task's cycle_id
completeCycle id Calculate velocity from cycle tasks, update status to Completed with computed points

Module Actions (lib/actions/modules.ts)

Action Parameters Description
getModules projectId All modules for a project with task IDs
getModule id Single module with task IDs
createModule projectId, name, description?, leadId?, startDate?, endDate? Insert with default status Planned
updateModule id, data (name?, description?, leadId?, startDate?, endDate?, status?) Update module fields
deleteModule id Delete module
addTaskToModule moduleId, taskId Insert into module_tasks and set task's module_id
removeTaskFromModule moduleId, taskId Delete from module_tasks and null task's module_id

Goal Actions (lib/actions/goals.ts)

Action Parameters Description
getGoals -- All goals with key results, ordered by due_date
getGoal id Single goal with key results
createGoal title, description?, ownerId, dueDate, status? Insert with default status On Track, progress 0
updateGoal id, data (title?, description?, ownerId?, dueDate?, status?, progress?) Update goal fields
deleteGoal id Delete goal (cascade-deletes key results)
createKeyResult goalId, data (title, target, current?, unit) Insert KR, then recalculate goal progress
updateKeyResult id, data (title?, current?, target?, unit?) Update KR, then recalculate goal progress
deleteKeyResult id Lookup goal_id, delete KR, then recalculate goal progress
recalculateGoalProgress goalId Fetch all KRs, compute average (current/target * 100), update goal.progress

Page Actions (lib/actions/pages.ts)

Action Parameters Description
getPages projectId All pages for a project, ordered by created_at desc
getPage id Single page
createPage projectId, title, content?, parentId? Insert with authenticated user as author
updatePage id, data (title?, content?) Update page title and content
deletePage id Delete page

Label Actions (lib/actions/labels.ts)

Action Parameters Description
getLabels -- All labels ordered by group then name
getLabel id Single label
createLabel name, color, group, description? Insert label with label_group column
updateLabel id, data (name?, color?, group?, description?) Update label fields
deleteLabel id Delete label

View Actions (lib/actions/views.ts)

Action Parameters Description
getSavedViews -- Public views + current user's private views
getSavedView id Single saved view
createSavedView name, description?, icon?, layout, filters?, groupBy?, sortBy?, isPublic? Insert with current user as creator
updateSavedView id, data (name?, description?, icon?, layout?, filters?, groupBy?, sortBy?, isPublic?) Update view fields
deleteSavedView id Delete saved view
togglePinView id Toggle the is_pinned boolean

Team Actions (lib/actions/team.ts)

Action Parameters Description
getTeamMembers -- All profiles ordered by full_name
getTeamMember id Single profile
updateProfile id, data (full_name?, avatar_url?, title?) Update own profile (verifies user owns the profile)
inviteMember email, role Admin-only; sends invite via Supabase Auth admin client
updateMemberRole id, role Admin-only; update member role
deactivateMember id Admin-only; set status to Deactivated (prevents self-deactivation)

Settings Actions (lib/actions/settings.ts)

API Keys

Action Parameters Description
getAPIKeys -- API keys for current user
createAPIKey name Generate key with kpm_ prefix using crypto.randomUUID
deleteAPIKey id Delete API key (scoped to current user)

Webhooks

Action Parameters Description
getWebhooks -- Webhooks for current user
createWebhook url, events[] Insert with status Active
updateWebhook id, data (url?, events?, status?) Update webhook fields
deleteWebhook id Delete webhook

Integrations

Action Parameters Description
getIntegrations -- All integration configs ordered by name
toggleIntegration id Toggle connected boolean; sets last_synced when connecting
updateIntegration id, data (connected?, lastSynced?) Update integration fields

Project Templates

Action Parameters Description
getProjectTemplates -- All templates ordered by category then name
getProjectTemplate id Single template

Notification Preferences

Action Parameters Description
getNotificationPreferences -- Preferences for current user
updateNotificationPreference id, data (inApp?, email?, slack?) Update notification channels

Analytics Actions (lib/actions/analytics.ts)

Action Parameters Description
getDashboardStats -- Aggregate counts: total, completed, in-progress, overdue tasks, projects, members
getDailyMetrics projectId?, days (default 30) Daily created/completed counts from daily_metrics
getBurndownData cycleId Burndown points (ideal, actual, scope) from burndown_points
getVelocityData projectId Planned vs completed per sprint from velocity_points
getCumulativeFlowData projectId, days (default 30) Status counts per day from cumulative_flow_points
getContributionData projectId? Per-member created, completed, avg cycle time from contribution_data
getStatusDistribution projectId? Task count per status (computed from tasks table)
getPriorityDistribution projectId? Task count per priority (computed from tasks table)

Activity Actions (lib/actions/activities.ts)

Action Parameters Description
getActivities projectId?, limit (default 50), offset (default 0) Paginated activities with profile joins
getRecentActivities limit (default 20) Latest activities with profile joins
createActivity type, entityType, entityId, entityTitle, projectId?, metadata? Log activity with authenticated user

Automation Actions (lib/actions/automations.ts)

Action Parameters Description
getAutomationRules projectId All rules for a project
getAutomationRule id Single rule
createAutomationRule projectId, name, trigger, condition?, action Insert with enabled: true
updateAutomationRule id, data (name?, trigger?, condition?, action?, enabled?) Update rule fields
deleteAutomationRule id Delete rule
toggleAutomationRule id Toggle the enabled boolean

Milestone Actions (lib/actions/milestones.ts)

Action Parameters Description
getMilestones projectId All milestones for a project, ordered by date
createMilestone projectId, name, date Insert with completed: false
updateMilestone id, data (name?, date?, completed?) Update milestone fields
deleteMilestone id Delete milestone
toggleMilestoneComplete id Toggle the completed boolean

Notification Actions (lib/actions/notifications.ts)

Action Parameters Description
getNotifications -- All notifications for current user, ordered by created_at desc
getUnreadCount -- Count of unread notifications for current user
markAsRead id Set read: true on single notification
markAllAsRead -- Set read: true on all unread notifications for current user
deleteNotification id Delete notification

Error Handling Pattern

All Server Actions follow the same pattern:

"use server"

import { createClient } from "@/lib/supabase/server"
import { revalidatePath } from "next/cache"

export async function updateTaskStatus(id: string, status: string) {
  try {
    const supabase = await createClient()

    const { data: task, error } = await supabase
      .from("tasks")
      .update({ status } as never)
      .eq("id", id)
      .select("*, subtasks(*)")
      .single()

    if (error) {
      return { error: error.message, data: null }
    }

    revalidatePath("/tasks")
    if (task && task.project_id) {
      revalidatePath(`/projects/${task.project_id}`)
    }
    return { error: null, data: mapTask(task) }
  } catch (e) {
    return { error: (e as Error).message, data: null }
  }
}

Using Server Actions in Components

"use client"

import { updateTaskStatus } from "@/lib/actions/tasks"
import { toast } from "sonner"

function onDragEnd(result: DropResult) {
  // Optimistic UI update first
  setColumns(prev => { /* ... */ })

  // Then persist to database
  toast.success(`Moved "${movedTask.title}" to ${destStatus}`)
  void updateTaskStatus(movedTask.id, destStatus).then(result => {
    if (result.error) {
      toast.error(result.error)
    }
  })
}

Supabase Client Selection

Context Client RLS
Dashboard reads (all project data) Server client Yes (user session)
Analytics aggregates Server client Yes (user session)
Write operations (create, update) Server client Yes (user session)
Delete operations Server client Yes (user session)
Auth operations Server client N/A (Supabase Auth API)
Admin operations (invite, role change) Admin client Bypassed (service role)
Notifications (own only) Server client Yes (user session)

The admin client (lib/supabase/admin.ts) uses SUPABASE_SERVICE_ROLE_KEY and is only used for admin team operations (inviting members, changing roles). It should never be exposed to the client.