fix(subscriptions): prevent duplicate subscription rows with unique constraint
Root causes of duplicate members in yearly subscriptions:
1. No DB-level unique constraint allowed race conditions between
SubscriptionGenerator, SyncService, and RetroactiveMembershipService
2. SyncService set person_id=NULL for member rows vs Generator's person_id=memberId
3. RetroactiveMembershipService did blind INSERTs with no dedup check
Fix:
- Migration removes existing duplicates (keeps paid row, lowest ID tiebreak)
- Normalizes NULL person_id on member rows
- Adds UNIQUE INDEX (member_id, financial_year, person_type, person_id)
- All insert paths catch Duplicate entry exceptions as race guard
- SyncService now sets person_id=memberId matching Generator
- RetroactiveMembershipService checks for existing row before INSERT
Co-Authored-By:
Claude Opus 4.6 <noreply@anthropic.com>
Showing
Please register or sign in to comment