# SerialNumber

## Description

SerialNumber represents a unique identifier assigned to an individual unit of an item, enabling unit-level traceability throughout the item's lifecycle. Serial numbers follow a state machine: AVAILABLE (in stock) → ISSUED (dispatched) → RETURNED (received back) → AVAILABLE (restocked) or SCRAPPED (disposed). SCRAPPED is a terminal state.

Serial-tracked items always have a quantity of exactly 1 per serial number. State transitions are driven by stock movements rather than direct commands.

## Domain Model Definitions

### Model type

Stateful

#### State Transitions

```mermaid
stateDiagram-v2
    [*] --> Available: assignSerialNumber
    Available --> Issued: executeStockMovement (goods issue)
    Issued --> Returned: executeStockMovement (return)
    Returned --> Available: restock
    Returned --> Scrapped: scrap
    Available --> Scrapped: scrap
```

### Command Definitions

- [assignSerialNumber](../commands/AssignSerialNumber.md) - Assign a serial number to an item at a storage location

### Query Definitions

- [getSerialNumber](../queries/GetSerialNumber.md) - Retrieve a serial number by id or serial number value
- [listSerialNumbers](../queries/ListSerialNumbers.md) - List serial numbers by item, storage location, or status
- [getSerialNumberHistory](../queries/GetSerialNumberHistory.md) - Retrieve the full movement history of a serial number

### Models

- SerialNumber

### Invariants

- Quantity is always exactly 1
- Serial number must be unique per item type (different items may share the same serial number)
- Serial number is immutable after assignment
- SCRAPPED is a terminal state
- ISSUED cannot transition directly to AVAILABLE — must pass through RETURNED
- State transitions are driven by stock movements

### Relationships

- **References Item**: Each serial number belongs to an Item from the item-management module
- **References StorageLocation**: Each serial number tracks its current storage location
