Skip to content

feat(analytics): explicit Column.isDone flag#66

Merged
Musiker15 merged 1 commit into
mainfrom
feat/column-is-done
May 28, 2026
Merged

feat(analytics): explicit Column.isDone flag#66
Musiker15 merged 1 commit into
mainfrom
feat/column-is-done

Conversation

@Musiker15
Copy link
Copy Markdown
Member

Summary

Replaces the analytics "last column by position = done" heuristic with an explicit, user-pinnable Column.isDone flag. The heuristic silently skewed cycle time / lead time / throughput / CFD on any board that didn't end in a Done/Closed column (e.g. a trailing "Blocked" parking lot).

Closes the Column.isDone item from the v0.2.0-beta Deferred list.

Why no ADR

Column.isDone is a plain server-visible boolean, semantically identical to the existing Column.position / Column.wipLimit fields (neither of which has an ADR). It introduces no new threat-model surface — the server already sees column ordering and WIP limits. The behavioural change (heuristic → flag) is documented inline + in the CHANGELOG.

Changes

  • Schema: Column.isDone Boolean @default(false) + hand-written migration 20260528000000_column_is_done (ALTER TABLE … ADD COLUMN … DEFAULT false).
  • Repository / API: Columns.create + Columns.update accept isDone; POST /api/boards/[id]/columns and PATCH /api/columns/[id] validate it; ColumnDto carries it.
  • UI (kanban-view.tsx): a ✓ toggle in each column header (aria-pressed, descriptive title) plus a DONE badge when flagged. Optimistic flip in board-client.tsx with revert-on-failure. New boards seed the default "Done" column with the flag on.
  • Analytics: extracted selectDoneColumnIds into src/lib/analytics/done-columns.ts (pure, dependency-free). Prefers flagged columns; falls back to the legacy last-column heuristic only when nothing is flagged — so existing boards keep working without a data backfill.

Backward compatibility

Existing boards have isDone = false everywhere after the migration → the fallback keeps their analytics identical to today. The moment a user flags a column, the explicit set takes over.

Tests

tests/unit/done-columns.test.ts — 5 cases (empty, flagged set, flag overrides positional fallback, last-column fallback, fallback respects position not array order). pnpm typecheck + pnpm lint clean.

Test plan

  • CI green (incl. the migration applying cleanly on a fresh DB)
  • Manual: toggle a non-last column as Done, open Analytics, confirm Throughput / Cycle Time count cards entering that column
  • Manual: a fresh board's "Done" column shows the DONE badge by default
  • Manual: an old board with no flag still computes analytics off the last column

🤖 Generated with Claude Code

Replaces the analytics "last column by position = done" heuristic with
an explicit, user-pinnable `Column.isDone` flag. The heuristic was a
soft contract that broke for boards not ending in a Done/Closed column
(e.g. a "Blocked" parking-lot column at the end), silently skewing
cycle time, lead time, throughput and CFD.

- Schema: `Column.isDone Boolean @default(false)` + migration
  `20260528000000_column_is_done`. Plain server-visible boolean like
  `position`/`wipLimit` — no E2EE impact.
- Repository + API: create/update accept `isDone`; column DTO carries it.
- UI: ✓ toggle in the column header (`aria-pressed`) + a `DONE` badge.
  New boards seed the default "Done" column with the flag on.
- Analytics: `selectDoneColumnIds` (new pure helper in
  `src/lib/analytics/done-columns.ts`) prefers flagged columns and
  only falls back to the last-column heuristic when nothing is flagged,
  so pre-existing boards keep working without a backfill.

Tests: `done-columns` (5 cases). CLAUDE.md schema + CHANGELOG updated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Signed-off-by: Moritz Kohm <moritz.kohm@gmail.com>
Signed-off-by: Musiker15 <info@musiker15.de>
@Musiker15 Musiker15 merged commit e6f860a into main May 28, 2026
8 checks passed
@Musiker15 Musiker15 deleted the feat/column-is-done branch May 28, 2026 15:17
@Musiker15 Musiker15 mentioned this pull request May 28, 2026
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant