Skip to content

Goal: SSRM Direct Backend Query

Lifecycle: In progress — Phase 1 (exploration and design) complete, implementation not started.

Tickets: PDEV-244 (parent) · PDEV-1308 ✅ · PDEV-1309 ✅ (one gap: PDEV-1335) · PDEV-1315 (/distinct requirements) · PDEV-1335 (lookupPage last-page signal)

Repositories: arda-frontend-app, operations and/or common-module, documentation

Predecessor: Spike #855 — Item List Filter & Sort, which built the SSRM + BFF cache this project replaces.

The /items grid uses AG Grid’s Server-Side Row Model, but the “server” is a Next.js BFF holding a per-tenant cache of every item (unstable_cache, 5-minute TTL, capped at 15 000 rows). Filtering, sorting and paging are evaluated in Lambda memory over that cache; the backend sees one unfiltered fan-out per cache fill and no Query DSL filter at all.

This project moves that evaluation to operations: property and enum filters, sort and pagination become Query DSL requests against POST /v1/item/item/query, and free-text search becomes POST /v1/item/item/lookup against the indexed search_text document. The cache, its 15 000-row ceiling, and the cross-Lambda freshAfter freshness mechanism all retire with it.

PDEV-244 was written before either half of this existed. Since then:

  • The SSRM machinery landed (spike #855), so the grid already speaks a block-request protocol — what is missing is a backend behind it.
  • PDEV-1251 landed /lookup, /by-code, the search_text generated column and its GIN trigram index, giving the backend a real search capability. This delivered what the earlier analysis had filed as a future follow-up, and made the original plan (a hand-curated six-field regex OR) obsolete.

The ticket as originally written targeted entity-data-grid in ux-prototype with a searchMode: 'client' | 'server' toggle. That framing no longer matches the system; see Scope.

  • arda-frontend-app — replace the cached SSRM route with a translator that compiles CloudScape filter tokens, the AG Grid sort model and the block range into Query DSL, routes to /query or /lookup by request shape, and removes the cache and its freshness plumbing.
  • operations / common-module — a distinct-values capability for the filter dropdowns (PDEV-1315), which the cache removal otherwise takes away. Shape, hosting and performance are open design decisions bounded by seven stated consumer requirements.
  • documentation — this goal, and the completion-phase updates listed under Deliverables.
  • The kanban grid and any other SSRM surface. Verified independent: the BFF cache exists only in src/app/api/arda/items/_lib/cachedItems.ts.
  • ux-prototype. Components that ought to be shared get follow-up tickets to promote them, rather than moving in this project.
  • Backend row counting. No withTotal, no COUNT aggregation — see Accepted losses.

Single-pass replacement, verified on the Amplify PR preview (pr-<N>.d38w5m1ngjza76.amplifyapp.com, dev backend) before merge. One PR carries the translator, the search routing, the count rework, the dropdowns and the cache removal together. A preview deployment exercises the whole page against real data, which a feature flag would only have offered after merge, and a single PR reverts cleanly.

Two consequences: the search-behavior decision could not be deferred to a later increment (it is settled — see below), and MSW mock fidelity becomes the automated safety net, since e2e runs in mock mode and a stale handler would keep the suite green while the real path is broken.

Filtering/sorting and free-text search are specified as two distinct capabilities:

  • Case I — no search string. CloudScape terms compose into the Query DSL filter; ordering is the user’s column sort, with eId appended for stable paging.
  • Case II — search string present. The same filter composes, AND-ed with the fuzzy predicate by /lookup; ordering is relevance, and the UI says so.

Both are servable by operations as it stands — the AND composition is what the endpoint hardwires. Seven sub-decisions (token grouping, single search token, whitespace normalization, NO_SORT in Case II, no backend counting, sort-state preservation, a 3-character minimum) are settled and recorded in the workbook thread.

Deliberate, not deferred:

  • The unfiltered total is gone. "X of Y items" cannot return in any form. The filtered count is exact once the last block is reached and immediately when a result set fits one block; otherwise it is qualified ("100+ items"). An occasional extra page request is accepted as preferable to a COUNT query on every filter change.
  • Free-text reach changes. Search gains description and the secondary-supply fields; it loses numerics, dates, cardNotesDefault, additionalQrs, the presentation fields, and notes beyond 256 characters. Disclosed rather than engineered away.
  • Option lists narrow for two fields. supplier and manufacturer resolve through the business-affiliate lookup, which requires typed input.
  1. The /items grid filters, sorts, pages and searches entirely against operations, with no per-tenant cache in the BFF and no 15 000-row ceiling.
  2. Case I and Case II behave as specified above, including the UI indication that relevance ordering is in effect.
  3. Filter dropdowns are populated for the nine open-set fields, with a type-ahead fallback wherever the value set is truncated.
  4. No column can 500 the grid: every filterable and sortable colId resolves to a verified backend locator, guarded by a coverage test.
  5. Verified on the Amplify preview against a dev tenant of more than 1 000 items, seeded through the system API as part of this project’s test setup.
  6. Mock-mode handlers and e2e coverage match the new contract.

Beyond the code:

  • Update the Spike #855 project, whose architecture this project replaces, and whose status is still in-progress.
  • Review the current-system documentation for descriptions of the items BFF cache or SSRM flow that go stale on merge.
  • Set this document’s status to completed.

Copyright: (c) Arda Systems 2025-2026, All rights reserved