Goal: Product Slow — Front-End Items Page Performance
Lifecycle: Completed
Linear issues
Section titled “Linear issues”- PDEV-489 — Front-End Performance Improvements
- PDEV-490 — Operations Performance Improvements (back-end prerequisite)
Eliminate the kanban-card N+1 fan-out on the /items page. Today the page
issues 1 + 2N backend round-trips per render (1 items/query-ssrm plus 2
kanban-card calls per visible row); a standard 60-row tenant pays 121
round-trips. The target shape is 1 + 1 = 2 per AG Grid SSRM block, achieved
by collapsing the per-row kanban-card calls onto a single batched
Filter.In(item_reference_entity_id, [eIds…]) query against the existing
/v1/kanban/kanban-card/query route. No new operations endpoint is added; the
work is frontend-only and depends on a composite bitemporal index that ships
from PDEV-490.
This project is the front-end counterpart to the operations-side work in the product-slow-responses umbrella, and is tracked under PDEV-489.
Linear tickets
Section titled “Linear tickets”Umbrella and the four concrete deliverables, all in PDEV and assigned to the current cycle:
- PDEV-489 — Items page front-end performance: collapse kanban-card N+1 fan-out: umbrella. Anchors the work; carries acceptance and the cross-component context. Status: Done — all five sub-PRs merged 2026-05-22.
- PDEV-235 — Items page: collapse kanban-card fan-out to a single batched
Filter.Inquery (1+2N → 2): the headline work. Replace the per-rowQuickActionsCelleffects with a single batched fetch per SSRM block, populating a page-levelitemCardsMap. Status: Done — shipped inArda-cards/arda-frontend-app#846(frontend v4.3.2). - PDEV-548 — Items detail panel: share kanban-card data with page-level
itemCardsMap: drop the redundantquery-details-by-itemfetch inItemDetailsPanelby reading from the existingItemCardsContext. Status: Done — shipped inArda-cards/arda-frontend-app#849(v5.0.0) and refined in#852(v6.0.1). - PDEV-549 — Items bulk handlers: collapse
cardsForItemloops ontoFilter.Inagainst/query: replace the per-item loops inhandleDeleteMultipleItems,handlePrintSelectedCards, andhandlePreviewSelectedCardswith a single batched call, mirroring the PDEV-235 pattern. Status: Done — shipped inArda-cards/arda-frontend-app#850(v6.0.0). - PDEV-550 — BFF kanban-card proxy routes: strip verbose logging:
remove the 10+
console.loglines per call fromapi/arda/kanban/query-details-by-itemandapi/arda/kanban/query, which block on Lambda’s synchronous stdout bridge and dump full response bodies to CloudWatch. Status: Done — shipped inArda-cards/arda-frontend-app#851(v4.3.4).
Repositories
Section titled “Repositories”| Repository | Role | Planned Changes |
|---|---|---|
arda-frontend-app | Production frontend — owner of all code changes | /items page restructure, ItemCardsContext expansion, bulk handler rewrite, BFF proxy log cleanup |
documentation | Project artifacts | goal.md (this file), per-sub-issue specifications and verification reports as the work progresses |
workbooks | Working notes and analysis | Working notes captured during implementation; promoted to the documentation repo as canonical patterns once stable |
Success Criteria
Section titled “Success Criteria”- The
/itemspage issues exactly 2 backend round-trips per AG Grid SSRM block on cold load (1items/query-ssrmplus 1 batchedkanban-card/query). - Per-row counts (
safeCards.length,inOrderQueueCount,printedCount) and the per-rowcandidateCardderive from a single batched dataset shared viaItemCardsContext. - Opening
ItemDetailsPanelfor a row already in the grid paints instantly from the cachedItemCardsContextentry — no per-card secondary GETs (the oldquery-details-by-itemper-card fan-out is gone). A single, parallelrefreshCardsForItem(eid)may fire as the spec’s freshness guarantee (paired with therId-set diff → optional stale banner); that is the refresh, not the per-card N+1. - Bulk handlers (
handleDeleteMultipleItems,handlePrintSelectedCards,handlePreviewSelectedCards) issue exactly 1 batched kanban-card call per invocation regardless of selection size. - The two BFF kanban-card proxy routes emit no per-request body or header logs in production builds; structured error logs only.
- Page latency on the 60-row test tenant drops from the current baseline to a near-flat profile dominated by the two round-trips per block.
- All four sub-issues land as separate PRs against
arda-frontend-appwith passing CI; the documentation worktree publishes the per-sub-issue verification reports.
Context
Section titled “Context”The original PDEV-489 proposal (P1–P5, drafted 2026-05-13) assumed a new
operations aggregate endpoint (summary-for-items, was K01). PDEV-490 design
sessions cancelled K01 on 2026-05-18 after verifying that the existing
/v1/kanban/kanban-card/query route already accepts
Filter.In(item_reference_entity_id, [eIds…]) and returns every field the
frontend row reads. The headline work is now frontend-only.
The frontend collapse relies on a composite bitemporal index
(tenant_id, item_reference_entity_id, eid, effective_as_of DESC, recorded_as_of DESC)
on kanban_card, shipping as Flyway migration V007 in
Arda-cards/operations#173.
Frontend work may develop in parallel with that PR’s review/merge cycle, but
must not deploy to dev before PR #173 lands or the SQL plan will fall back
to sequential scan.
Original P5 (the “500 == no cards” dead branch) is closed transparently by
PDEV-490 K12 (cardsForItem withTotal = false), which also lands in
operations#173.
In Scope
Section titled “In Scope”- Frontend restructure of
/itemspage kanban-card traffic onto a single batchedFilter.Inquery per SSRM block. - Expansion of
ItemCardsContextto serve as the shared cache between the grid, the detail panel, and bulk-action handlers. - Cleanup of the two BFF kanban-card proxy route handlers to remove verbose request/response logging.
- Per-sub-issue specification, verification, and PR-body changelog entries recorded in the documentation worktree.
Out of Scope
Section titled “Out of Scope”- New operations endpoints. The decision is to reuse
/v1/kanban/kanban-card/querywithFilter.In. - Client-side caching of kanban-card data beyond the page-scoped
ItemCardsContext(kanban-card data is too change-heavy to cache at the BFF layer; the items list’s separateunstable_cacheremains). - BFF auth-helper consolidation, the hard-coded
User-Agent: PostmanRuntime/7.45.0, anddevLogchain rewrites (captured as bycatch in the PDEV-489 body; spin off individually if/when they bite). - Operations-side improvements (AWS Advanced JDBC Wrapper,
AppError.Transientretry contract). These are independent and ship from PDEV-490.
Constraints
Section titled “Constraints”-
No new operations routes. The existing
/v1/kanban/kanban-card/queryis the only kanban-card endpoint touched. -
Frontend collapse must not deploy to
devahead of Arda-cards/operations#173 or the SQL plan will sequential-scankanban_card. -
One shared branch (
jmpicnic/product-slow-fe) across all three worktrees for now; per-sub-issue branches may be split out later if parallel work becomes necessary. -
Each sub-issue ships as its own PR against
arda-frontend-appwith the workspace’s standard PR-body changelog entry. The sub-issue PRs form a stack managed with thegh-stackskill — the headline PDEV-235 change is the base of the stack, and the remaining sub-issues stack on top in sequence:- PDEV-235 (base) — items page collapse onto batched
Filter.In; targetsmain. - PDEV-548 — detail panel reads from
ItemCardsContext; targets the PDEV-235 branch. - PDEV-549 — bulk handlers onto
Filter.In; targets the PDEV-548 branch. - PDEV-550 — BFF proxy log cleanup; targets the PDEV-549 branch.
The stack ordering follows the data dependency: PDEV-235 introduces the shared
itemCardsMapand batched query that PDEV-548 and PDEV-549 consume; PDEV-550 is independent but parked at the top of the stack so it lands last and does not block the latency-critical changes on log cleanup review. As each PR merges intomain, the rest of the stack rebases down. - PDEV-235 (base) — items page collapse onto batched
Reference Documents
Section titled “Reference Documents”- PDEV-490 specification — the operations-side prerequisite (composite bitemporal index, retry contract).
- PDEV-490 verification — confirms the existing
/v1/kanban/kanban-card/queryroute reuses cleanly. - Bitemporal composite indexes — the index shape the frontend collapse relies on.
- AWS Advanced JDBC Wrapper integration — failover behaviour during deploys (independent, but relevant to the read path).
- API design — Transient failures and retry contract — 503 +
Retry-Aftersurface the items-page consumer should honour. arda-frontend-appitems page (src/app/items/page.tsx) — the consumer.columnPresets.tsx— theQuickActionsCellwith the two per-row effects.operationsKanbanCardEndpoint— the/v1/kanban/kanban-card/queryroute being reused.operationsKanbanCardPersistence— confirmsitem_reference_entity_idis filterable.
Copyright: (c) Arda Systems 2025-2026, All rights reserved
Copyright: © Arda Systems 2025-2026, All rights reserved