# Phase 7.3 — Rewards Engine | Field | Value | | --- | --- | | Identifier | `loyalty-7.3` | | Status | Complete | | Module | loyalty | | Service | `loyalty-service` | | Version | `0.7.3.0` | | Database | `loyalty_db` | | Depends On | Phase 7.2 | | ADR(s) | ADR-001, ADR-003, ADR-006, ADR-011 | | Manifest | [phase-manifest.yaml](ai-framework/phase-manifest.yaml) | ## Objective Deliver the Rewards Engine: redemption lifecycle on catalog rewards with points debited exclusively through the immutable Point Engine — without campaign rules, referral, wallet, or gift cards. ## Scope ### In Scope - Reward inventory fields: `stock_limit`, `redeemed_count`, `max_per_member` - `RewardRedemption` lifecycle: pending → fulfilled | cancelled - Redeem / fulfill / cancel APIs; list by reward and globally - Points debit/refund via `PointEngineService` (`auto_commit=False` composition) - Permissions, events, validators, migration `0004_phase_73_rewards` - Tests + documentation + handover + service snapshot ### Out of Scope - Campaign rule engine (7.4) - Referral / wallet / gift cards / analytics / partner APIs (7.5–7.9) ## Redemption Rules | Rule | Detail | | --- | --- | | Active reward only | Status must be `active` | | Stock | `redeemed_count < stock_limit` when limit set | | Per-member cap | Non-cancelled count ≤ `max_per_member` when set | | Member | Must be `active` | | Points | Debit via ledger; free (`points_cost=0`) skips ledger | | Cancel | Only from `pending`; refunds points; decrements stock counter | | Fulfill | Only from `pending` | ## APIs | Method | Path | Permission | | --- | --- | --- | | POST | `/api/v1/rewards/{id}/redeem` | `loyalty.rewards.redeem` | | GET | `/api/v1/rewards/{id}/redemptions` | `loyalty.redemptions.view` | | GET | `/api/v1/redemptions` | `loyalty.redemptions.view` | | GET | `/api/v1/redemptions/{id}` | `loyalty.redemptions.view` | | POST | `/api/v1/redemptions/{id}/fulfill` | `loyalty.rewards.fulfill` | | POST | `/api/v1/redemptions/{id}/cancel` | `loyalty.rewards.cancel` | ## Events | Event | When | | --- | --- | | `loyalty.reward.redeemed` | Redeem (points deducted) | | `loyalty.reward.fulfilled` | Fulfill | | `loyalty.reward.redemption_cancelled` | Cancel + refund | ## Migration | Item | Detail | | --- | --- | | Alembic | `0004_phase_73_rewards` (down_revision `0003_phase_72_points`) | | Breaking | None — additive columns + table | ## Tests Command: `cd backend/services/loyalty && pytest -q` → **72 passed** ## Known Limitations - No automatic redemption expiry worker - No partner fulfillment webhooks (7.9) - Campaign-driven rewards deferred to 7.4 ## Next Phase Phase 7.4 — Campaign Engine ## Related Documents - [Handover](phase-handover/phase-7-3.md) - [Phase 7.2](loyalty-phase-7-2.md) - [Service Snapshot](service-snapshots/loyalty.yaml) - [ADR-011](architecture/adr/ADR-011.md)