E6-F1: Loyalty Points Tracking¶
Epic: E6: Loyalty Program
Size: S (Small)
Problem / Outcome¶
Track fan attendance and loyalty points.
Scope¶
In-Scope:
- Points model (1 point per attended paid match - home AND away)
- 5-year rolling window for points
- Points balance API
- Admin view of user loyalty points
Out-of-Scope:
- Points for free tickets
Eligibility Rules¶
- All matches count equally: Home and Away matches both earn 1 point
- Paid ticket required: Free tickets do not earn points
- OIB required: User must have valid OIB on their profile to earn points
Acceptance Criteria¶
- AC1: Fan earns 1 point per attended paid match (home or away) with valid OIB
- AC2: Points older than 5 years excluded from balance
- AC3: GET /users/me/loyalty returns current points balance
- AC4: Admin can view loyalty points for any user via admin portal
- AC5: User can view total points in Ticketing Profile ("My Loyalty Status" section)
- AC6: User can view points history with match-by-match breakdown via GET /users/me/loyalty/history
- AC7: User sees general info that HNS determines early access per match (no specific tier shown in profile)
- AC8: Points history shows 5-year rolling window indicator
Data Model Impact¶
LoyaltyPoint table:
- id (UUID, PK)
- user_id (UUID, FK)
- match_id (UUID, FK)
- ticket_id (UUID, FK)
- points (INTEGER, default 1)
- earned_at (TIMESTAMP)
LoyaltyBalance view:
- user_id (UUID)
- total_points (INTEGER)
- qualifying_points (INTEGER) - within 5 years
- oldest_point_date (DATE)
- newest_point_date (DATE)
Permissions/Roles¶
- Authenticated user (read own)
- System (write)
How to Verify¶
npm test -- --grep "loyalty points"
Expected: Points tracked, rolling window works.
Dependencies¶
Implementation Tasks¶
Doc References¶
- Profile Management Flow - Loyalty Status section
- Loyalty Points History Flow
- Loyalty Early Access Purchase Flow
- Architecture Overview
Last Updated: January 2026