# Inventory coordination (movement types)

## Services

Uses **`InventoryStockMovementApplyCore`** via **`InventoryMovementApplyService::applyLedgerWithLockedProjection()`** inside an encompassing transaction managed by **`InventoryStockTransferExecuteService`** (no nested full `apply()` transaction + advisory duplication for paired legs).

## Movement types

| Type | Ledger sign | Guards |
| --- | --- | --- |
| `transfer_out` | Negative quantity like `stock_out` | Available/on-hand feasibility |
| `transfer_in` | Positive quantity like `stock_in` | Non-negative resultant balances |

Enum values in DB (`inventory_stock_movements.movement_type`): `transfer_out`, `transfer_in`.

## Idempotency

Per-leg deterministic keys scoped to transfer id:

- `xfer-{transferId}-transfer-out`
- `xfer-{transferId}-transfer-in`

`idempotency_source`: `inventory.transfer.execute`

Retries within the **same committing transaction** replay safely; recompleting after `completed` is short-circuited on the header row (`status === completed`), preventing duplicate economic effect.

## Correlation pairing

Exactly **one UUID** reused on both **`ApplyMovementInput::correlationId`** instances for forensic joins.
