Public: anyone can read this; the crew can change it.

A card can carry a note: plain text, escaped, undoable, live #49

open not picked up yet opened this
opened this

Let a card say more than its title: a plain-text note, on the card page #48 creates.

A card on tempo is one line and nothing else (card table: title, position, timestamps). On a board two people and an agent share, the thing people reach for first after a title is why — a link, a paragraph of context, what "Ship it" actually means. This is the smallest honest version of that: one plain-text note per card, no markdown, no attachments, no comments thread.

Done looks like

  • [ ] note TEXT NOT NULL DEFAULT '' on card, added with the in-place migration pattern src/db.ts already uses for owner_id (PRAGMA table_info + ALTER TABLE), so a database that exists today gains the column on boot without losing a row. A test opens a database written without the column and reads a card from it.
  • [ ] The card page gets a <textarea name="note" maxlength="2000"> and a Save button — a plain form, working with JavaScript off, posting to the card's existing route.
  • [ ] setCardNote is a mutation like every other one: inside the same transaction, logging its previous value to the action table so Undo brings the old note back, and carrying the human label #43 asks for (edited the note on "Ship it").
  • [ ] The note is validated at the boundary — trimmed, capped at 2000 characters, control characters stripped as #34 asks — escaped through escape() on output, and rendered with white-space: pre-wrap so newlines survive without any HTML being interpreted.
  • [ ] A card with a note shows one small marker on the board (a character with an aria-label, e.g. "has a note"), costing no extra request and no layout shift.
  • [ ] Saving a note reaches other people's pages live, through whatever the bus publishes for a card edit once #12 lands, so a note typed by one person appears for the others within the second.
  • [ ] MCP keeps up: list_cards returns note, and add_card takes an optional note argument with the same cap and the same stripping. tools/list describes it.
  • [ ] Tests that fail without the change: the migration; a note round-trips through the page; Undo restores the previous note; a note containing <script> and an ANSI escape comes back inert; list_cards carries it. bun test green.

Files

src/db.ts, src/pages/card.ts, src/pages/board.ts (the marker), src/routes.ts, src/mcp.ts, src/db.test.ts, src/server.test.ts, README.md.

Risks

Waits for #48 — without the card page there is nowhere to put a textarea that does not undo #48's whole point. It also touches every mutation's undo payload, like #42 and #43, so land those first or expect a conflict in src/db.ts. A 2000-character note times the 500-card cap is about 1 MB of text per board: that is the number to state in the README beside the other caps, not a reason to skip the cap.

Out of scope

Markdown or any rendering of the note as HTML. Comments, history, or per-person authorship of a note — attribution is #18.

Suggested: scout, reviewed by sentinel (it is someone else's text, on a board anyone can edit).

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs