# Phase Handover — Loyalty 7.1 Membership Engine ## Metadata | Field | Value | | --- | --- | | Phase ID | loyalty-7.1 | | Title | Membership Engine | | Status | Complete | | Service(s) | loyalty (`loyalty-service`, port 8004) | | Version | 0.7.1.0 | | Date | 2026-07-25 | | ADR(s) | ADR-001, ADR-003, ADR-006, ADR-011 | ## Reusable Components | Component | Location | Reuse notes | | --- | --- | --- | | Lifecycle validators | `app/validators/membership.py` | Transition matrix + expiry helpers | | MembershipEngineService | `app/services/membership_engine.py` | Lifecycle orchestration | | MembershipLifecycleEvent | `app/models/foundation.py` | Append-only history pattern | ## Public APIs | Method | Path | Auth / Permission | Notes | | --- | --- | --- | --- | | POST | `/api/v1/members/{id}/activate` | `loyalty.members.activate` | Sets term/expiry | | POST | `/api/v1/members/{id}/renew` | `loyalty.members.renew` | Extends from current expiry | | POST | `/api/v1/members/{id}/freeze` | `loyalty.members.freeze` | Reason required | | POST | `/api/v1/members/{id}/resume` | `loyalty.members.resume` | From frozen/suspended | | POST | `/api/v1/members/{id}/cancel` | `loyalty.members.cancel` | Reason required | | POST | `/api/v1/members/{id}/expire` | `loyalty.members.expire` | Manual expire | | POST | `/api/v1/members/{id}/transfer` | `loyalty.members.transfer` | Creates target member | | GET | `/api/v1/members/{id}/lifecycle` | `loyalty.members.lifecycle.view` | History | ## Events | Event type | Domain / Integration | Payload summary | Version | | --- | --- | --- | --- | | `loyalty.member.activated` | Domain | membership_number, status, expires | 1 | | `loyalty.member.renewed` | Domain | membership_number, expires | 1 | | `loyalty.member.frozen` | Domain | membership_number, reason | 1 | | `loyalty.member.resumed` | Domain | membership_number | 1 | | `loyalty.member.cancelled` | Domain | membership_number, reason | 1 | | `loyalty.member.expired` | Domain | membership_number | 1 | | `loyalty.member.transferred` | Domain | source + target ids | 1 | ## Extension Points | Extension point | How to extend | Forbidden uses | | --- | --- | --- | | Transition matrix | Extend `ALLOWED_TRANSITIONS` + tests | Bypass validators in APIs | | Program cascade | Adjust `ACTIVE_MEMBER_STATUSES` policy intentionally | Soft-cascade without docs | | Provider contracts | Unchanged from 7.0 | Implement providers inside Loyalty | ## Known Limitations - No scheduled auto-expire worker - Transfer does not migrate point accounts (deferred to 7.2+) - Outbox flush still platform-bus maturity item ## Migration Notes | Item | Detail | | --- | --- | | Alembic revision(s) | `0002_phase_71_membership` | | Upgrade steps | `alembic upgrade head` in loyalty service | | Downgrade support | Yes (drops columns/table) | | Data backfill | None | | Breaking changes | None (additive) | ## Dependencies | Dependency | Type | Required for | | --- | --- | --- | | loyalty-7.0 | Phase | Foundation aggregates | | Core entitlement | Platform | Deferred feature-key wiring | | shared-lib | Library | Events, security, exceptions | ## Next Phase Entry 1. This handover + [loyalty-phase-7-1.md](../loyalty-phase-7-1.md) 2. Updated module registry / manifests 3. Build immutable point ledger; do not store balance on PointAccount 4. Suggested next: `loyalty-7.2` Point Engine | Field | Value | | --- | --- | | Recommended next phase | loyalty-7.2 | | Blockers for next phase | None | | Entry checklist | Read 7.1 handover; keep lifecycle statuses stable | ## Completion Sign-Off - [x] Quality gates passed - [x] Tests green (59) - [x] Documentation updated - [x] Progress / next-steps / registries updated - [x] No TODO for claimed deliverables - [x] Self audit completed ## Related Documents - [loyalty-phase-7-1.md](../loyalty-phase-7-1.md) - [loyalty-phase-7-0.md](../loyalty-phase-7-0.md) - [ADR-011](../architecture/adr/ADR-011.md)