Project

General

Profile

Actions

Feature #1547

closed
RA

Feature #1511: Replace ticket view with Kanban board for CTO and assigned developers

Frontend: board polling, manual refresh and card-move animation

Feature #1547: Frontend: board polling, manual refresh and card-move animation

Added by Redmine Admin 1 day ago. Updated 1 day ago.

Status:
Shipped
Priority:
Normal
Assignee:
-
Start date:
08/03/2026
Due date:
% Done:

0%

Estimated time:
spec_ref:

docs/superpowers/specs/2026-08-03-kanban-board-design.md

build_status:
build_number:
ci_run_url:
scan_status:
scan_report_url:
deploy_status:
preprod_url:
deployed_at:
branch:
feat/1547-board-polling-refresh
pr_url:
https://github.com/omdev-tech/PipeLiner-Client/pull/99
security_key:
severity:
paused:

Description

**Surface:** frontend (`src/`)
**Depends on:** "Frontend: Kanban board replaces the ticketing list view"

Decision **D3**: "real-time" for this epic means **polling only**. This narrows the epic's original AC ("tickets move instantly") to *"tickets move within one poll interval, with an animated transition, plus an on-demand manual refresh"*.

An SSE or websocket channel is **explicitly out of scope** and becomes a follow-up ticket. There is precedent for both approaches in the repo — SSE in `src/features/chat/useAssistantStream.ts`, polling in `src/features/projects/useProject.ts:26` and `src/features/usage/useHostMetrics.ts:24` — and we are deliberately taking the cheaper one for v1.

Reuse the existing `refetchInterval` convention rather than inventing a new one; the interval lives in **one named constant**. **Proposed: 30s** — confirm with the PO.

## Acceptance criteria
- [ ] The board query polls on an interval defined in one named constant and refetches on window focus; a fake-timer test asserts exactly one refetch per interval.
- [ ] Polling **pauses when the tab is hidden** and resumes on focus: a test dispatching `visibilitychange` asserts zero fetches while hidden and exactly one refetch on focus.
- [ ] No duplicate intervals after remount: a mount/unmount/mount cycle followed by one tick issues exactly one refetch.
- [ ] **In-flight drag protection, concrete test:** start a transition mutation and leave it pending; force a refetch that returns the server state with the card still in its origin column → the card stays at its optimistic position while the mutation is pending, and reconciles to server truth only after it settles. Both phases asserted.
- [ ] A card whose status changed server-side moves to its new column on the next poll with the animated transition from the design section.
- [ ] `prefers-reduced-motion: reduce` disables or reduces the animation — asserted under a mocked `matchMedia`.
- [ ] A manual refresh control triggers an immediate refetch, shows the designed loading state, and is disabled while a fetch is in flight — clicking it mid-fetch issues no second request.
- [ ] No `EventSource`, WebSocket or SSE endpoint is introduced (assertion in test or lint).
- [ ] Refresh-related strings exist in **both** `en.ts` and `fr.ts` with identical ICU placeholders.
- [ ] Gates green: `npx vitest run && npx tsc --noEmit && npx eslint . && npm run build`.

Actions

Also available in: PDF Atom