Review: Update board API to use board notes instead of boards table
Verdict: READY
Re-review after architectural decisions posted in comment #6640. All three NEEDS_REFINEMENT blockers resolved.
Template Completeness
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
File Targets
- [x]
src/pal_e_docs/routes/boards.py— verified: exists, 636 lines, 14 @router endpoints._board_to_out(line 26) and_item_to_out(line 46) are the core rewrite targets. - [x]
src/pal_e_docs/schemas.py— verified:BoardOutat line 269,BoardItemOutat line 243. Additive fields (note_idon BoardOut,board_note_idon BoardItemOut) are straightforward schema additions. - [x]
src/pal_e_docs/routes/notes.py— correctly listed as do-not-touch - [x]
src/pal_e_docs/models.py— correctly listed as do-not-touch;BoardItem.board_note_idFK confirmed at line 259 with relationship at line 282 - [x]
scripts/migrate_boards_to_notes.py— verified: exists, prerequisite documented in Decision 2
Repo Placement
OK — issue filed on forgejo_admin/pal-e-docs, which owns boards.py and schemas.py. Single-repo change.
Decisions Resolved
| # | Blocker | Decision | Verified |
|---|---|---|---|
| 1 | Unresolved architecture (keep routes vs. alias) | Keep all 14 <code>/boards/{slug}</code> routes at same URLs, query <code>notes WHERE note_type='board'</code> internally. Boards table stays during this ticket; removal is #199. | Sound — all 14 endpoints confirmed in boards.py, no route changes needed. Clean separation from #199. |
| 2 | Migration script prerequisite undocumented | Agent must document prerequisite in PR body. Code must handle NULL board_note_id gracefully (log warning, skip). Deploy order: run script then deploy. | Sound — <code>scripts/migrate_boards_to_notes.py</code> exists. NULL handling is a safety net the agent can implement in <code>_item_to_out</code> and query filters. |
| 3 | Response contract ambiguous (board_id/note_id) | Additive: BoardOut gains <code>note_id</code> (board note ID), existing <code>id</code> stays (boards table ID). BoardItemOut keeps <code>board_id</code>, gains <code>board_note_id</code>. All existing fields preserved. Final cleanup deferred to #199. | Sound — test suite (1010 lines) does not assert <code>board_id</code> on BoardItemOut responses. Additive fields won't break existing tests or consumers (SDK, MCP, frontend). |
Dependencies
- #195 (Add board to NoteType) — board item #314, column: done. Prerequisite satisfied. Confirmed:
"board"exists in schemas.py NoteType literal (line 23). - #196 (Add board_note_id FK) — board item #315, column: done. Prerequisite satisfied. Confirmed: FK at models.py line 259.
- Migration script —
scripts/migrate_boards_to_notes.pyexists, must run before deploy. Decision 2 documents this. - #198 (MCP/SDK/hooks update) — board item #317, backlog, position 3. Downstream of this ticket. Correctly sequenced.
- #199 (Drop legacy boards table) — board item #318, backlog, position 4. Final cleanup. Correctly sequenced.
- #208 (Refactor sync_board) — board item #327, backlog. Independent concern (plan discovery from notes vs. board items). No ordering conflict with this ticket.
Acceptance Criteria
Updated acceptance criteria from comment #6640 are sufficient for agent execution:
- [x] GET /boards returns notes where note_type="board" internally, same response shape + note_id — testable
- [x] GET /boards/{slug}/items queries via board_note_id, same response shape + board_note_id — testable
- [x] All 14 endpoints work — now backed by the specific architecture decision (keep routes, query notes internally)
- [x] sync_board works with board_note_id path — testable
- [x] NULL board_note_id handled gracefully — testable (create board item without migration, verify warning not crash)
- [x] PR documents migration prerequisite — verifiable in PR body
Optional (non-blocking): Cross-board endpoints (GET /boards/backlog/items, GET /boards/activity) still join Board→Project. The agent should switch these joins to Note→Project via board_note_id. This is implicit in "all 14 endpoints work" but could be called out explicitly. Not a blocker — the agent will encounter these joins when rewriting.
Blast Radius
- Test suite — 1010 lines, 40+ test functions. No direct assertions on
board_idin response payloads. Additive schema change (new fields, existing preserved) minimizes breakage risk. Tests create boards via POST /boards; the create endpoint must produce both a Note and a Board row during transition. - SDK/MCP/frontend — downstream consumers unaware of board_note_id. Additive response contract means zero breakage. Full consumer update deferred to #198.
- sync_board / sync_issues — both currently query
Board.id. Must switch to board_note_id-based lookups. Covered by "all 14 endpoints." - _board_to_out / _item_to_out helpers — core rewrite targets. Agent will need to map Note fields to BoardOut (note.id→note_id, board.id→id, note.slug→slug) and add board_note_id to BoardItemOut. Straightforward from Decision 3.
Recommendation
No action needed — ticket is READY for agent execution. All three blockers resolved with clear, verifiable decisions. The issue body should ideally be updated to incorporate the decisions from comment #6640, but the agent can read both issue body and comments, so this is not a blocker.
One optional improvement: explicitly call out cross-board endpoints (backlog/items, activity) in acceptance criteria. The agent will discover these during implementation regardless.