build: /spec-feature task-management-ui --requirements 'React UI in studio-u...
Some checks are pending
ci/woodpecker/push/woodpecker Pipeline is pending

This commit is contained in:
rdev-worker 2026-02-11 05:07:32 +00:00
parent 1f5422937f
commit 0c5bab957c
2 changed files with 125 additions and 1 deletions

View File

@ -22,7 +22,7 @@ artifacts:
status: pending status: pending
path: review.md path: review.md
spec: spec:
status: pending status: draft
path: spec.md path: spec.md
tasks: tasks:
status: pending status: pending

View File

@ -0,0 +1,124 @@
# Feature: Task Management UI
## Problem Statement
Users of the Foundary Studio currently have no visual interface for managing tasks. The backend (studio-api) is being built with full Task CRUD endpoints (via the `data-models` feature), but there is no frontend to interact with them. Project teams need a way to visualize task status at a glance, move tasks through workflow stages, create and edit tasks with metadata (labels, assignees), and filter their view to focus on relevant work items.
Without a UI, users would need to interact with raw API endpoints — impractical for day-to-day project management workflows.
## User Stories
- As a **team member**, I want to see all tasks organized by status in a Kanban board so that I can understand the state of work at a glance.
- As a **team member**, I want to drag tasks between columns (To Do, In Progress, Done) so that I can quickly update task status without opening a form.
- As a **team member**, I want to create a new task with title, description, labels, and assignee so that I can capture work items as they arise.
- As a **team member**, I want to edit an existing task's details so that I can keep task information up to date.
- As a **team member**, I want to filter the board by label so that I can focus on a specific category of work (e.g., bugs only).
- As a **team member**, I want to filter the board by assignee so that I can see work assigned to a specific person.
- As a **team member**, I want to delete a task from the edit modal so that I can remove work items that are no longer needed.
## Acceptance Criteria
### Kanban Board View
- [ ] Board displays three columns: **To Do** (status=`open`), **In Progress** (status=`in_progress`), **Done** (status=`done`)
- [ ] Each column shows a count of tasks it contains
- [ ] Tasks are rendered as cards within their respective status column
- [ ] Task cards display: title, priority badge, label badges, and assignee avatar/name
- [ ] Board fetches tasks from `GET /api/studio-api/projects/{projectId}/tasks` on mount
- [ ] Empty columns display a placeholder message (e.g., "No tasks")
### Drag and Drop
- [ ] Tasks can be dragged from one column and dropped into another
- [ ] Dropping a task into a new column fires `PUT /api/studio-api/tasks/{id}` with the new status
- [ ] The board updates optimistically (moves the card immediately, reverts on API error)
- [ ] Visual feedback during drag: dragged card has elevated shadow, drop target column is highlighted
- [ ] Cancelled tasks (status=`cancelled`) are excluded from the board view
### Task Creation
- [ ] A "New Task" button is visible above/beside the board
- [ ] Clicking "New Task" opens a modal/dialog with fields: title (required), description (optional), label (multi-select from existing labels), assignee (select from known users/IDs)
- [ ] Submitting the form calls `POST /api/studio-api/projects/{projectId}/tasks` to create the task
- [ ] After successful creation, the new task appears in the "To Do" column without a full page refresh
- [ ] Validation: title is required (1-200 chars); shows inline error if empty
### Task Editing
- [ ] Clicking a task card opens an edit modal/dialog pre-populated with the task's current data
- [ ] Edit modal includes fields: title, description, status (dropdown), priority (dropdown), labels (multi-select), assignee
- [ ] Saving calls `PUT /api/studio-api/tasks/{id}` with updated fields
- [ ] After successful update, the board reflects changes (card moves columns if status changed)
- [ ] A "Delete" action in the edit modal calls `DELETE /api/studio-api/tasks/{id}` after confirmation
- [ ] Deleting a task removes it from the board without a full page refresh
### Filtering
- [ ] A filter bar is visible above the board
- [ ] Filter by label: dropdown/multi-select populated from `GET /api/studio-api/labels`
- [ ] Filter by assignee: dropdown/input populated from task data or a known user list
- [ ] Filters apply client-side to the fetched task list (no additional API calls)
- [ ] Active filters are visually indicated (e.g., badge count, highlighted filter chip)
- [ ] A "Clear filters" action resets all filters
### Label and Assignee Integration
- [ ] Labels are fetched from `GET /api/studio-api/labels` for the filter and task form dropdowns
- [ ] Labels display with their name and color (color swatch or colored badge)
- [ ] Assignees are attached/detached via `POST/DELETE /api/studio-api/tasks/{taskId}/assignments`
- [ ] Labels are attached/detached via `POST/DELETE /api/studio-api/tasks/{taskId}/labels/{labelId}`
### UI/UX Quality
- [ ] Board is responsive: on small screens, columns stack vertically or become horizontally scrollable
- [ ] All UI uses the existing design system (`@foundary-test-1770784989/ui` components, CSS variables)
- [ ] Loading states shown while data is being fetched (skeleton or spinner)
- [ ] Error states shown when API calls fail (toast or inline alert)
- [ ] Board integrates into the existing `DashboardShell` layout with sidebar navigation
### Routing
- [ ] Board is accessible at a dedicated route (e.g., `/projects/{projectId}/board`)
- [ ] Route is added to the sidebar navigation
- [ ] Uses `react-router-dom` for client-side routing (already installed)
## Technical Constraints
- **Frontend stack**: React 18 + TypeScript + Vite, using `@foundary-test-1770784989/ui` component library (Radix UI primitives + Tailwind CSS)
- **Drag-and-drop**: Requires installing a DnD library (e.g., `@dnd-kit/core` + `@dnd-kit/sortable`) — no DnD library currently installed
- **API client**: Use `@foundary-test-1770784989/api-client` (`createClient`) for all API calls
- **CSS**: Must use CSS custom properties (`var(--*)`) from the design token system — no hardcoded colors
- **Layout**: Must render inside `DashboardShell` with `Sidebar` and `Header` components from `@foundary-test-1770784989/layout`
- **Components**: Use existing `Dialog`, `Button`, `Input`, `Textarea`, `Select`, `Badge`, `Card`, `Alert` from `@foundary-test-1770784989/ui`
- **No state management library**: Use React state + context or hooks for local state; no Redux/Zustand currently in the project
- **Backend dependency**: Requires `data-models` feature to be implemented first (provides the Task, Label, Assignment CRUD endpoints)
- **Task statuses**: Board maps `open` → To Do, `in_progress` → In Progress, `done` → Done. The `cancelled` status exists in the API but is not shown on the board.
- **No pagination**: Backend list endpoints return all records (per data-models spec); client renders all tasks
## Dependencies
- **`data-models` feature** (must be built first): Provides all backend REST endpoints:
- `GET/POST /api/studio-api/projects/{projectId}/tasks` — list/create tasks
- `GET/PUT/DELETE /api/studio-api/tasks/{id}` — read/update/delete task
- `GET /api/studio-api/labels` — list labels
- `POST/DELETE /api/studio-api/tasks/{taskId}/labels/{labelId}` — manage task-label associations
- `POST/DELETE /api/studio-api/tasks/{taskId}/assignments` — manage assignments
- **Project selection**: The board is scoped to a single project. Requires a project to exist and be selected/navigated to.
- **`react-router-dom`** (already installed v6.23.1): For client-side routing
- **DnD library** (to be installed): `@dnd-kit/core` and `@dnd-kit/sortable` recommended for accessible, modern drag-and-drop
- **Existing shared packages**: `@foundary-test-1770784989/ui`, `@foundary-test-1770784989/layout`, `@foundary-test-1770784989/api-client`
## Out of Scope
- **Project CRUD UI** — This feature assumes a project already exists; creating/managing projects is a separate feature
- **User management / user picker** — Assignee field will accept a user ID string; no user directory or avatar service
- **Real-time updates** — No WebSocket/SSE for live board sync across clients
- **Task comments or activity log** — No comment thread or history view on tasks
- **Subtasks or task dependencies** — Flat task list only
- **Task reordering within a column** — Cards within a column are ordered by `created_at`; manual sort order is out of scope
- **Board customization** — Column names and statuses are fixed (To Do / In Progress / Done); no custom columns
- **Bulk operations** — No multi-select, bulk status change, or bulk delete
- **Offline support** — Requires network connectivity
- **Priority filtering** — Only label and assignee filters are in scope; priority filter can be added later
- **Label CRUD UI** — Labels are managed via API; no UI for creating/editing labels in this feature
## Open Questions
1. **Project context**: How does the user select which project's board to view? Is there a project list page, or should the board default to the first/only project? This affects routing and navigation design.
2. **Assignee data source**: Since there is no user directory, where does the assignee dropdown get its options? Options: (a) free-text input for user ID, (b) derive from existing assignments on tasks, (c) hardcoded list for MVP.
3. **DnD library choice**: `@dnd-kit` is recommended for its accessibility and modern API, but `react-beautiful-dnd` is another option. Should we standardize on one?
4. **Optimistic updates vs. refetch**: Should the board use optimistic UI updates (move card immediately, revert on error) or refetch the full task list after each mutation?
5. **State management**: Should task data be managed via React Context (shared across board + modals) or local component state with prop drilling? Adding React Query / TanStack Query for server state caching is another option.
6. **Board URL structure**: Should the route be `/projects/:projectId/board` or `/board?project=:projectId` or something else?