{
  "feature_id": "F-113",
  "agent": "reviewer",
  "stage": "review_gate",
  "verdict": "APPROVED",
  "reviewed_at": "2026-08-21",
  "summary": "Email on PROCESSING/SHIPPED implemented via the existing admin transition route; courier is stored on orders, editable in store settings, shown in the SHIPPED email and required when marking as SHIPPED. Admin UI was wired to the wrong route and is now fixed.",
  "checks": [
    { "item": "Migration 039 adds nullable `courier varchar(120)` with idempotent ADD COLUMN IF NOT EXISTS and a working down", "ok": true },
    { "item": "Zod validation on /orders/:id/transitions/admin and settings: courier 1..120 chars, couriers array 1..60 chars, max 30 items", "ok": true },
    { "item": "SHIPPED requires trackingNumber AND courier (422 COURIER_REQUIRED + 422 TRACKING_NUMBER_REQUIRED); both passed to mailer and history", "ok": true },
    { "item": "Mailer content is built by a pure buildOrderStatusEmail helper that is unit tested; HTML escaping is preserved", "ok": true },
    { "item": "couriers list editable via store_settings.shipping_couriers (JSON array); parseCouriers defaults to a sensible list, validates JSON, trims, caps at 30 and falls back on bad input", "ok": true },
    { "item": "Bug fix: apps/admin used /orders/:id/transitions (customer route, no email) — now uses /orders/:id/transitions/admin, restoring the email + tracking + notified banner", "ok": true },
    { "item": "Admin UI: courier select in SHIPPED confirm and in shipping sidebar; both wired to transition + updateShipping; settings page has new 'Transportistas' tab with textarea", "ok": true },
    { "item": "Tests cover mailer content, courier parse (defaults, JSON, garbage, cap) and OrderService.transitionAdmin pass-through", "ok": true }
  ],
  "issues": []
}
