5.5 KiB
5.5 KiB
spec, created, status
| spec | created | status |
|---|---|---|
| docs/specs/tasks/subtask-detachment.md | 2026-07-18 | complete |
Implementation Plan: Subtask detachment
Overview
Add one canonical backend detach operation that atomically clears hierarchy and normalizes inherited workspace policy, then expose it through the shared task-menu surfaces. Backend and frontend implementation can proceed independently after the HTTP contract is fixed; integrated desktop/mobile E2E follows both.
Backend
Canonical service operation
- Add
Service.DetachTask(ctx, taskID)inapps/backend/internal/task/service/service_detachment.go. - Load the task, return roots unchanged, and otherwise clear
ParentIDwhile preserving all unrelated fields. - Copy and normalize
Metadata["workspace"]: change onlymode: "inherit_parent"tomode: "shared_group". - Persist through the task repository, reload repositories for the response, and publish
task.updated. - Update
apps/backend/internal/task/service/service_events.gosoparent_idis always present in task lifecycle payloads, including its cleared value.
HTTP contract and Office parity
- Register
POST /api/v1/tasks/:id/detachinapps/backend/internal/task/handlers/task_handlers.goand implement the handler beside existing task HTTP handlers. - Return the updated task DTO, map missing tasks to
404, and surface persistence errors consistently. - Route the Office dashboard's empty-parent mutation through the canonical detach operation while leaving non-empty reparenting behavior unchanged.
Frontend
API and action state
- Add
detachTask(taskId)toapps/web/lib/api/domains/kanban-api.tsand its barrel export. - Add a focused detach action hook that calls the endpoint, reports failure through the existing toast pattern, and prevents duplicate confirmation submissions.
- Ensure the task mapper/store retains the workspace mode needed to render the shared-workspace warning.
Menus and confirmation
- Add a reusable
TaskDetachConfirmDialogunderapps/web/components/task/with concise hierarchy-only copy and a conditional shared-workspace warning. - Add
Detach from parentwith the existing unlink icon toapps/web/components/task/task-switcher-context-menu.tsxfor single subtasks only. - Thread the action through
TaskSwitcher, desktop sidebar actions, and mobile action presentation. - Add the same entry to
apps/web/components/kanban-card-menu-items.tsx; the shared entry builder keeps card right-click and three-dot menus aligned. - Route the Office parent picker's
No parentselection throughdetachTask; non-empty parent changes continue using the Office update API.
Tests
- Canonical detach: table-driven service tests cover root no-op, ordinary child,
inherit_parent,shared_group, andnew_workspacemodes inapps/backend/internal/task/service/service_detachment_test.go. - Relationship preservation: service tests prove descendants, blockers, repositories, sessions, and workspace-group rows are not mutated by the task-row operation.
- Event clearing: service/event tests assert
task.updated.parent_idis present and empty after detach. - HTTP integration: handler tests exercise success, root idempotency, missing task, and persistence failure.
- Menu visibility: component tests assert the action is present only for a subtask and hidden for root and multi-selection menus.
- Card parity:
apps/web/components/kanban-card-menu-items.test.tsxasserts both menu renderers receive the detach entry and invoke the action. - Mapper/state: frontend tests assert a cleared
parent_idremoves cached nesting and workspace mode is retained for confirmation copy. - Office picker: component tests assert
No parentcalls the detach endpoint while selecting a parent uses the existing update endpoint.
E2E Tests
- Add
apps/web/e2e/tests/task/subtask-detachment.spec.tsfor sidebar right-click, confirmation, live root promotion, card three-dot parity, root-menu absence, and descendant preservation. - Add
apps/web/e2e/tests/task/mobile-subtask-detachment.spec.tsfor the touch-accessible task action and confirmation flow onmobile-chrome. - Seed an inherited-workspace subtask and assert the confirmation warning and post-detach workspace context remain shared.
Implementation Waves
Wave 1 (parallel):
Wave 2:
Verification
From apps/backend:
rtk go test ./internal/task/service ./internal/task/handlers ./internal/office/dashboard
From apps/web:
rtk pnpm test -- components/task/task-switcher.test.tsx components/kanban-card-menu-items.test.tsx components/task/simple/components/parent-picker.test.tsx lib/kanban/map-task.test.ts
rtk pnpm run typecheck
rtk pnpm run lint
rtk pnpm e2e:run e2e/tests/task/subtask-detachment.spec.ts e2e/tests/task/mobile-subtask-detachment.spec.ts
From the repository root after make fmt:
rtk make typecheck
rtk make test
rtk make lint
Risks
- Omitting a cleared
parent_idfrom WebSocket payloads would leave existing clients visually nested until reload. - Leaving
inherit_parentafter clearing the parent would silently provision a separate workspace on a future launch. - Mobile context menus are not assumed to be touch-accessible; the action must be wired through the existing mobile action presentation.