93 lines
2.9 KiB
Markdown
93 lines
2.9 KiB
Markdown
# 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)
|