TorbatYar/docs/loyalty-phase-7-0.md
Mortezakoohjani e41ecfad4c Sync platform docs, infra, and module services with Accounting integration.
Include Loyalty/Communication/Sports Center backends and registry updates alongside production nginx and compose wiring.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-25 22:35:23 +03:30

206 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.57.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)