Link groups model and grouped card containers #41

Open
opened 2026-06-10 01:38:32 +00:00 by ldraney · 3 comments
Owner

Type

Feature

Lineage

Depends on ldraney/palinks #40 (canvas view with activity-based card sizing).
Related to ldraney/palinks #36 (clicks table) for aggregate group tracking.

Repo

ldraney/palinks

User Story

As a palinks user
I want to group related links into a parent card that contains their individual cards
So that related links stay spatially together on the canvas and I can track their activity as a unit

Context

With the canvas layout in place (#40), links need a grouping mechanism. A link group is a named container that houses multiple link cards. On the canvas, the group renders as a larger parent card with its children arranged inside it. Groups track aggregate click activity (sum of member clicks) for their own sizing. Grouped links always move together — dragging the group card repositions all children.

Groups are optional — links can exist ungrouped on the canvas. A link belongs to at most one group.

File Targets

Files the agent should modify or create:

  • db/migrate/*_create_link_groups.rblink_groups table: name, description, canvas_x, canvas_y, color (optional)
  • db/migrate/*_add_group_id_to_links.rb — add link_group_id foreign key to links
  • app/models/link_group.rb — has_many :links, aggregate click count method, canvas position
  • app/models/link.rb — belongs_to :link_group (optional), scope for ungrouped
  • app/views/links/_link_group.html.erb — group container partial with nested link cards
  • app/views/links/index.html.erb — render groups and ungrouped links on canvas
  • app/javascript/controllers/canvas_controller.js — group drag moves all children, group collapse/expand (file created by #40)
  • app/controllers/link_groups_controller.rb — CRUD for groups, add/remove links
  • config/routes.rb — link_groups resource routes

Files the agent should NOT touch:

  • app/javascript/controllers/sortable_controller.js — legacy grid ordering

Feature Flag

Flag: link_groups
Type: global
Default: disabled
Visibility: superadmin only
Removal: after 2 weeks stable

Acceptance Criteria

  • Can create, rename, and delete link groups
  • Can add/remove links to/from a group via UI
  • Grouped links render inside a parent container card on the canvas
  • Group container size reflects aggregate click activity of its members
  • Dragging a group card moves all child link cards with it
  • Ungrouped links continue to render independently on the canvas
  • A link can belong to at most one group

Test Expectations

  • Unit test: LinkGroup#aggregate_clicks sums member link click counts
  • Unit test: Link scopes for grouped/ungrouped filter correctly
  • Integration test: adding a link to a group persists the association
  • Integration test: deleting a group does not delete its links (orphans them)
  • Run command: bin/rails test

Constraints

  • Groups are a lightweight container — no nested groups (one level only)
  • Group color is optional, defaults to a neutral container style
  • Must work with the canvas_layout flag — groups only render on canvas view
  • Follow existing controller/model patterns in the codebase
  • canvas_controller.js is created by #40 — this ticket extends it, does not create it

Checklist

  • PR opened
  • Tests pass
  • No unrelated changes
  • palinks — project this affects
  • #40 — canvas view (direct dependency, must ship first)
  • #36 — clicks table (transitive dependency via #40)
### Type Feature ### Lineage Depends on `ldraney/palinks #40` (canvas view with activity-based card sizing). Related to `ldraney/palinks #36` (clicks table) for aggregate group tracking. ### Repo `ldraney/palinks` ### User Story As a palinks user I want to group related links into a parent card that contains their individual cards So that related links stay spatially together on the canvas and I can track their activity as a unit ### Context With the canvas layout in place (#40), links need a grouping mechanism. A link group is a named container that houses multiple link cards. On the canvas, the group renders as a larger parent card with its children arranged inside it. Groups track aggregate click activity (sum of member clicks) for their own sizing. Grouped links always move together — dragging the group card repositions all children. Groups are optional — links can exist ungrouped on the canvas. A link belongs to at most one group. ### File Targets Files the agent should modify or create: - `db/migrate/*_create_link_groups.rb` — `link_groups` table: name, description, canvas_x, canvas_y, color (optional) - `db/migrate/*_add_group_id_to_links.rb` — add `link_group_id` foreign key to links - `app/models/link_group.rb` — has_many :links, aggregate click count method, canvas position - `app/models/link.rb` — belongs_to :link_group (optional), scope for ungrouped - `app/views/links/_link_group.html.erb` — group container partial with nested link cards - `app/views/links/index.html.erb` — render groups and ungrouped links on canvas - `app/javascript/controllers/canvas_controller.js` — group drag moves all children, group collapse/expand (file created by #40) - `app/controllers/link_groups_controller.rb` — CRUD for groups, add/remove links - `config/routes.rb` — link_groups resource routes Files the agent should NOT touch: - `app/javascript/controllers/sortable_controller.js` — legacy grid ordering ### Feature Flag Flag: `link_groups` Type: global Default: disabled Visibility: superadmin only Removal: after 2 weeks stable ### Acceptance Criteria - [ ] Can create, rename, and delete link groups - [ ] Can add/remove links to/from a group via UI - [ ] Grouped links render inside a parent container card on the canvas - [ ] Group container size reflects aggregate click activity of its members - [ ] Dragging a group card moves all child link cards with it - [ ] Ungrouped links continue to render independently on the canvas - [ ] A link can belong to at most one group ### Test Expectations - [ ] Unit test: LinkGroup#aggregate_clicks sums member link click counts - [ ] Unit test: Link scopes for grouped/ungrouped filter correctly - [ ] Integration test: adding a link to a group persists the association - [ ] Integration test: deleting a group does not delete its links (orphans them) - Run command: `bin/rails test` ### Constraints - Groups are a lightweight container — no nested groups (one level only) - Group color is optional, defaults to a neutral container style - Must work with the canvas_layout flag — groups only render on canvas view - Follow existing controller/model patterns in the codebase - canvas_controller.js is created by #40 — this ticket extends it, does not create it ### Checklist - [ ] PR opened - [ ] Tests pass - [ ] No unrelated changes ### Related - `palinks` — project this affects - `#40` — canvas view (direct dependency, must ship first) - `#36` — clicks table (transitive dependency via #40)
Author
Owner

Scope Review: NEEDS_REFINEMENT

Review note: review-1407-2026-06-09

Ticket is well-structured with all template sections present, but has unresolved dependency and traceability gaps that prevent advancement.

Issues found:

  • [BODY] Lineage references #39 but the canvas view issue is #40 — fix the reference
  • [SCOPE] story:canvas-layout is not listed in the project-palinks user-stories section — needs entry created
  • [SCOPE] arch-palinks note missing in pal-e-docs (board-wide gap, not unique to this ticket)
  • [SCOPE] Feature flag system is not yet implemented (docs/feature-flags.md confirms "pending implementation") — the link_groups flag cannot be created until the flag infrastructure exists. Add as explicit dependency or defer the flag section.
  • File target gap: canvas_controller.js does not exist yet — created by #40 (canvas view), which is still in backlog
  • [DECOMPOSE] 7 AC + 9 file targets exceeds 5-minute rule. Route to skill-decompose-ticket after dependencies (#36, #40, flag system) land. Suggested split: (1) model/migrations/routes, (2) controller/CRUD, (3) view/canvas integration.
## Scope Review: NEEDS_REFINEMENT Review note: `review-1407-2026-06-09` Ticket is well-structured with all template sections present, but has unresolved dependency and traceability gaps that prevent advancement. **Issues found:** - **[BODY]** Lineage references `#39` but the canvas view issue is `#40` — fix the reference - **[SCOPE]** `story:canvas-layout` is not listed in the project-palinks user-stories section — needs entry created - **[SCOPE]** `arch-palinks` note missing in pal-e-docs (board-wide gap, not unique to this ticket) - **[SCOPE]** Feature flag system is not yet implemented (`docs/feature-flags.md` confirms "pending implementation") — the `link_groups` flag cannot be created until the flag infrastructure exists. Add as explicit dependency or defer the flag section. - **File target gap:** `canvas_controller.js` does not exist yet — created by #40 (canvas view), which is still in backlog - **[DECOMPOSE]** 7 AC + 9 file targets exceeds 5-minute rule. Route to `skill-decompose-ticket` after dependencies (#36, #40, flag system) land. Suggested split: (1) model/migrations/routes, (2) controller/CRUD, (3) view/canvas integration.
Author
Owner

Scope refinement (2026-06-09):

Changes from scope review review-1407-2026-06-09:

  • Fixed lineage: changed #39 to #40 (correct canvas view issue number)
  • Added note in file targets that canvas_controller.js is created by #40, this ticket extends it
  • Added constraint clarifying canvas_controller.js dependency

Acknowledged but not blocking this ticket:

  • story:canvas-layout not yet in project-palinks user-stories — cross-cutting gap
  • arch-palinks note missing — board-wide gap, tracked separately
  • Decomposition suggestion noted — will evaluate after #40 lands since dependencies must ship first anyway
**Scope refinement (2026-06-09):** Changes from scope review `review-1407-2026-06-09`: - Fixed lineage: changed `#39` to `#40` (correct canvas view issue number) - Added note in file targets that `canvas_controller.js` is created by #40, this ticket extends it - Added constraint clarifying canvas_controller.js dependency Acknowledged but not blocking this ticket: - `story:canvas-layout` not yet in project-palinks user-stories — cross-cutting gap - `arch-palinks` note missing — board-wide gap, tracked separately - Decomposition suggestion noted — will evaluate after #40 lands since dependencies must ship first anyway
Author
Owner

Scope Review: APPROVED

Review note: review-1407-2026-06-09-r2

Re-review after refinement. All blocking issues from the previous NEEDS_REFINEMENT review (review-1407-2026-06-09) are resolved:

  • Lineage correctly references #40 (was #39)
  • canvas_controller.js dependency on #40 is explicitly documented in File Targets and Constraints
  • Feature flag section documents target gate design (acceptable as forward-looking)

Remaining non-blocking [SCOPE] items (cross-cutting gaps with established precedent):

  • story:canvas-layout user story entry missing from project-palinks
  • arch-palinks architecture note missing from pal-e-docs

[DECOMPOSE] deferred: when this ticket moves from backlog to todo (after #40 ships), route to skill-decompose-ticket for sub-ticket creation.

## Scope Review: APPROVED Review note: `review-1407-2026-06-09-r2` Re-review after refinement. All blocking issues from the previous NEEDS_REFINEMENT review (`review-1407-2026-06-09`) are resolved: - Lineage correctly references #40 (was #39) - canvas_controller.js dependency on #40 is explicitly documented in File Targets and Constraints - Feature flag section documents target gate design (acceptable as forward-looking) Remaining non-blocking [SCOPE] items (cross-cutting gaps with established precedent): - `story:canvas-layout` user story entry missing from project-palinks - `arch-palinks` architecture note missing from pal-e-docs [DECOMPOSE] deferred: when this ticket moves from backlog to todo (after #40 ships), route to `skill-decompose-ticket` for sub-ticket creation.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ldraney/palinks#41
No description provided.