Summary
PATCH /api/v1/projects/{projectId}/task-statuses/{statusId} accepts and validates a position field, and the domain-layer response reflects the new value correctly — but the change is never persisted. A subsequent GET shows the original, unchanged position. This makes it currently impossible to reorder task statuses via the API at all.
Root cause
In services/api/internal/repository/postgres/task_repository.go, UpdateTaskStatus:
func (r *TaskRepository) UpdateTaskStatus(ctx context.Context, s *taskdom.TaskStatus) error {
_, err := r.db.ExecContext(ctx, `
UPDATE task_statuses SET name=$1, color=$2, category=$3, updated_at=$4 WHERE id=$5`,
s.Name, s.Color, string(s.Category), s.UpdatedAt, s.ID.String(),
)
...
}
The UPDATE statement has no position=$N clause at all. The domain-layer Service.UpdateTaskStatus (in services/task/task_service.go) correctly sets st.Position = *in.Position on the in-memory struct before calling this, and the handler returns that in-memory struct — so the API response looks correct — but the SQL write silently drops the field. A fresh GET afterward shows the original position, unchanged.
Repro:
curl -X PATCH ".../task-statuses/{id}" -d '{"position": 5}'
# response shows "position": 5
curl ".../task-statuses"
# this same status is still at its old position
Related, smaller bug in the same function
services/task/task_service.go, UpdateTaskStatus:
This unconditionally overwrites Color with whatever was in the request, including nil when the field is simply omitted (as opposed to the Name/Position/Category fields just above it, which correctly check for presence first). A position-only update ({"position": 5}, no color key) silently wipes the status's color to null. Likely wants the same "only set if provided" guard the other fields already have.
Impact
Task statuses created via the API (as opposed to the initial seed/migration data) are stuck at whatever position they were created with — there's no way to reorder a Kanban board's columns through the API, since every reorder attempt appears to succeed but never actually persists.
Environment
- Paca: built from
master (opensrc fetch, recent)
- Confirmed via direct read of
task_repository.go, task_service.go, and live API behavior
Filed with the help of Sally Sonnet.
Summary
PATCH /api/v1/projects/{projectId}/task-statuses/{statusId}accepts and validates apositionfield, and the domain-layer response reflects the new value correctly — but the change is never persisted. A subsequentGETshows the original, unchanged position. This makes it currently impossible to reorder task statuses via the API at all.Root cause
In
services/api/internal/repository/postgres/task_repository.go,UpdateTaskStatus:The
UPDATEstatement has noposition=$Nclause at all. The domain-layerService.UpdateTaskStatus(inservices/task/task_service.go) correctly setsst.Position = *in.Positionon the in-memory struct before calling this, and the handler returns that in-memory struct — so the API response looks correct — but the SQL write silently drops the field. A freshGETafterward shows the original position, unchanged.Repro:
Related, smaller bug in the same function
services/task/task_service.go,UpdateTaskStatus:This unconditionally overwrites
Colorwith whatever was in the request, includingnilwhen the field is simply omitted (as opposed to theName/Position/Categoryfields just above it, which correctly check for presence first). A position-only update ({"position": 5}, nocolorkey) silently wipes the status's color to null. Likely wants the same "only set if provided" guard the other fields already have.Impact
Task statuses created via the API (as opposed to the initial seed/migration data) are stuck at whatever
positionthey were created with — there's no way to reorder a Kanban board's columns through the API, since every reorder attempt appears to succeed but never actually persists.Environment
master(opensrcfetch, recent)task_repository.go,task_service.go, and live API behaviorFiled with the help of Sally Sonnet.