Review: Canvas view with activity-based card sizing
Verdict: APPROVED
Re-review of board item #1406 after refinement. Previous review
review-1406-2026-06-09 returned NEEDS_REFINEMENT with 4 items. All 4 have been addressed.Previous Findings — Resolution
- [x]
story:canvas-layoutnot in user-stories — acknowledged as cross-cutting gap, not blocking. Precedent set by #36 and #41 reviews. Accepted. - [x] Undocumented dependency on #34 (feature_flags) — FIXED. Feature Flag section now says
Flag: none. Canvas ships as default layout; flag gate deferred to when #34 lands. Matches #36's approach. - [x] Missing AC for initial placement — FIXED. Two new ACs added: auto-placement of links with null
canvas_x/canvas_yin a grid pattern, and new links get auto-placed at sensible default. Migration columns specified as nullable. - [x] Pan/zoom underspecified — FIXED. AC now specifies "click-drag on empty background" for pan and "scroll wheel" for zoom. Constraints add "No pinch-to-zoom required (desktop-first)."
Template Completeness
- [x] Type — Feature
- [x] Lineage — depends on #36, prerequisite for #41
- [x] Repo — ldraney/palinks
- [x] User Story
- [x] Context — includes architecture decision (HTML/CSS vs canvas/WebGL)
- [x] File Targets — 6 targets + 1 exclusion
- [x] Feature Flag — "none" with rationale
- [x] Acceptance Criteria — 7 items
- [x] Test Expectations — 4 tests + run command
- [x] Constraints — 6 constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:canvas-layout label — present on board item #1406
- [ ] story note MISSING —
story:canvas-layoutnot listed inproject-palinksuser-stories section. Cross-cutting gap acknowledged in prior reviews (#36, #41). Not blocking per precedent. - [x] arch:palinks label — present on board item
- [ ] arch note MISSING — no
arch-palinksnote exists. Board-wide gap acknowledged in #36 review. Not blocking. - [x] Forgejo issue — ldraney/palinks#40, open
File Targets
- [x]
db/migrate/*_add_canvas_position_to_links.rb— new file to create. Verified nocanvas_x/canvas_ycolumns exist in current schema. Links table hasposition(integer) but no spatial columns. - [x]
app/models/link.rb— verified exists (8 lines). Has position/favorite scopes, no click logic. Correct target forcanvas_scalemethod. - [x]
app/views/links/index.html.erb— verified exists (23 lines). Currently rendersdiv.link-gridwithdata-controller="sortable". Correct target for canvas container replacement. - [x]
app/views/links/_link.html.erb— verified exists (40 lines). Rendersdiv.link-cardwith sortable targets. Correct target for inline position/scale styles. - [x]
app/javascript/controllers/canvas_controller.js— new file to create. Controllers directory exists withsortable_controller.jsas pattern reference. - [x]
app/assets/stylesheets/application.css— verified exists. Has.link-grid(line 142) and.link-cardstyles. Correct target for canvas container styles. - [x] Do NOT touch:
sortable_controller.js— verified exists (230 lines). Correct exclusion.
Repo Placement
Correct. Issue filed on ldraney/palinks, all file targets within the same repo. Single-repo change.
Dependencies
- #36 (clicks table) — currently
in_progresson board-palinks (item #1400). This ticket depends on it for click count data. Dependency is documented in both Lineage and Constraints. #36 must merge first. - #34 (feature_flags) — in
backlog(item #1398). No longer a dependency. Feature Flag section correctly says "none" and ships ungated. Flag gate deferred to when #34 lands. - #41 (link groups) — in
todo(item #1407). Downstream dependency: depends on canvas existing. Not a blocker for this ticket. Correctly documented in Lineage.
Acceptance Criteria
- [x] "Links render on a canvas with absolute positioning instead of a grid" — testable, clear
- [x] "Card size scales proportionally to click count (min scale 0.7, max scale 1.5)" — testable with specific bounds
- [x] "Cards can be dragged to new positions, position persists on reload" — testable via integration test
- [x] "Canvas supports pan (click-drag on empty background) and zoom (scroll wheel)" — testable, interaction methods specified
- [x] "Links with zero clicks render at base size (scale 1.0)" — testable edge case
- [x] "Links with no canvas_x/canvas_y are auto-placed in a grid pattern on first render" — testable, addresses existing-links migration
- [x] "New links get auto-placed at sensible default position" — testable, addresses post-deployment creation
All 7 ACs are verifiable by an agent. Test expectations cover unit tests for scale calculation, nullable columns, and integration tests for drag persistence and auto-placement.
Blast Radius
.link-gridCSS class used in 3 places:application.css(lines 142, 450) andindex.html.erb(line 7). Replacing with canvas container is safe — no other views reference it.sortable_controller.js(230 lines) manages current grid ordering. Correctly excluded. With "Flag: none," the canvas replaces the grid outright — no coexistence concern since the sortable controller just won't be attached to the new DOM.- No clicks table or
click_countreferences exist yet — confirms dependency on #36. - No other services or repos affected. palinks is a standalone Rails app.
Decomposition Assessment
6 file targets in 1 repo, 7 acceptance criteria. At the boundary of the 5-minute thresholds but all targets are tightly coupled in a single feature unit: migration + model method + view changes + Stimulus controller + CSS. Natural cohesion. No decomposition needed.
Recommendation
No action needed. All previous NEEDS_REFINEMENT items resolved. Scope is solid.