# Phase 4: Tasks (Kanban) - Context

**Gathered:** 2026-05-15
**Status:** Ready for planning

<domain>
## Phase Boundary

Inside a tablo, a user can run a kanban board with four fixed columns (todo / in progress / in review / done). Users can create tasks in a column, edit task title and description inline, move tasks between columns via drag-and-drop, reorder tasks within a column, and delete tasks. All mutations are HTMX-driven; ordering persists across refreshes.

Delivers TASK-01..07. **Not** in scope: configurable/user-defined columns (fixed for v1), rich-text task descriptions, task comments, task assignees, due dates, task tags/labels, file attachments on tasks (files attach to tablos in Phase 5), tab navigation on the tablo detail page (added only when Phase 5 files section is integrated).

</domain>

<decisions>
## Implementation Decisions

### Column Architecture
- **D-01:** Fixed 4 columns: `todo`, `in_progress`, `in_review`, `done` — hardcoded as Go constants, no `task_columns` table. No column CRUD routes in this phase. TASK-01's "configurable" option is deferred.
- **D-02:** Column stored on each task row as a Postgres `ENUM` type: `CREATE TYPE task_status AS ENUM ('todo','in_progress','in_review','done')`. Type-safe in the DB; sqlc generates a Go type; invalid values rejected at DB layer. Adding a future status requires `ALTER TYPE task_status ADD VALUE` (safe, non-blocking migration).
- **D-03:** Hard-delete only — no `deleted_at` column on tasks. Consistent with Phase 3 (D-01). All task delete handlers require inline confirmation before firing (reuse D-07 pattern from Phase 3).

### Task Ordering
- **D-04:** Task position stored as `position INTEGER NOT NULL` on the tasks row. First task in a column = 100, second = 200, gap of 100 between each. Inserting between two tasks uses the midpoint (e.g. 150). When gaps narrow below a threshold (e.g. adjacent positions differ by < 2), a rebalance pass reassigns multiples of 100 for that column. O(n) rebalance is acceptable at v1 task counts.
- **D-05:** Last-write-wins for concurrent edits — documented in code, acceptable for v1 (per TASK-07). No optimistic locking required.

### Move/Reorder Interaction
- **D-06:** Drag-and-drop via **Sortable.js** (standalone ~30KB utility, not a JS framework). Handles both within-column reorder (TASK-05) and cross-column move (TASK-04) via a single draggable surface per column.
- **D-07:** Sortable fires an `end` event on drop. A small inline `<script>` (~5 lines, no module system) reads the new task order from the DOM and fires an `hx-post` to `/tablos/{id}/tasks/reorder` with the new positions array. Server reorders the affected tasks, returns updated column fragment(s). Stays HTMX-first — the inline script is a thin event bridge, not application logic.

### Task Detail UX
- **D-08:** Task editing (TASK-03) uses **inline expand** in the kanban card. Clicking a task card swaps it via HTMX to an editable form showing title + description fields. On save (`POST /tablos/{tablo_id}/tasks/{task_id}`), the form swaps back to the display card with updated values. On cancel, restores the original card without a server round-trip. Same HTMX swap pattern as Phase 3's inline title/description edit (D-06).
- **D-09:** Task creation (TASK-02) uses an **inline form at the bottom of each column**. Clicking `+ Add task` in a column renders a small form (title only for quick capture) at the bottom of that column via HTMX swap. On submit, the new task card appends to the column and the form resets. On cancel, the form disappears. Consistent with Phase 3's inline create pattern (D-05).
- **D-10:** The kanban board is **embedded directly in the tablo detail page** (`GET /tablos/{id}`). No tab navigation yet. The page shows: tablo title/description (inline editable from Phase 3) → kanban board below. Phase 5 will add a files section further below. Tabs can be introduced later if the page becomes crowded.

