# listStockRollupsBySite

## Overview

Per-(item × site) stock rollup with per-storage-location breakdown. Replaces the broken auto-generated `stockLevels` query for the `/inventory/stock-level` page after migration 0016 pivoted the StockLevel table to a stockType-keyed tall layout. The frontend renders one row per item-at-site with `onHand` / `blocked` / `available` columns; this resolver does the aggregation server-side and exposes a `locations` array per row for drill-down.

Accepts optional filters `itemId` / `itemIds` (UUIDs) and `siteId` (UUID), plus `search` — a case-insensitive substring matched against item name OR SKU, combined with the id/site filters via AND (whitespace-only is ignored; no minimum length, so it supports the item picker's type-ahead) — and `availableOnly` (boolean; when true, returns only items with `AVAILABLE` stock > 0 and excludes the rest **before** pagination, so the page holds only transferable items — the item picker sets this, while the stock-level list leaves it unset to show blocked / in-transit / depleted items). Pagination is Relay-style (`first` / `after` / `last` / `before` / `pageInfo`). The aggregation runs inline over `StockLevel` / `StorageLocation` / `Item` / `Site` (offset/limit internally); this resolver encodes the offset position as an opaque base64 cursor (`offset:N`) so the FE can drive it with the same `useCollectionVariables` / `useDataTable` / `DataTable.Pagination` plumbing as every other list page. Mixing forward and backward pagination args is rejected at the resolver boundary rather than silently truncated. Supported sort fields: `itemSku` | `onHand` | `available` | `blocked` | `reserved`. `reserved` is always `"0"` until StockReservation is wired in IMS, so sorting by it falls back to the `itemSku` tie-break.

## Modules Commands Used

- (none) — the (item × site) aggregation is computed inline in the resolver over `StockLevel` / `StorageLocation` / `Item` / `Site`; it issues no module command.

## Exception Handling

| Error Code | Description |
| --- | --- |
| (none) | Pagination misuse ("Mixing forward (first/after) and backward (last/before) pagination args is not allowed.") and cursor-decode failures ("Invalid cursor: ...") surface as plain `Error` from the resolver rather than module domain errors. |
