You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Three SPA tables render one page from a server-paged endpoint with no paging affordance. Rows beyond that page silently disappear:
Surface
Call sites
Effective cap
ORDER BY
Consequence
Customer book
web/src/routes/CustomersPage.tsx:42
default 100
customer name, then id ascending
Alphabetically later customers vanish; a newly created late-sorting customer can disappear after refresh.
Flock bird-movement ledger
web/src/routes/FlocksPage.tsx:217, :233
explicit 50; endpoint max 500
date, then id descending
The oldest movements vanish after the 50th row, including after recording a new movement.
Inventory item movement ledger
web/src/routes/InventoryPage.tsx:147
explicit 100; endpoint max 500
date, created timestamp, then id descending
The oldest purchase, usage, and adjustment rows vanish after the 100th movement.
All three datasets can grow without a product-defined bound. The movement ledgers are append-only, so they become more likely to cross the cap over time.
Existing reusable primitive
web/src/components/usePagedList.ts already owns paging, request sequencing, deduplication, load-more state, error recovery, and loaded-window refresh. History, Expenses, Sales, Feed, Water, and Audit already use it.
The customer endpoint already accepts offset; listCustomers currently exposes only limit. Both movement API helpers already expose limit and offset.
Proposed scope
Migrate CustomersPage, the Flocks bird ledger, and the Inventory movement ledger to usePagedList.
Expose offset from listCustomers.
Render the existing translated Load more affordance while another page may exist.
Preserve the currently loaded window after create/record/correct mutations instead of collapsing back to page one.
Keep each repository's existing stable ordering.
Acceptance criteria
Every row remains reachable after the first page on all three surfaces.
A full page exposes Load more; a short page withdraws it; an in-flight load cannot be started twice.
A failed extension keeps already loaded rows and permits retry; a failed replacement does not leave stale rows under a new context.
Recording a bird movement or inventory mutation refreshes all pages the user had loaded.
Creating a customer refreshes the loaded customer window without silently hiding already reached rows.
Focused frontend tests cover crossing each old cap and loading the next page.
No hardcoded English is introduced.
Not in scope
The paged/searchable flock and customer selectors are tracked separately because a native <select> needs a different reusable UI primitive.
Implementation order
This is the first implementation group.
Complete this issue by reusing the existing usePagedList hook for Customers, bird movements, and inventory movements.
Expand SimulationDataSeeder with deterministic over-cap bands owned by this issue:
at least 101 customers, including a named sentinel that sorts after the first 100;
at least 51 bird movements for one known flock, including an oldest-page sentinel;
at least 101 inventory movements for one known inventory item, including an oldest-page sentinel.
Use the normal handlers/domain paths and deterministic existence probes so a clean rerun converges to AlreadySeeded. Update ComputeExpectedCounts, SimulationManifestCounts/lifecycle metadata as applicable, ValidateCounts, the manifest fingerprint, and SimulationSeedCommandTests; the fixture must continue to certify exact counts rather than a >= floor.
Add focused Playwright coverage that reaches each sentinel through Load more. Keep the fixture names deterministic and verify the existing quick suite still targets intended rows after the customer catalog crosses 100; do not mask a broken write with tolerated statuses.
If new Simulation:* options are introduced instead of structural constants, update SimulationOptions, tools/simulation/bootstrap.sh, docker-compose.sim.yml, and verify-harness.sh in the same change.
Problem
Three SPA tables render one page from a server-paged endpoint with no paging affordance. Rows beyond that page silently disappear:
web/src/routes/CustomersPage.tsx:42web/src/routes/FlocksPage.tsx:217,:233web/src/routes/InventoryPage.tsx:147All three datasets can grow without a product-defined bound. The movement ledgers are append-only, so they become more likely to cross the cap over time.
Existing reusable primitive
web/src/components/usePagedList.tsalready owns paging, request sequencing, deduplication, load-more state, error recovery, and loaded-window refresh. History, Expenses, Sales, Feed, Water, and Audit already use it.The customer endpoint already accepts
offset;listCustomerscurrently exposes onlylimit. Both movement API helpers already exposelimitandoffset.Proposed scope
usePagedList.offsetfromlistCustomers.Acceptance criteria
Not in scope
The paged/searchable flock and customer selectors are tracked separately because a native
<select>needs a different reusable UI primitive.Implementation order
This is the first implementation group.
usePagedListhook for Customers, bird movements, and inventory movements.#511 and #512 are technically independent, but this issue goes first because it uses an established primitive and has the smaller design surface.
Related issues
Simulation and E2E fixture
Expand
SimulationDataSeederwith deterministic over-cap bands owned by this issue:Use the normal handlers/domain paths and deterministic existence probes so a clean rerun converges to
AlreadySeeded. UpdateComputeExpectedCounts,SimulationManifestCounts/lifecycle metadata as applicable,ValidateCounts, the manifest fingerprint, andSimulationSeedCommandTests; the fixture must continue to certify exact counts rather than a>=floor.Add focused Playwright coverage that reaches each sentinel through Load more. Keep the fixture names deterministic and verify the existing quick suite still targets intended rows after the customer catalog crosses 100; do not mask a broken write with tolerated statuses.
If new
Simulation:*options are introduced instead of structural constants, updateSimulationOptions,tools/simulation/bootstrap.sh,docker-compose.sim.yml, andverify-harness.shin the same change.