Skip to content

Goal: Inventory v00

Add two new nullable fields to the Item entity — a dimensioned quantity totalInventoryCount and a timestamp lastCountDate — and surface them for viewing and editing across the frontend Items List View and the Item Detail panel. This is the first inventory-count increment (v00): it establishes the data model and end-to-end read/edit path, without inventory-movement history, audit, or automated counting.

Implemented — in review. Backend merged and released as operations 6.6.0 (PR #230); frontend PR #984 open with all checks green, awaiting review. Tracked as PDEV-1173.

  • PDEV-1173 — Inventory count on Item: totalInventoryCount + lastCountDate (In Review); to be closed by arda-frontend-app #984 on merge.
RepositoryRolePlanned Changes
operationsBackend (Kotlin/Ktor/Exposed)Add totalInventoryCount: Quantity.Value? and lastCountDate: DateTime? to the Item entity, serializer, ItemInput DTO, persistence (ITEM_TABLE/ItemRecord), and a new Flyway migration V022. Extend unit tests.
arda-frontend-appFrontend (Next.js/React)Add both fields to the domain/API types and mappers; hidden-by-default grid columns (count amount + unit, and date), all inline-editable via the existing grid-edit machinery; a new “Inventory Count” group (View + Edit) in the Item Detail panel with editable, clearable inputs.
documentationProject + reference docsThis goal and project artifacts; update the Item current-system functional reference for the new fields.

api-test (Bruno) is out of scope for v00 (see Out of Scope).

  1. An Item can be created and updated with totalInventoryCount (amount + unit) and lastCountDate (date + time) via the operations API, and both round-trip correctly through read.
  2. Either field can be set to a value and later cleared back to null — the count via the Detail Edit panel (both amount and unit cleared), the date via either the Edit panel or inline — and the null persists on reload.
  3. Both fields appear in the Items List View — the count as an amount column plus a unit column (mirroring Min Qty / Min Unit), the date as a single column — all hidden by default and available via the column-visibility menu, formatted per existing conventions (en-US; empty renders as the existing placeholder).
  4. Both fields are inline-editable in the List View using the existing grid editing machinery (count amount via the default editor, count unit via UnitCellEditor, date via a date cell editor), persisting through the same PUT flow as the current editable columns.
  5. The Item Detail View panel shows both fields under an “Inventory Count” group at the end of the panel; empty values render as the existing placeholder.
  6. The Item Detail Edit panel exposes both fields under an “Inventory Count” group at the end (added to the panel’s table of contents), with a number + unit input for the count and a clearable datetime input for the date.
  7. Backend and frontend baseline gates pass (operations make build; arda-frontend-app lint/typecheck/tests/build); the Item current-system reference documents the two new fields.

The Item entity lives in operations under reference/item/ and is bitemporal. Two near-exact precedents guide the design:

  • totalInventoryCount mirrors the existing minQuantity field — a nullable domain Quantity ({ amount: Double, unit: String }), persisted as a two-column value-object component (*_amount + *_unit).
  • lastCountDate mirrors the Order entity’s deliverBy — a nullable DateTime (timestamp + time_zone), the platform’s standard persisted date type (there is no date-only stored type).

The most recent comparable change is the manufacturer-field project (migration V021), which added a nullable reference to Item; this project follows the same shape and is the newest migration baseline (new migration = V022).

On the frontend, the Items List View is an AG Grid whose columns are assembled by preset builders and gated through a column-visibility menu. The grid already supports inline editing of dimensioned quantities: Min Qty/Min Unit and Order Qty/Order Unit are amount+unit column pairs made editable by gridColumnEnhancers (amount via the default editor, unit via UnitCellEditor), with edits persisted through handleCellValueChanged and the PUT flow. This is the direct precedent for totalInventoryCount’s inline editing. The Item Detail panel has two forms: a read-only View panel (ItemDetailsPanel, a flat field list with no titled sections today) and an Edit panel (ItemFormPanel, which does have titled sections + a table of contents). The Item update path is a PUT full-document replace: a field omitted from the request is written as null, and the edit flow already relies on this to clear fields — so “settable back to null” needs no new mechanism.

  • Backend: two new nullable Item fields (totalInventoryCount as Quantity.Value?, lastCountDate as DateTime?), including entity, hand-written serializer descriptor, ItemInput DTO + toItem, persistence (table columns, record delegates, insert, fromEntity, fillPayload), Flyway V022, and unit-test updates (DDL, model round-trip, universe fixtures, service/endpoint).
  • Frontend: domain Item type, ARDA DTO types, and mappers (read + create + update, including clear-to-null); grid columns (hidden by default, registered in the column config + visibility menu) — an amount + unit column pair for the count (mirroring Min Qty / Min Unit) and one date column; inline editing of all three via the existing grid-edit machinery (gridColumnEnhancers + getEditableCellValue/applyEditableCellValue, UnitCellEditor for the unit, a date cell editor for the date); “Inventory Count” group in both View and Edit detail panels with an editable number+unit input and a clearable datetime input; component tests, MSW fixtures, and Playwright specs.
  • Documentation: this project’s artifacts and an update to the Item current-system functional reference.
  • Inventory movement/transaction history, audit trail, or count reconciliation.
  • Server-side sorting or filtering on the new columns (they follow the existing columns’ client-side behavior; no new backend query support in v00).
  • api-test (Bruno) coverage for the new fields — deferred to a follow-up.
  • Any new shared ux-prototype/design-system component (the Edit inputs use existing/native controls).
  • Validation constraints beyond nullability (no non-negative or no-future-date guards unless added later).

Normalization rules applied on input/save so a valid value is always persisted:

  • totalInventoryCount (Quantity):
    • amount provided, unit empty → unit defaults to “each”.
    • unit provided, amount empty → amount defaults to 0.
    • both empty → the field is null and renders the placeholder.
    • Inline in the grid, amount and unit are separate cells edited one at a time, so clearing the field entirely to null is done in the Detail Edit panel (clear both); a single inline edit cannot null both at once. This is accepted.
  • lastCountDate (DateTime): a null value is still a valid, displayable state (renders the placeholder) and remains user-clearable both inline and in the Detail Edit panel. When the stored value is null, the date/time edit control pre-seeds to “now” for convenience; the user may accept it, change it, or clear it back to null.
  1. No breaking API changes — both fields are additive and nullable; existing Item create/read/update payloads remain valid without them.
  2. Follow the established value-object patterns: totalInventoryCount mirrors minQuantity (Quantity component), lastCountDate mirrors Order.deliverBy (DateTime component). New migration is V022.
  3. The Quantity component’s DB-level all-or-nothing rule (both columns null or both set) is satisfied by the normalization defaults in Field Semantics & Defaults (fill the missing half rather than reject); only both-empty is null.
  4. Clearing a field to null must persist through the PUT full-document-replace update path already used by the Edit panel.
  5. Grid columns default to hidden and are opt-in via the column-visibility menu; once shown, they follow the existing columns’ inline-edit behavior.

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