The task list supports search, assignee and status filters, sorting, pagination, and the expected loading, empty, and error states.
Project — Task Board
Build a task board with status/priority filters, bulk update, inline status toggle, and create_task RPC.
What You Are Building
A workspace task board where members can create, assign, and track tasks. Tasks have a status, priority, due date, and assignee. Admins can delete tasks. All members can create and update task status. The list supports search, filtering by status and assignee, sorting, and pagination. Bulk status update is available for admins.
- MemberCreate tasks, edit tasks, change status inline, and use the task board as part of daily workflow.
- Admin / OwnerCan do everything members can do, plus permanently delete tasks and manage cleanup actions.
How this product should work
This project should feel like a working queue for a real team, where everyday updates are fast and admin-only cleanup actions are clearly separated.
One shared modal handles add and edit, including assignee, priority, due date, and status rules.
Inline status updates and bulk status changes should both feel immediate and stay in sync with the RPC behavior.
Delete stays admin-only, uses confirmation, and removes the task cleanly without leaving the table in a broken state.
Features to Build
| # | Feature | Est. Time |
|---|---|---|
| 1 | tasks table + RLS + RPC functions |
1h 30m |
| 2 | Task list page (search, filters, sort, pagination) | 1h 30m |
| 3 | Add / Edit task modal (shared form) | 1h 30m |
| 4 | Inline status update (per row) | 30m |
| 5 | Delete task (confirmation, admin only) | 30m |
| 6 | Bulk status update (select + action bar) | 1h |
| 7 | All states + permissions | 30m |
1. Database
tasks Table
| Column | Type | Rules |
|---|---|---|
| id | uuid | PK, default gen_random_uuid() |
| workspace_id | uuid | FK → workspaces.id, ON DELETE CASCADE |
| title | text | NOT NULL, max 200 chars |
| description | text | nullable |
| status | text | NOT NULL, default 'open', one of: 'open', 'in-progress', 'done', 'cancelled' |
| priority | text | NOT NULL, default 'medium', one of: 'low', 'medium', 'high', 'urgent' |
| assignee_id | uuid | FK → auth.users.id, ON DELETE SET NULL, nullable |
| due_date | date | nullable |
| created_by | uuid | FK → auth.users.id, ON DELETE SET NULL |
| created_at | timestamptz | default now() |
| updated_at | timestamptz | default now(), updated by trigger |
Constraints
CHECK (status IN ('open', 'in-progress', 'done', 'cancelled'))
CHECK (priority IN ('low', 'medium', 'high', 'urgent'))
Indexes
CREATE INDEX idx_tasks_workspace_id ON tasks (workspace_id);
CREATE INDEX idx_tasks_status ON tasks (workspace_id, status);
CREATE INDEX idx_tasks_assignee ON tasks (workspace_id, assignee_id);
CREATE INDEX idx_tasks_due_date ON tasks (workspace_id, due_date);
RLS Policies
SELECT: workspace members can view all tasks in their workspace
INSERT: workspace members can insert (created_by set via RLS WITH CHECK)
UPDATE: workspace members can update tasks in their workspace
DELETE: only workspace admins/owners can delete
RPC Functions
create_task — creates a task and writes to audit_logs
Parameters: p_workspace_id uuid, p_title text, p_description text DEFAULT NULL,
p_priority text DEFAULT 'medium', p_assignee_id uuid DEFAULT NULL,
p_due_date date DEFAULT NULL
Validation:
1. Auth check
2. title not blank, max 200 chars
3. priority IN ('low','medium','high','urgent')
4. workspace membership check
5. assignee_id exists in workspace_members if provided
Returns: json — { "data": { task row } }
update_task_status — updates status of one or more tasks atomically
Parameters: p_task_ids uuid[], p_new_status text
Validation:
1. Auth check
2. p_new_status is valid
3. all task_ids exist in the caller's workspace
Returns: json — { "updated_count": N }
Run checklist: New Table · RLS Policies · RPC Function
2. Task List Page
URL: /workspace/{id}/tasks
Requirements
HEADER
[ ] Page title: "Tasks"
[ ] "Add Task" button — visible to all members
SEARCH & FILTERS
[ ] Search input: searches task title — debounced 300ms — sent to Supabase
[ ] Filter: Status — dropdown (All / Open / In Progress / Done / Cancelled)
[ ] Filter: Priority — dropdown (All / Low / Medium / High / Urgent)
[ ] Filter: Assignee — dropdown (All / Me / specific members from backend)
[ ] Active filters shown as chips above the table: "Status: Open ×"
[ ] "Clear all filters" button appears when any filter is active
[ ] All filters sent to Supabase — never client-side array filtering
[ ] Filter state preserved in URL: ?status=open&priority=high&assignee=me
SORT
[ ] Default sort: created_at DESC (newest first)
[ ] Sortable columns: Title, Priority, Due Date, Created At
[ ] Sort state preserved in URL: ?sort=due_date&order=asc
TABLE COLUMNS
[ ] Checkbox (for bulk) · Title · Status badge · Priority badge · Assignee avatar · Due Date · Actions
BADGES
[ ] Status: open=grey, in-progress=blue, done=green, cancelled=grey-strikethrough
[ ] Priority: low=grey, medium=amber, high=orange, urgent=red
PAGINATION
[ ] 25 per page, "Showing X–Y of Z tasks"
[ ] Page state in URL: ?page=2
STATES
[ ] Loading: skeleton rows
[ ] Empty (no tasks): "No tasks yet." + "Add your first task" button
[ ] Empty (filter/search): "No tasks match your filters." + clear button
[ ] Error: "Could not load tasks." + retry
Run checklist: WeWeb Page Build · Search, Filters & Pagination
3. Add / Edit Task Modal
One shared component. Add mode = empty form. Edit mode = pre-filled.
Form Fields
| Field | Type | Rules |
|---|---|---|
| Title | text | Required, max 200 chars |
| Description | textarea | Optional |
| Priority | dropdown | Required, default: Medium |
| Assignee | searchable dropdown | Optional — fetches workspace members |
| Due Date | date picker | Optional, min: today |
| Status | dropdown | Required — visible in Edit mode only |
Behavior
ADD MODE:
[ ] Title: "Add Task" · Submit: "Add Task"
[ ] Status field hidden (always starts as 'open')
[ ] On success: "Task added." toast, list refreshes with new task
EDIT MODE:
[ ] Title: "Edit Task" · Submit: "Save Changes"
[ ] All fields pre-filled from current task data
[ ] Status field visible — can be changed here
[ ] On success: "Changes saved." toast, list refreshes
BOTH MODES:
[ ] Loading state on submit button, all fields disabled during submit
[ ] API error: banner above submit button
[ ] Escape + X close button work
[ ] Focus moves to first field on open
Run checklist: Add/Edit Consistency · Modals & Dialogs
4. Inline Status Update
5. Delete Task (Admin Only)
Title: "Delete Task?"
Body: "'[Task Title]' will be permanently deleted."
Body: "This action cannot be undone."
Buttons: Cancel · "Delete Task" (red)
Run checklist: Delete & Destructive Actions
6. Bulk Status Update
SELECTION
[ ] Checkbox in header: select/deselect all on current page
[ ] Checkbox per row
[ ] Selection count shown: "5 selected"
BULK ACTION BAR
[ ] Appears above table only when rows are selected
[ ] "Change Status:" dropdown (Open / In Progress / Done / Cancelled)
[ ] "Apply to 5 tasks" button — shows count
[ ] "Cancel" button clears selection
BEHAVIOR
[ ] Calls update_task_status RPC with array of selected task IDs
[ ] Loading state on Apply button during operation
[ ] On success: "5 tasks updated." toast, table refreshes, selection cleared
[ ] On error: error banner in action bar, selection preserved
[ ] Bulk action bar visible to all members (not admin-only — status update is allowed for all)
Run checklist: Tables & Data Lists
7. Permissions Summary
| Action | Member | Admin | Owner |
|--------|--------|-------|-------|
| View tasks | ✓ | ✓ | ✓ |
| Add task | ✓ | ✓ | ✓ |
| Edit task | ✓ | ✓ | ✓ |
| Update status (inline + bulk) | ✓ | ✓ | ✓ |
| Delete task | ✗ | ✓ | ✓ |
[ ] Delete button/action hidden for member role — not just disabled
[ ] RLS enforced: member cannot DELETE directly in Supabase
What You Should NOT Do
× Filter tasks client-side — all filters, search, sort go to Supabase
× Make create_task and update_task_status two separate frontend calls — use RPC
× Skip the RPC and do INSERT directly from WeWeb for task creation (no audit log)
× Hardcode status or priority options — use WeWeb variables/constants
× Show a full page spinner when loading — use skeleton rows
× Forget to reset pagination to page 1 when any filter changes
× Show the Delete action to member-role users
× Send p_task_ids to update_task_status as individual calls in a loop (use array)