Skip to content

Kanban Cards Module

Kanban Cards manage physical and digital kanban cards used in lean manufacturing and inventory management. Cards signal the need to replenish inventory, initiate production, or trigger material movement between process steps.

  • Items Module: References the item a card represents
  • Serial Number Service: Generates unique identifiers for physical cards
  • Facilities Module: Tracks card location within warehouses and production areas

PlantUML diagram

The card’s item is an ItemReference (see Entity References) that, besides the item eId / rId / cached name, carries denormalized retired and provenance fields used to resolve and mark cards whose item has been deleted — see Deleted-Item Resolution.

OpenAPI specification: https://stage.alpha002.io.arda.cards/v1/kanban/docs/redoc/index.html#tag/v1

Universes configured with EntityServiceConfiguration accept both JSON field paths (camelCase) and database column names (snake_case) as locators. The table below shows both forms. See Query DSL: EntityServiceConfiguration.

JSON Field PathColumn NameTypeDescription
eIdeiduuidEntity UUID
serialNumberkanban_card_snStringCard serial number
itemReference.entityIditem_reference_entity_iduuidAssociated item entity ID
itemReference.itemNameitem_reference_item_nameStringAssociated item name
itemReference.retireditem_reference_retiredbooleanWhether the referenced item is logically deleted
cardQuantity.amountcard_quantity_amountDecimalInventory quantity represented
cardQuantity.unitcard_quantity_unitStringInventory unit of measure
requestLocation.facilityphysical_locator_facilityStringCurrent facility
requestLocation.departmentphysical_locator_departmentStringCurrent department
requestLocation.locationphysical_locator_locationStringCurrent location
statusstatusStringCurrent card status
printStatusprint_statusStringCurrent print status
iduuidRecord ID (bitemporal)
effective_as_ofTIMESTAMPBitemporal effective timestamp
recorded_as_ofTIMESTAMPBitemporal recorded timestamp
retiredBOOLEANWhether logically deleted
tenant_iduuidOwning tenant
last_event_*variousFields describing the most recent lifecycle event
last_print_event_*variousFields describing the most recent print event

KanbanCardService implements DataAuthorityService<KanbanCard, KanbanCardMetadata>.

  • create, read, update, delete
  • list, count, history
  • summaryByStatus — aggregates cards by status with quantity totals
  • listWithDetails — returns cards with full item details

Two specialized lifecycle interfaces:

KanbanCardLifecycle — operational state transitions:

REQUESTED -> ACCEPTED -> IN_PROCESS -> COMPLETED -> FULFILLED -> RECEIVED -> IN_USE -> DEPLETED -> WITHDRAWN

Methods: request, accept, startProcessing, completeProcessing, fulfill, receive, use, deplete, withdraw

KanbanCardPrintLifecycle — print state management:

NOT_PRINTED -> PRINTED (print)
PRINTED -> PRINTED (reprint)
PRINTED -> NOT_PRINTED (unmark)
PRINTED -> LOST (reportLost)
PRINTED -> DEPRECATED (deprecate)
PRINTED -> RETIRED (retire)
DEPRECATED -> LOST (reportLost)
DEPRECATED -> RETIRED (retire)
LOST -> PRINTED (reprint)
LOST -> RETIRED (retire)

Methods: printCards, cardPrinted, reprint, reportLost, retire, unmarkPrinted

The unmarkPrinted method transitions a card from PRINTED to NOT_PRINTED. It is a no-op for cards not in PRINTED status (idempotent for NOT_PRINTED). Exposed via POST /kanban-card/{eId}/event/unmark.

  • Serial number uniqueness within tenant scope
  • Valid lifecycle state transitions
  • Item reference validation
  • Location tracking on lifecycle transitions
  • Print status management

Kanban cards support a free-text notes field (up to 8192 characters, nullable). Notes are initialized from the item’s defaults when a card is created and can be updated independently via a dedicated endpoint. See Kanban Card Notes for the feature specification.

Items are soft-deleted — deletion writes a retired = true bitemporal row that keeps the full item payload — and a kanban card keeps its item reference after the item is gone. Resolving such a card no longer errors: as of PDEV-808 the card’s ItemReference carries the referenced item’s deletion state, and reads resolve the retained record so the card renders with the item’s last-known name and a deleted marker.

The ItemReference gains two denormalized fields, synchronized from the item:

  • retired: Boolean — whether the referenced item is logically deleted (default false)
  • provenance: { updatedBy, updatedAt } | null — who/when of the last sync (the deletion stamp when retired is true)

