Skip to content

web(board): group a board by a DATE field — week/month/quarter/year columns (#307) - #332

Merged
ikrasovytskyi merged 1 commit into
mainfrom
web/307-date-boards
Aug 12, 2026
Merged

web(board): group a board by a DATE field — week/month/quarter/year columns (#307)#332
ikrasovytskyi merged 1 commit into
mainfrom
web/307-date-boards

Conversation

@ikrasovytskyi

Copy link
Copy Markdown
Contributor

Closes #307 (the roadmap slice of #225).

What it does

Group a board by a date field → one column per period, chronologically. Drag a
card into a column → the record's date moves to that period. That's the
difference between a roadmap and a report; the original ticket calls the read-only
workaround "a poop solution".

The design

date-buckets.ts keeps three operations in one module so they can never disagree:

dateBucketKey   '2026-08-12' → '2026-Q3'      (which column)
bucketLabel     '2026-Q3'    → 'Q3 2026'      (what it says)
bucketStartISO  '2026-Q3'    → '2026-07-01'   (what a drop writes)

The load-bearing property is the round trip — the value a drop writes must
re-bucket into the column it was dropped into, otherwise a card jumps columns the
instant you release it. Asserted across all four granularities and several dates
including year boundaries.

Two other decisions worth flagging:

  • Columns come from the data, not a min→max range. Two records three years apart
    must not emit 36 empty month columns. Tested.
  • All arithmetic is UTC, matching dateDayKey's existing convention — otherwise
    two people in different timezones see the same card in different columns.
  • Week buckets are keyed by their Monday, which sidesteps ISO week-53 edge cases
    entirely and makes the key directly convertible back to a date. 2026-01-01 (a
    Thursday) correctly buckets to the week starting 2025-12-29.

Widened together, in one commit

canGroupBoardBy + boardGroupDisabledReason (web) and boardGroupError (API)
— per docs/architecture/field-surfaces.md, a picker that offers what the renderer
or the server refuses is the bug. The multi-value rejections are untouched and
still tested: a date is single-valued, so the rule they enforce still holds.

group_by_granularity joins the view config, defaulting to month so a legacy or
half-configured board still renders. The toolbar shows the period picker only when a
board is actually grouped by a date.

Two existing tests failed — on purpose

rejects date and date says "not built yet" both broke when date became
groupable. That's the suite doing its job. Both are updated to the new truth,
not deleted, and the old expectation is noted in a comment so the change is legible.

Verification

  • 16 new bucket unit tests, 4 new server tests.
  • Web 507 passed / 36 files; API 1828 passed / 187 files (only
    backup-restore.test.ts fails — needs Docker, documented in CLAUDE.md).
  • pnpm lint, pnpm typecheck, pnpm build green; pnpm sdk:generate drift committed.
  • Not browser-verified (no jsdom). Worth confirming: board grouped by a date, switch
    the period picker, drag a card between columns and check the date field updated.

Not included (rest of #225)

Number bins, and text/lookup/formula grouping. The picker already says so in the
user's own words — "number grouping (into bins) is not built yet".

🤖 Generated with Claude Code

…olumns (#307)

A board can now be a roadmap. Grouping by a date field produces one column per
period, and dragging a card into a column moves the record's date.

New `date-buckets.ts` holds the three operations together — key, label, and the
value a drag writes back — so they can't disagree:

  dateBucketKey   '2026-08-12' → '2026-Q3'
  bucketLabel     '2026-Q3'    → 'Q3 2026'
  bucketStartISO  '2026-Q3'    → '2026-07-01'

The load-bearing property is the round trip: the date a drop writes must re-bucket
into the column it was dropped in, or a card would jump columns the moment you
released it. That's asserted across all four granularities.

Columns are derived from the DATA, not from a min/max range: two records three
years apart must not emit 36 empty month columns. All arithmetic is UTC, matching
`dateDayKey`'s existing convention, so two people in different timezones never see
a card in different columns.

Widened together, in this one commit, as the convention requires:
  canGroupBoardBy + boardGroupDisabledReason (web) and boardGroupError (API)
The multi-value rejections are untouched and still tested — a date is single-valued,
so the rule this all enforces still holds.

`group_by_granularity` joins the view config (month default, so a legacy or
half-configured board still renders). Toolbar shows the period picker only when a
board is actually grouped by a date.

Note: two pre-existing assertions FAILED when date became groupable — "rejects
date" and "date says not built yet". That's the tests doing their job; both are
updated to the new truth rather than deleted.

Verified: 16 new bucket tests + 4 new server tests; web 507 passed / 36 files; API
1828 passed / 187 files (only backup-restore.test.ts fails — needs Docker,
documented); lint, typecheck, build green; SDK regenerated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 12, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
storyos-docs 27ab655 Commit Preview URL

Branch Preview URL
Aug 12 2026, 11:21 PM

@ikrasovytskyi
ikrasovytskyi added this pull request to the merge queue Aug 12, 2026
Merged via the queue into main with commit 5a193fc Aug 12, 2026
4 checks passed
@github-actions
github-actions Bot deleted the web/307-date-boards branch August 12, 2026 23:40
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