> ## Documentation Index
> Fetch the complete documentation index at: https://internal.softcrum.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Module Spec — loyalty (schema loyalty)

> Event → conditions (profile attrs, segment/tier membership, aggregates, frequency) → effects (parametric rule_effect_types, is_system seed: award_points, issue_coupon, send_webhook, trigger_campaign; F2 row: apply_discount per DEC-H4).

## Entities & invariants

| Table                                   | Key invariants                                                                                                                                                                                                                         |
| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| programs                                | program\_id on EVERY loyalty table from migration 1; tenant-named, full CRUD, count gated by entitlement; default program auto-created and resolved when a request omits it (ADR-021)                                                  |
| point\_currencies                       | ≥2 per program: redeemable + status; never mixed (ADR-011)                                                                                                                                                                             |
| ledger\_transactions                    | append-only; parametric types earn\|redeem\|expire\|revoke\|adjust; pending→available after tenant return window                                                                                                                       |
| point\_lots                             | FIFO consumption; expiration rolling\|end\_of\_month\|end\_of\_year, tier-overridable; expiring\_soon scan (cron fan-out)                                                                                                              |
| contact\_balances                       | projection, SAME transaction as ledger write; nightly drift reconciliation (freshness add-on raises reconciliation frequency only)                                                                                                     |
| rule\_campaigns / rules                 | versioned; condition AST (JSON) + effects; budgets total & per-contact; publishing invalidates compiled-rules cache                                                                                                                    |
| rewards                                 | parametric reward\_types (tenant-extensible); cost\_points; catalog per program                                                                                                                                                        |
| coupon\_campaigns / coupon\_codes       | unique-code mass generation (F1b) or generic; states issued→redeemed\|expired\|void                                                                                                                                                    |
| redemptions                             | parent/child from day 1; Idempotency-Key mandatory; rollback parent-level revert\|keep; money\_component nullable (mixed points+money seam, DEC-H3 — F1 unused)                                                                        |
| stacking\_rules                         | F1b UI; ALL vs PARTIAL policy; discount categories + hierarchy; non-combinable sets                                                                                                                                                    |
| referral\_codes / referral\_conversions | double-sided reward released on qualifying event (first PAID purchase, never signup); fraud flags: self-referral, velocity, device/IP heuristics                                                                                       |
| tier\_definitions / tier\_memberships   | qualification\_metric: points\_earned\|spend\|event\_count; qualification window rolling\|calendar; explicit downgrade policy + grace period; tier\_overrides (earning multipliers, reward pricing, expiration) — schema day 1, UI F1b |
| badges / challenges                     | reserved schema, F2 (strategic gamification: goal-gradient, endowed progress)                                                                                                                                                          |

## Rule engine contract

Event → conditions (profile attrs, segment/tier membership, aggregates, frequency) → effects (parametric rule\_effect\_types, is\_system seed: award\_points, issue\_coupon, send\_webhook, trigger\_campaign; F2 row: apply\_discount per DEC-H4). Effects are deduped per (event, rule) — idempotent.

## Events emitted

points.earned|redeemed|expired|adjusted|revoked · points.expiring\_soon · coupon.issued|redeemed|expired · referral.link\_created|converted · tier.upgraded|downgraded

## Endpoints (Runtime hot: SLO \<300 ms)

POST /v1/loyalty/redemptions (loyalty.redemptions.create) · POST /v1/loyalty/coupons/validate (loyalty.coupons.validate) · POST /v1/loyalty/qualifications (loyalty.qualifications.read) · GET /v1/loyalty/members/me (member token) · Management CRUD: campaigns, rules, rewards, tiers, referrals (loyalty.\{resource}.\{action})
