Include Loyalty/Communication/Sports Center backends and registry updates alongside production nginx and compose wiring. Co-authored-by: Cursor <cursoragent@cursor.com>
7.2 KiB
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:
LoyaltyProgramMembershipTierMemberPointAccountRewardCampaignLoyaltyAuditLogOutboxEvent(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:
NotificationProviderAnalyticsProviderCustomer360ProviderAIProviderModuleIntegrationProviderCRMProviderCommunicationProviderFileStorageProvider
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
- Database-per-service (
loyalty_db) — ADR-001 / ADR-011 - Row-level
tenant_idfrom request tenant context — ADR-003 - Transactional outbox (
outbox_events) + EventEnvelope — ADR-006 - Layering: API → Services → Repositories → Models
- Direct balance modification forbidden; PointAccount DTOs
extra='forbid' - Optimistic locking (
versionrequired) on Program / Member / PointAccount updates - Campaign
rule_versionincrements when rules change - Soft delete releases unique business keys (
__del__{id}) so codes can be reused - At most one
is_defaultprogram per tenant (app clear + partial unique index) - Invalid
X-Tenant-ID→400 invalid_tenant_id - Permission inheritance:
loyalty.view, resource*.manage,loyalty.manage - 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
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
- Code completed
- Architecture / dependency / repository / migration / API / permission / security / tenant / docs / business-rule / performance tests
- Documentation updated
- Module registry updated
- ADR-011 accepted
- Enterprise validation + self-heal completed (including incomplete 7.1 residue cleanup)
- No CRM ownership of Loyalty
- No TODO placeholders in foundation
- No Phase 7.1 APIs/migrations present