# Architect — F-021 Orders module

## Feature
F-021 records purchase truth with item snapshots and an explicit state machine. Catalog changes must never alter historical order values.

## Design

### Module boundaries
Create `project/src/modules/orders/` with domain/application/infrastructure/api/tests. Orders owns order persistence only. It does not own catalog, pricing or inventory truth.

### Data model
Add migration `016_orders.js`:
- `orders_orders`: id, user_id, idempotency_key unique nullable, state, totals snapshots, timestamps.
- `orders_items`: id, order_id, product_id, variant_id, sku, ean nullable, name, unit_price_cents, discount_cents, tax_cents, quantity.
- Check `state IN (...)`.
- `idempotency_key` allows checkout idempotency later.

### State machine
States: PENDING, AWAITING_PAYMENT, PAID, PROCESSING, SHIPPED, DELIVERED, CANCELLED, REFUNDED, PARTIALLY_REFUNDED.
Allowed transitions:
- PENDING -> AWAITING_PAYMENT or CANCELLED
- AWAITING_PAYMENT -> PAID or CANCELLED
- PAID -> PROCESSING, SHIPPED, REFUNDED, CANCELLED
- PROCESSING -> SHIPPED, CANCELLED, REFUNDED
- SHIPPED -> DELIVERED, PARTIALLY_REFUNDED
- DELIVERED -> PARTIALLY_REFUNDED
- REFUNDED and PARTIALLY_REFUNDED are terminal.
Any other transition throws `OrderStateTransitionError`.

### Use cases
- `createOrder(input)`: snapshots items, starts at PENDING or AWAITING_PAYMENT, emits `OrderCreated`.
- `transition(orderId, nextState)`: enforces state machine; emits `OrderPaid`/`OrderCancelled` events when relevant.
- `getOrder(orderId)`: ownership scoped to user.

### API
- Authenticated `POST /orders` creates an order from a snapshot payload; ownership-scoped reads.

### Domain events
- `OrderCreated`, `OrderPaid`, `OrderCancelled` emitted synchronously via an event publisher interface (no-op implementation for v1; integration points in checkout F-022 and notifications F-024).

## Acceptance trace
- Snapshot survives catalog edits: order items keep name/sku/ean/price/tax/discount from creation.
- Illegal transitions are rejected, e.g. SHIPPED -> PENDING.
- All legal transitions are covered by unit tests.
- `OrderCreated` is published on creation.
