Files
mercadodevida/work/artifacts/F-113/architect.md
2026-08-21 12:27:13 +02:00

2.5 KiB

F-113 — Arquitectura: email en procesando/enviado con tracking y courier editable

Descubrimiento clave

El mailer de estado ya existe (order-status-mailer.ts, F-106) y se dispara en POST /orders/:id/transitions/admin. PERO la UI admin (apps/admin) llama a la ruta de cliente POST /orders/:id/transitions, que no envía email, ignora trackingNumber y devuelve 404 si el backoffice no es el dueño del pedido. F-113 conecta la UI admin con la ruta admin correcta para que el email realmente salga en procesando/enviado.

Decisiones

  1. Courier persistido: migración 039 añade orders_orders.courier varchar(120) NULL. Se propaga por dominio (Order.courier), repositorio, updateState/transitionAdmin (firma courier?: string), servicio y serializeOrder.
  2. Lista editable de couriers: se guarda como JSON array en store_settings.shipping_couriers. GET/PATCH /admin/settings exponen couriers: string[] (default si no existe: Correos, SEUR, MRW, GLS, DHL, UPS). Validación zod: array ≤30 items, cada string 1..60.
  3. SHIPPED exige tracking y courier: en la ruta admin, state==='SHIPPED' requiere trackingNumber (ya existía, 422 TRACKING_NUMBER_REQUIRED) y ahora también courier (422 COURIER_REQUIRED). Ambos se pasan al mailer.
  4. Mailer: sendOrderStatusEmail acepta courier?: string | null. En el cuerpo (texto y HTML) del email, si hay courier se añade línea "Transportista: X" junto a "Número de seguimiento: Y". Escape HTML ya presente.
  5. Email en procesando y enviado: como la UI admin ya usa transition() para todos los estados y la ruta admin envía email en cada transición, apuntar la UI a la ruta admin garantiza email en PROCESSING y SHIPPED (y el resto). No se añade lógica de envío nueva, solo se corrige el endpoint consumido.

Admin UI (apps/admin)

  • api-client.ts: ordersApi.transition(id, state, trackingNumber?, courier?)POST /api/orders/{id}/transitions/admin (envía courier si está presente). StoreSettings.couriers?: string[].
  • types/index.ts: Order.courier?: string | null.
  • Página de pedido: al confirmar SHIPPED, mostrar selector de courier (desde ajustes) además del tracking; ambos obligatorios. Mostrar courier en el detalle.
  • Ajustes: nueva pestaña "Transportistas" con textarea (uno por línea) que edita la lista.

Fuera de alcance

  • No rediseñar los demás emails de estado.
  • Sin integración con APIs externas de transportistas.