Include Loyalty/Communication/Sports Center backends and registry updates alongside production nginx and compose wiring. Co-authored-by: Cursor <cursoragent@cursor.com>
206 lines
7.2 KiB
Markdown
206 lines
7.2 KiB
Markdown
# Phase 7.0 — Loyalty Service Foundation
|
||
|
||
| Field | Value |
|
||
| --- | --- |
|
||
| Status | Complete (validated + self-healed) |
|
||
| Module | loyalty |
|
||
| Version | 0.7.0.0 |
|
||
| Database | `loyalty_db` |
|
||
| API Port | 8004 |
|
||
| ADR | ADR-001, ADR-003, ADR-006, ADR-011 |
|
||
|
||
## Goal
|
||
|
||
Establish the Enterprise Loyalty Platform as an independent shared service foundation and architectural boundaries only.
|
||
Not part of CRM. Reusable by all business modules via API + Events.
|
||
|
||
## Loyalty Responsibilities (Phase 7.0)
|
||
|
||
Loyalty owns foundation aggregates only:
|
||
|
||
- LoyaltyProgram
|
||
- MembershipTier (shell for Phase 7.1)
|
||
- Member (shell for Phase 7.1)
|
||
- PointAccount shell — **no mutable balance** (ledger in Phase 7.2)
|
||
- Reward catalog shell (Phase 7.3)
|
||
- Campaign shell with versioned rules counter (Phase 7.4)
|
||
- LoyaltyAuditLog
|
||
- OutboxEvent (ADR-006 transactional publish)
|
||
|
||
## Service Boundaries
|
||
|
||
| Loyalty owns | Loyalty does not own |
|
||
| --- | --- |
|
||
| Aggregates above | CRM sales entities |
|
||
| Loyalty HTTP APIs under `/api/v1/*` | Accounting / Posting Engine |
|
||
| `loyalty.*` permissions (enforced on routes) | Notification / Communication delivery |
|
||
| Publish-only Loyalty events via outbox | Analytics store (Phase 7.8) |
|
||
| Platform provider **interfaces** | Identity / Wallet UI |
|
||
| | Restaurant / Marketplace / Ecommerce domain data |
|
||
|
||
Communication with platform and business services is **API + Events only**. No cross-DB access.
|
||
|
||
## Owned Modules (aggregates)
|
||
|
||
Independent aggregates in `backend/services/loyalty/app/models/foundation.py`:
|
||
|
||
1. `LoyaltyProgram`
|
||
2. `MembershipTier`
|
||
3. `Member`
|
||
4. `PointAccount`
|
||
5. `Reward`
|
||
6. `Campaign`
|
||
7. `LoyaltyAuditLog`
|
||
8. `OutboxEvent` (infra)
|
||
|
||
Cross-aggregate links use UUID references inside `loyalty_db` only (no SQLAlchemy relationship graphs).
|
||
|
||
## External Platform Dependencies (contracts only)
|
||
|
||
Defined in `app/providers/contracts.py` — **no implementations**:
|
||
|
||
- `NotificationProvider`
|
||
- `AnalyticsProvider`
|
||
- `Customer360Provider`
|
||
- `AIProvider`
|
||
- `ModuleIntegrationProvider`
|
||
- `CRMProvider`
|
||
- `CommunicationProvider`
|
||
- `FileStorageProvider`
|
||
|
||
## Published Events
|
||
|
||
| Event | Aggregate |
|
||
| --- | --- |
|
||
| `loyalty.program.created` / `updated` / `deleted` | loyalty_program |
|
||
| `loyalty.tier.created` / `updated` / `deleted` | membership_tier |
|
||
| `loyalty.member.created` / `updated` / `enrolled` / `deleted` | member |
|
||
| `loyalty.point_account.opened` / `updated` / `deleted` | point_account |
|
||
| `loyalty.reward.created` / `updated` / `deleted` | reward |
|
||
| `loyalty.campaign.created` / `updated` / `deleted` | campaign |
|
||
|
||
Events are written to `outbox_events` in the same DB transaction as the mutation (ADR-006). Phase 7.0 does **not** consume platform events.
|
||
|
||
## API Contracts
|
||
|
||
| Method | Path |
|
||
| --- | --- |
|
||
| CRUD + soft delete | `/api/v1/programs` |
|
||
| CRUD + soft delete | `/api/v1/tiers` |
|
||
| CRUD + enroll + soft delete | `/api/v1/members` |
|
||
| Open / list / update / soft delete | `/api/v1/point-accounts` |
|
||
| CRUD + soft delete | `/api/v1/rewards` |
|
||
| CRUD + soft delete | `/api/v1/campaigns` |
|
||
| Audit read | `/api/v1/audit?entity_type=&entity_id=` |
|
||
| Health | `/health` |
|
||
|
||
## Permissions
|
||
|
||
Route-enforced trees (admin roles or explicit permission strings):
|
||
|
||
- `loyalty.*`
|
||
- `loyalty.programs.*`
|
||
- `loyalty.tiers.*`
|
||
- `loyalty.members.*`
|
||
- `loyalty.point_accounts.*`
|
||
- `loyalty.rewards.*`
|
||
- `loyalty.campaigns.*`
|
||
- `loyalty.audit.*`
|
||
|
||
## Architecture Decisions
|
||
|
||
1. Database-per-service (`loyalty_db`) — ADR-001 / ADR-011
|
||
2. Row-level `tenant_id` from request tenant context — ADR-003
|
||
3. Transactional outbox (`outbox_events`) + EventEnvelope — ADR-006
|
||
4. Layering: API → Services → Repositories → Models
|
||
5. Direct balance modification forbidden; PointAccount DTOs `extra='forbid'`
|
||
6. Optimistic locking (`version` required) on Program / Member / PointAccount updates
|
||
7. Campaign `rule_version` increments when rules change
|
||
8. Soft delete releases unique business keys (`__del__{id}`) so codes can be reused
|
||
9. At most one `is_default` program per tenant (app clear + partial unique index)
|
||
10. Invalid `X-Tenant-ID` → `400 invalid_tenant_id`
|
||
11. Permission inheritance: `loyalty.view`, resource `*.manage`, `loyalty.manage`
|
||
12. Production rejects default DB credentials and `debug=True`
|
||
|
||
## Database / ER (logical)
|
||
|
||
```
|
||
LoyaltyProgram 1──* MembershipTier
|
||
LoyaltyProgram 1──* Member 1──1 PointAccount
|
||
LoyaltyProgram 1──* Reward
|
||
LoyaltyProgram 1──* Campaign
|
||
* ── LoyaltyAuditLog (by entity_type/entity_id)
|
||
* ── OutboxEvent
|
||
```
|
||
|
||
Indexes cover tenant+status / program / tier / outbox status. No cross-DB FKs.
|
||
|
||
## Enterprise Validation (Self-Heal)
|
||
|
||
| Gate | Result |
|
||
| --- | --- |
|
||
| Architecture / boundaries | Pass |
|
||
| Module ownership (not CRM) | Pass |
|
||
| Repository / service layering | Pass |
|
||
| Tenant isolation | Pass |
|
||
| Soft delete + unique reclaim | Pass (healed) |
|
||
| Outbox-ready events | Pass (healed) |
|
||
| Permission enforcement + tree inheritance | Pass (healed) |
|
||
| Security (auth deny / invalid tenant / prod guards) | Pass (healed) |
|
||
| Audit read API + JSON-safe changes | Pass (healed) |
|
||
| Balance forbid at HTTP | Pass (healed) |
|
||
| Null required-field updates | Pass (healed) |
|
||
| Performance indexes + default uniqueness | Pass (healed) |
|
||
| Documentation / ADR / registry | Pass |
|
||
| Automated tests | **52 passed** |
|
||
|
||
Audit report: [loyalty-phase-7-0-audit.md](loyalty-phase-7-0-audit.md)
|
||
|
||
## Tests Executed
|
||
|
||
| Suite | Result |
|
||
| --- | --- |
|
||
| Architecture / dependency / migration | Pass |
|
||
| Permissions / security / tenant isolation | Pass |
|
||
| Repository / API / business rules / audit / outbox | Pass |
|
||
| Performance indexes / docs | Pass |
|
||
|
||
Command: `cd backend/services/loyalty && pytest -q`
|
||
|
||
## Known Limitations
|
||
|
||
- Membership engine depth (lifecycle rules, eligibility) → Phase 7.1
|
||
- Immutable point ledger / earn-redeem / expiration → Phase 7.2
|
||
- Full reward redemption flows → Phase 7.3
|
||
- Campaign segments/triggers/rule engine → Phase 7.4
|
||
- Referral / wallet / gift card / analytics / public APIs → Phases 7.5–7.9
|
||
- Outbox worker / real message bus flush → platform bus maturity (rows are persisted PENDING)
|
||
- Soft-delete of program does not cascade-close children (explicit Phase 7.1+ policy)
|
||
- JWT↔tenant claim binding and Core entitlement feature checks → platform-wide follow-up
|
||
|
||
## Next Phase
|
||
|
||
Phase 7.1 — Membership Engine (**not started**)
|
||
|
||
## Completion Checklist
|
||
|
||
- [x] Code completed
|
||
- [x] Architecture / dependency / repository / migration / API / permission / security / tenant / docs / business-rule / performance tests
|
||
- [x] Documentation updated
|
||
- [x] Module registry updated
|
||
- [x] ADR-011 accepted
|
||
- [x] Enterprise validation + self-heal completed (including incomplete 7.1 residue cleanup)
|
||
- [x] No CRM ownership of Loyalty
|
||
- [x] No TODO placeholders in foundation
|
||
- [x] No Phase 7.1 APIs/migrations present
|
||
|
||
## Related Documents
|
||
|
||
- [Progress](progress.md)
|
||
- [Next Steps](next-steps.md)
|
||
- [Module Registry — loyalty](module-registry.md#loyalty)
|
||
- [Loyalty Phase Area](phases/Loyalty/README.md)
|
||
- [ADR-011](architecture/adr/ADR-011.md)
|
||
- [Audit Report](loyalty-phase-7-0-audit.md)
|
||
- [Service README](../backend/services/loyalty/README.md)
|