Skip to content

Goal: Item Manufacturer Field

Add an optional Item Manufacturer field to the parts catalog. It captures who makes a part — distinct from the supplier you buy it from (e.g. a part bought from Uline but made by 3M). Rather than a plain string, the manufacturer is modeled as a BusinessAffiliate carrying a BusinessRole of type MANUFACTURER, mirroring the recently-shipped Item → ItemSupply → Supplier(VENDOR) linkage — and reusing it, by generalizing SupplierReference into a role-agnostic BusinessRoleReference (PDEV-875). The value is surfaced in the item form (Ordering Details), in the catalog filter and column, and threaded into the card / Kanban / label / breadcrumb print payloads.

RepositoryRolePlanned Changes
operationsUpstream (backend)MANUFACTURER role type; PDEV-875 BusinessRoleReference generalization; manufacturer field on Item + migration; role-parameterized resolver with STRICT/PROPAGATE mode; listener + item-side cross-role query; print-payload threading (card/Kanban/label/breadcrumb).
arda-frontend-appDownstream (frontend)BusinessRoleReference DTO; mapper (always-reference); generic manufacturer lookup adapter; Ordering-Details typeahead; catalog filter + column.
documentationProject docsThis goal, design, decision log, project plan under roadmap/reference-data/item/manufacturer-field/; promotion on completion.
workbooksAnalysis sourceThe notebooks/manufacturer-field/ analysis (ba-manufacturer-changes-analysis.md) that this plan derives from.
  1. An item can be created/edited with an optional manufacturer via an Ordering-Details typeahead that behaves like the existing Type/Supplier typeaheads; the value persists and round-trips.
  2. The manufacturer is stored as a BusinessRoleReference (role MANUFACTURER) linked to a real BusinessAffiliate + BusinessRole, with the same find-or-create and retirement semantics as the supplier/VENDOR path.
  3. The item create/update API accepts an optional resolution mode (STRICT | PROPAGATE) that defaults to PROPAGATE when the caller omits it (a hard requirement is deferred to PDEV-1107).
  4. Renaming or retiring a manufacturer BusinessRole keeps every linked item’s stored manufacturer consistent (via the listener), unless the item itself is deleted/retired.
  5. The catalog can be filtered by manufacturer and shows an optional sortable Manufacturer column.
  6. The manufacturer name is present in the card, Kanban card, label, and breadcrumb print payloads (empty when unset).
  7. SupplierReference is fully generalized to BusinessRoleReference (PDEV-875) with the supplier wire shape and behavior preserved (no regression to the VENDOR path).
  8. All work follows the per-task TDD protocol (see Constraints) with self-contained, reviewable commits.

This builds directly on the supplier/vendor work (PDEV-731, PDEV-928): the businessaffiliates module in operations, the SupplierReference value object and its resolver (ItemVendorResolver, PROPAGATE-only), the ItemSupplyRoleListener reverse-sync, and the frontend supplier typeahead / lookup machinery. The full end-to-end analysis of the required changes — backend and frontend — is in the workbook: ba-manufacturer-changes-analysis.md (notebooks/manufacturer-field/).

The design and all its decisions are captured in the sibling design, decision log, and project plan.

  • Backend: MANUFACTURER role type; PDEV-875 generalization; Item.manufacturer field + migration + persistence component; role-parameterized resolver with optional STRICT/PROPAGATE mode (defaults to PROPAGATE); listener keeping linked items consistent on role rename/retire; item-side findItemsByManufacturerRole query.
  • Backend: reuse the generic role-filtered business-affiliate lookup for manufacturer suggestions.
  • Backend: thread the manufacturer name into the card, Kanban card, label, and breadcrumb print payload builders.
  • Frontend: always-reference BusinessRoleReference DTO + mapper; generic manufacturer lookup client
    • adapter + Redux cache; Ordering-Details typeahead (“Item Manufacturer”); catalog filter + optional sortable column; mocks + unit + mock-mode E2E.
  • Manufacturer management screens (list/create/edit/merge of manufacturers as first-class entities) — a deliberate follow-up. The denormalized reference fields are added now to support it.
  • Print-template layout/testData.json changes in the printing-templates repo — deferred to a follow-up ticket (this project only guarantees the data is present in the payloads).
  • Bulk-import round-trip of item.manufacturer — deferred to a follow-up ticket, created after the backend is complete so it can carry concrete specifics.
  1. Coding standards adherence is mandatory and strict. Before implementing in each repo, read and follow the relevant skills: kotlin-coding, unit-tests-backend, unit-tests-infra (backend); typescript-coding, react-best-practices, ui-component, unit-tests-frontend (frontend); plus general-conventions. Honor the monadic error channel (Result/AppError, smart constructors, .unitify()), single-exit style, and config-driven test assertions.
  2. Per-task TDD protocol. Each incremental task: (a) write unit tests that compile — production types/signatures defined (stubbed with TODO() for Kotlin) — and fail because the behavior is absent; (b) implement until unit tests pass; (c) add integration/E2E tests as needed; (d) land a single self-contained, reviewable commit. Exception: the PDEV-875 rename (Phase 1, T-01) is a refactor — the existing suite must stay green throughout; tests-first applies only to the new role/MANUFACTURER behavior.
  3. Backend e2e = ContainerizedPostgres integration tests inside operations (resolver both modes, listener, retired guard, item round-trip). No api-test/Bruno worktree.
  4. No common-module changeSupplierReference lives in operations.
  5. Wire compatibility — PDEV-875 preserves the supplier JSON shape; the VENDOR path must not regress.
  6. Single-agent, sequential execution across the existing worktrees; no integration branch.
  7. Push guards — narrow staging; never git add -A (guard against sweeping a composite includeBuild into settings.gradle.kts); run the local gate before every push.
#DeliverableLocation
1Design documentdesign.md
2Decision logdecision-log.md
3Project plan (phased, TDD tasks)project-plan.md
4operations changes + PRbranch jmpicnic/pdev-664-manufacturer-field
5arda-frontend-app changes + PRbranch jmpicnic/pdev-664-manufacturer-field

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