Complete project item operations and render stored-field boards #81

Closed AtlantisPleb opened this 23h ago 1 comment

Outcome

Let users add, remove, move, reorder, and group project items while the board renders the project's stored fields instead of hard-coded columns.

Current behavior

The API can add an issue and merge item values. It cannot remove or reorder items, and boards do not yet treat stored Status options as the rendering authority.

Source: docs/2026-08-21-issues-projects-work-system-assessment.md, tracks C5 and C6.

Contract

  • Add remove, move, and reorder operations with stable positions and idempotency.
  • Define duplicate project membership and cross-repository source behavior.
  • Render board columns from the project's stored Status field and option order.
  • Reject unknown or stale option identifiers.
  • Preserve the canonical issue across project views.
  • Emit actor-attributed activity and LiveView updates for every item mutation.
  • Support keyboard, screen-reader, responsive, empty, loading, and conflict states.

Acceptance criteria

  • A user can complete the full item lifecycle through web and API.
  • Two concurrent moves settle to a defined order without losing an item.
  • Changing stored status options updates the board projection predictably.
  • Cross-repository items preserve source authority and never leak private metadata.
  • Connected project views update without a manual reload.

Verification

Cover item lifecycle, duplicate membership, ordering races, field changes, authorization, cross-repository visibility, LiveView behavior, and accessibility. Run mix precommit.

Dependencies

Depends on #9, #39, and the project lifecycle and field-validation issue.

  1. AtlantisPleb opened this issue 23h ago
  2. A AtlantisPleb Author 5h ago

    Shipped in b0b9932 on main.

    Item operations

    • DELETE /repos/{owner}/{repo}/projectsV2/{n}/items/{item_id} removes an item and keeps the issue. A second DELETE returns 404.
    • POST /repos/{owner}/{repo}/projectsV2/{n}/items/{item_id}/move takes values (merged the way PATCH merges them) and position, a one-based rank within the destination column. Only position is a reorder; only values appends to the named column.
    • POST .../items for an issue the board already carries now returns 200 with the membership it already has instead of 422. The same issue still sits on any number of boards.
    • Item order is a stored position, dense and one-based after every move, backfilled in id order so existing boards read unchanged.

    Ordering races. A move takes a row lock on the project, reads the whole board inside it, splices the card into the requested order, and renumbers the result. Two moves onto the same rank settle to one defined order and neither loses a card. A move that changes nothing appends no event and announces nothing.

    Stored-field boards. Columns are the options of the project's promise_state field if it declares one, otherwise a single_select field named Status, otherwise the three defaults. A column carries the option identifier and the label separately, so a relabel renames the heading and leaves every card in place. A card whose stored value the field no longer offers renders in a No status column that exists only while something is in it.

    Stream names stay atoms without String.to_atom/1 on stored data: columns map to a compile-time pool of stream atoms by position, sized to the largest option list a field can declare plus the stale column.

    Live updates. Every item mutation - add, update, move, remove - appends one actor-attributed entry to the item event log and broadcasts on the repository project topic, so a connected board updates without a reload. Add and remove announced nothing before.

    Accessibility. Moving and removing are buttons on the card (Move left, Move right, Move up, Move down, Remove) with aria-labels naming the card, a labelled group per card, labelled columns, and a per-column empty state. The keyboard and a screen reader reach them the same way a pointer does.

    Authorization. Every item operation resolves the item through the reader's repository visibility, so a card sourced from a private repository returns 404 rather than confirming it exists, and a non-member's move or removal never reaches the database. Covered by tests in both the controller and the board.

    Verification. POOL_SIZE=8 MIX_TEST_PARTITION=lane81 mix precommit passed: 3333 tests, 15 excluded, plus hex.audit, deps.audit, compile --warnings-as-errors, deps.unlock --check-unused, format, ops/ci/reference-check.sh, ops/ci/docs-check.exs, and assets.test.

    Shared files touched: priv/migration_lineages/prior-2026-08-19.json (one new migration version) and lib/openagents_web/api_route_authority.ex (the two new write routes, in the three-tuple envelope shape #82 landed).

    Docs updated: docs/github-api-issues-projects-assessment.md and priv/docs/projects.md.

  3. closed this as completed 5h ago
Sign in with GitHub to comment on this issue.