# Phase 7.4 — Campaign Engine | Field | Value | | --- | --- | | Identifier | `loyalty-7.4` | | Status | Complete | | Module | loyalty | | Service | `loyalty-service` | | Version | `0.7.4.0` | | Database | `loyalty_db` | | Depends On | Phase 7.3 | | ADR(s) | ADR-001, ADR-003, ADR-006, ADR-011 | ## Objective Deliver the Campaign Engine: lifecycle transitions, versioned rules, and apply-to-member point grants exclusively via PointEngine — without referral, wallet, or gift cards. ## Scope ### In Scope - Lifecycle: schedule / activate / pause / resume / expire - Rules update with `rule_version` bump - `CampaignApplication` tracking + idempotency + per-member caps - Apply grants via `PointEngineService.earn(auto_commit=False)` - Reject soft-delete while campaign ACTIVE - Migration `0005_phase_74_campaigns` ### Out of Scope - Referral (7.5), Wallet (7.6), Gift cards (7.7), Analytics (7.8), Partner APIs (7.9) ## APIs | Method | Path | Permission | | --- | --- | --- | | POST | `/api/v1/campaigns/{id}/schedule` | `loyalty.campaigns.schedule` | | POST | `/api/v1/campaigns/{id}/activate` | `loyalty.campaigns.activate` | | POST | `/api/v1/campaigns/{id}/pause` | `loyalty.campaigns.pause` | | POST | `/api/v1/campaigns/{id}/resume` | `loyalty.campaigns.resume` | | POST | `/api/v1/campaigns/{id}/expire` | `loyalty.campaigns.expire` | | POST | `/api/v1/campaigns/{id}/rules` | `loyalty.campaigns.rules.update` | | POST | `/api/v1/campaigns/{id}/apply` | `loyalty.campaigns.apply` | | GET | `/api/v1/campaigns/{id}/applications` | `loyalty.campaigns.view` | ## Events `loyalty.campaign.{scheduled,activated,paused,resumed,expired,rules_updated,applied}` ## Tests **87 passed** (`pytest -q`) ## Next Phase Phase 7.5 — Referral Engine ## Related Documents - [Handover](phase-handover/phase-7-4.md) - [Service Snapshot](service-snapshots/loyalty.yaml)