These are a routing hint and a convenience for consumers that do not re-resolve; the resolved item record is the source of truth.

Propagation (observer; async, best-effort)

Section titled “Propagation (observer; async, best-effort)”

ItemListener (in the kanban service) observes Item Update / Delete events, published post-commit. On each event it copies rId, name, retired (= true on delete), and provenance onto every card referencing the item (cardsForItem). Dispatch is async and best-effort — a failed listener is logged at WARN, not retried — so the cache is eventually consistent.

detailsFor and listWithDetails resolve each card’s item by the cached retired flag:

  • retired == false (believed live, and the legacy default) → getAsOf(eId, asOf, includeRetired = true) — include-retired is the safety net for the observer-lag window and for legacy cards.
  • retired == truegetRecord(rId) — a direct primary-key fetch of the frozen tombstone, asOf-independent.

The response’s retired / provenance are coalesced from the resolved record, with the cache as a fallback. This makes the pre-existing backlog correct with no data backfill: a legacy card (retired = false) takes the believed-live path, include-retired resolves the tombstone, and the record marks it correctly.

On a single-card detail read where the cache is stale, the corrected reference is healed back to the card — best-effort and conflict-tolerant (swallows AppError.ConflictingState), effective-dated no earlier than the item change it reflects. List reads coalesce only (no inline heal writes, to avoid turning a page read into N writes). listWithDetails partitions its chunk (believed-live entries by eId, retired entries by rId) and skips a genuinely-absent (corrupt) item rather than failing the whole page.

No endpoint or authentication changes. The card’s item reference gains retired and provenance additively; KanbanCardDetails gains no top-level fields (consumers read card.item.retired / card.item.provenance). The 500 (IncompatibleState) is removed for the deleted-item case on the detail / list / print routes (retained only for genuine internal inconsistency). The card print payload (KanbanCardPrintInfo) gains item_retired, item_last_updated_by, and item_last_updated_at, so a printed card marks a deleted item; the item Label/Breadcrumb print is handled in the Item Module.

KanbanCardUniverse extends AbstractScopedUniverse<KanbanCard, KanbanCardMetadata, KANBAN_CARD_TABLE, KanbanCardRecord>().

The item reference is flattened into the kanban_card table via the shared ItemReferenceComponent. Alongside the existing item_reference_entity_id / item_reference_item_name / item_reference_record_id, it carries the denormalized deletion fields: item_reference_retired (boolean, NOT NULL DEFAULT false) and the nested provenance component item_reference_provenance_updated_by (varchar, nullable) / item_reference_provenance_updated_at (bigint, nullable, both-or-neither). Because the component is shared, the same columns also exist on order_line, where they are currently unused (see Item Module).

Event sourcing tables:

  • kanban_card_event — lifecycle state changes
  • kanban_card_print_event — print lifecycle changes

Both tables record event_type, from_status, to_status, location, timestamps, and author.

Physical cards include a QR code linking to:

https://{base-url}/kanban/cards/{kanban-card-id}?view=card&src=qr
EnvironmentBase URL
Productionlive.app.arda.cards
Stagingstage.app.arda.cards
Developmentdev.app.arda.cards
PropertyValue
EncodingURL string encoded as QR code
Error correctionLevel M (15% recovery) — suitable for shop floor conditions where cards may be scratched or dirty
Minimum print size20 mm x 20 mm at 300 DPI for reliable scanning with mobile phone cameras
Label placementBottom-right quadrant of the card, with at least 4 mm quiet zone on all sides
Human-readable fallbackCard serial number printed below the QR code in OCR-B font for manual lookup when scanning fails

The card eId is available via the query endpoint:

POST /v1/kanban/kanban-card/query

Authentication: Bearer token. Pass the tenant identifier in the X-Tenant-Id request header.

Pagination: Default page size is 20; maximum is 500. Use the pageSize query parameter to increase the limit within that bound.

Extracting the ID: The entity identifier is at results[*].payload.eId in the response body.

API documentation:

  • OpenAPI: https://prod.alpha001.io.arda.cards/v1/kanban/docs/openApi.json
  • Swagger UI: https://prod.alpha001.io.arda.cards/v1/kanban/docs/openapi/index.html
  • Redoc: https://prod.alpha001.io.arda.cards/v1/kanban/docs/redoc/index.html