# Architect — F-022 Checkout orchestrator with idempotency

## Feature
F-022 orchestrates the money path: cart -> validation -> pricing -> stock -> discounts -> shipping -> order -> reservation -> payment intent. It owns no business data and exposes a single endpoint with idempotency.

## Design

### Module boundaries
Create `project/src/modules/checkout/` with domain/application/api/tests. Checkout does not own persistence; it composes cart, pricing, promotions, inventory, shipping, orders and a payment provider interface stub.

### Endpoint
- `POST /checkout` requires authenticated user, payload `{ items, address, promoCode?, idempotencyKey }` (recalculated internally). Server fetches cart via `CartService`, recalculates through Pricing/Promotions/Inventory/Shipping, validates everything, creates `AWAITING_PAYMENT` order, reserves stock, creates payment intent.

### Idempotency
- `idempotency_key` is required on the request body.
- The orders table already has `idempotency_key UNIQUE`. When an order already exists for `(userId, idempotencyKey)` the orchestrator returns the existing order without re-reserving stock or re-creating payment intent.
- Double-submit returns the same order id with no duplicate stock reservation.

### Flow and failure handling
1. Load cart. Reject 409 if cart empty or any item unavailable after recalculation.
2. Apply promo discount server-side; reject 422 on invalid promo.
3. Calculate shipping with default address if missing; reject 422 outside zones.
4. Create `AWAITING_PAYMENT` order with snapshots.
5. Reserve inventory atomically. If any reservation fails: cancel the order (state machine), release any partial reservations, return HTTP 409 with reason.
6. Create payment intent (interface stub for v1) and link to order.
7. Return 200 with order summary, stock reserved, payment intent reference.

### Metrics
- `checkout_success_total` counter
- `checkout_failure_total` counter

## Acceptance trace
- Unavailable item -> 409, no order, no payment, no reservation.
- Idempotent key reuse -> same order, no duplicate reservation, no duplicate payment.
- Successful checkout -> order AWAITING_PAYMENT + stock reserved.
- Failure after reservation -> reservation released, order cancelled.
