Skip to main content
Estado: Propuesto · Refs: v0.2 §2.2, benchmark (locked points de Open Loyalty, períodos pendientes de Voucherify)
Traducción. Autoritativo: ../../adr/adr-011-points-ledger.md.

Decisión

  • loyalty.ledger_transactions es append-only; tipos (paramétricos): earn|redeem|expire|revoke|adjust; estados pending→available (el earn se confirma tras la ventana de devolución configurada por el tenant). Una columna de saldo mutable está PROHIBIDA.
  • Dos monedas por programa como mínimo: redeemable y status (XP). Nunca mezcladas (modelo aerolínea).
  • Los earn crean loyalty.point_lots con expires_at; los canjes consumen lotes FIFO. Modos de expiración por programa (sobreescribibles por nivel): rolling N días | fin de mes | fin de año. El escaneo points.expiring_soon alimenta campañas de retención.
  • loyalty.contact_balances es una proyección actualizada en la MISMA transacción que la escritura del libro (casi en tiempo real, no negociable); la reconciliación nocturna detecta drift (el add-on de frescura de datos sube la frecuencia de la reconciliación, nunca la del saldo).
  • Los canjes son padre/hijo (solicitudes multi-recompensa); rollback a nivel de padre con modos revert|keep; Idempotency-Key obligatorio. money_component (monto + moneda, nullable) reserva la costura del canje mixto puntos + dinero (DEC-H3) — sin usar en F1.

Consecuencias

  • Pasivo auditable, saldos reproducibles, semántica estándar de la industria. − Más filas que un saldo ingenuo; mitigado por la evaluación de particionamiento y las proyecciones.