### Claude's Discretion
- Exact Tailwind styling for task cards (compact vs spacious, shadow depth) — consistent with Phase 3's Card component aesthetic.
- Column header visual treatment (background color, count badge showing tasks per column).
- Whether the Sortable.js drag handle is the full card or a dedicated grip icon.
- HTTP verb for task create and edit: `POST /tablos/{id}/tasks` and `POST /tablos/{id}/tasks/{task_id}` (HTML form compatible).
- Whether position rebalancing happens synchronously in the same transaction as the reorder, or is deferred (sync is simplest for v1).
- Exact threshold for triggering rebalance (planner's call — e.g. when any adjacent gap < 2).

</decisions>

<canonical_refs>
## Canonical References

**Downstream agents MUST read these before planning or implementing.**

### Prior Phase Context (locked decisions that constrain this phase)
- `.planning/phases/03-tablos-crud/03-CONTEXT.md` — D-05 (inline create pattern), D-06 (inline edit pattern), D-07 (inline delete confirmation), D-01 (hard-delete), D-03 (sort by created_at) — all reused or extended in this phase
- `.planning/phases/02-authentication/02-CONTEXT.md` — D-23/D-24 (chi route groups, middleware order), RequireAuth middleware
- `.planning/phases/01-foundation/01-CONTEXT.md` — chi router + templ + sqlc + goose migration conventions

### Requirements
- `.planning/REQUIREMENTS.md` §TASK-01..07 — The 7 task requirements this phase delivers
- `.planning/PROJECT.md` — Core value statement and constraints (HTMX-first, no JS framework, single binary)
- `.planning/ROADMAP.md` §Phase 4 — Success criteria and user-in-loop note

### Codebase Patterns (Go backend)
- `backend/internal/web/router.go` — Router structure, protected group, route ordering convention (static before parametric)
- `backend/internal/web/handlers_tablos.go` — HTMX-aware handler pattern (HX-Request detection, fragment vs full-page response) — reuse verbatim
- `backend/internal/web/ui/` — Existing Card, Button, Badge, CSRFField components
- `backend/templates/` — Base layout, templ component patterns
- `backend/internal/db/queries/tablos.sql` — sqlc query style reference
- `backend/migrations/0003_tablos.sql` — Migration style reference (uuid PK, indexes, enum types)
- `backend/internal/tasks/doc.go` — Placeholder package; Phase 4 implementation lands here

</canonical_refs>

<code_context>
## Existing Code Insights

### Reusable Assets
- `ui.Card`, `ui.Button`, `ui.Badge`, `ui.CSRFField` — available in `backend/internal/web/ui/`. Task cards should use `ui.Card` variant.
- `auth.RequireAuth` middleware — already wraps the tablo route group; task routes nest inside the same group.
- `auth.Authed(ctx)` — extracts `*auth.User` from context for tablo ownership checks (tasks inherit tablo ownership).
- HTMX fragment pattern from Phase 2/3 (`HX-Request` header detection, 200+fragment vs 303+redirect) — reuse verbatim for all task mutations.
- `templates.Layout` — base layout; task views extend it via the tablo detail page.

### Established Patterns
- sqlc queries in `backend/internal/db/queries/<domain>.sql`, generated output in `backend/internal/db/sqlc/`. Phase 4 adds `tasks.sql`.
- Handler constructors return `http.HandlerFunc` with a `TasksDeps` struct (mirrors `TablosDeps` from Phase 3).
- Middleware order is locked (D-24): `RequestID → RealIP → SlogLogger → Recoverer → ResolveSession → csrf.Protect → [route groups]`. Task routes add to the existing `RequireAuth` group.
- goose migrations numbered sequentially: `0004_tasks.sql` is next.
- `templ generate` must run after any `.templ` file change to regenerate `*_templ.go`.
- Static route segments declared BEFORE parametric in chi (Pitfall 1) — e.g. `/tablos/{id}/tasks/new` before `/tablos/{id}/tasks/{task_id}`.

### Integration Points
- `backend/internal/web/router.go` — add task routes inside the existing `RequireAuth` group, nested under `/tablos/{id}/tasks*`.
- `backend/cmd/web/main.go` — pass `TasksDeps` (db pool) to `NewRouter` alongside existing `TablosDeps`.
- `backend/templates/tablos/detail.templ` (or equivalent) — embed the kanban board below the tablo title/description section.
- Sortable.js — loaded via CDN `<script>` tag in the base layout or tablo detail template (no npm required).

</code_context>

<specifics>
## Specific Ideas

- The `task_status` enum uses snake_case values: `todo`, `in_progress`, `in_review`, `done` — matching Go idiomatic constants.
- The reorder endpoint (`POST /tablos/{id}/tasks/reorder`) should accept a JSON body `{ "tasks": [{ "id": "uuid", "position": 150 }] }` or form-encoded array — planner decides encoding based on what HTMX + Sortable.js makes easiest.
- Column headers should show a task count badge (e.g. "In Progress (3)") — derived from the fetched task list, not a separate query.
- TASK-07 ("ordering persists across refreshes") is satisfied by writing `position` to the DB on every reorder — no client-side-only state.

</specifics>

<deferred>
## Deferred Ideas

- **Configurable columns** — user-defined column names and counts, `task_columns` table with CRUD. Deferred to v2 or a later phase. Schema is evolvable (add `task_columns` table, migrate `task_status` enum to FK reference).
- **Tabs on tablo detail (Overview / Tasks / Files)** — tab navigation deferred until Phase 5 adds the files section; revisit then if the page layout needs organization.
- **Task due dates, assignees, labels, comments** — out of v1 scope per PROJECT.md.
- **Rich-text task descriptions** — plain text only in v1; BlockNote/ProseMirror deferred.

</deferred>

---

*Phase: 4-Tasks (Kanban)*
*Context gathered: 2026-05-15*
