diff --git a/.planning/phases/16-tablo-detail/16-REVIEW.md b/.planning/phases/16-tablo-detail/16-REVIEW.md new file mode 100644 index 0000000..82ed8da --- /dev/null +++ b/.planning/phases/16-tablo-detail/16-REVIEW.md @@ -0,0 +1,259 @@ +--- +phase: 16-tablo-detail +reviewed: 2026-05-16T00:00:00Z +depth: standard +files_reviewed: 5 +files_reviewed_list: + - internal/web/handlers/tasks.go + - internal/web/ui/app.css + - internal/web/ui/icon_button.templ + - internal/web/views/tablos.templ + - internal/web/views/tasks.templ +findings: + critical: 3 + warning: 4 + info: 3 + total: 10 +status: issues_found +--- + +# Phase 16: Code Review Report + +**Reviewed:** 2026-05-16 +**Depth:** standard +**Files Reviewed:** 5 +**Status:** issues_found + +## Summary + +Reviewed the phase 16 restyling of the tablo detail view — the tasks handler, CSS, icon button component, tablos list template, and tasks kanban template. The core styling work is solid and uses CSS variables consistently. However, three blocking issues were found: unsafe bare type assertions that will panic if the repository interface is not satisfied, a `renderTaskEditForm` function producing a form with no `action`/HTMX attributes (submit does nothing), and a HTMX swap target mismatch in the task edit modal. Four warnings cover hardcoded hex colors in the `tabloStatusPresentation` function, a hardcoded personal name in production logic, HTMX delete actions missing a confirm dialog, and overdue tasks being silently bucketed to the first date bucket rather than "sans-date" in the roadmap view. + +--- + +## Critical Issues + +### CR-01: Bare type assertion panics in `PostTasks`, `GetEditTaskModal`, and `PatchTask` + +**File:** `internal/web/handlers/tasks.go:113` +**Issue:** After checking `h.repo.(taskMutationRepository)` with an `ok` guard on lines 101, 150, and 202, the same handlers turn around and call `h.repo.(taskPageRepository)` without an `ok` guard on lines 113, 171, and 224. If the concrete repository type satisfies `taskMutationRepository` but not `taskPageRepository` (possible in any future refactor or test double scenario), the assertion panics and kills the server process with no 500 response. + +```go +// lines 101-113 in PostTasks — repo is checked, but taskPageRepository is not: +repo, ok := h.repo.(taskMutationRepository) +if !ok { + http.Error(w, "tasks repository not configured", http.StatusInternalServerError) + return +} +// ... +taskRecords, err := h.repo.(taskPageRepository).ListTasksByOwner(r.Context(), user.ID) // PANICS if not satisfied +``` + +**Fix:** Apply the same two-value assertion pattern used for `taskMutationRepository`: + +```go +taskRepo, ok := h.repo.(taskPageRepository) +if !ok { + http.Error(w, "tasks repository not configured", http.StatusInternalServerError) + return +} +taskRecords, err := taskRepo.ListTasksByOwner(r.Context(), user.ID) +``` + +Apply this fix in `PostTasks` (line 113), `GetEditTaskModal` (line 171), and `PatchTask` (line 224). + +--- + +### CR-02: `renderTaskEditForm` produces a form with no submit action + +**File:** `internal/web/handlers/tasks.go:503` +**Issue:** The raw-HTML builder `renderTaskEditForm` constructs a `