XP thresholds (500→1200→2000→…→11000→+2500/level) drive automatic level
increases. add_xp_with_levelup() replaces bare add_xp() in match
processing: for each level gained it grants level×500 coins and milestone
packs (bronze@5, silver@10, gold@15, rare_gold@20, gold every 5 after).
GET /profile now returns computed level (recalculated from XP so it
stays consistent), xp_to_next_level, and xp_for_next_level so the
dashboard can render a progress bar without a second call.
POST /matches/result response gains level_ups array (empty when no
level-up occurred) with new_level, coins_granted, pack_granted per event.
Four new tests: profile level fields, level_for_xp boundary checks,
level-up event in match result, milestone pack unit test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Returns all pack definitions with id, name, description, cost_coins, and
total_cards so the dashboard can render a purchasable pack store without
needing to know the definitions at compile time.
Two new tests: store listing shape and buy-then-open round-trip.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
FUT Champions (Weekend League):
- POST /fut-champs/start — open a new 30-match week (one active session at a time)
- GET /fut-champs — current session status with matches_remaining
- POST /fut-champs/:id/result — record a match; auto-completes and computes tier at 30
- POST /fut-champs/:id/claim — claim coins + pack reward (idempotent guard)
- GET /fut-champs/history — past sessions newest-first
- 11 reward tiers: Elite (27+ wins, 50k coins + icon pack) down to Bronze 1 (0 wins, 250 coins)
Division Rivals:
- POST /rivals/claim-weekly — claim weekly reward scaled by current division
- Week counter is monotonic (offline-safe, no real-time calendar dependency)
- Division 1-3 get a bonus pack alongside coins
Migration 0008 adds fut_champs_sessions table and two columns to seasons.
12 new integration tests — all 67 pass, clippy clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GET /chemistry-styles — lists 18 FUT-style chemistry styles with stat boost breakdowns
- POST /collection/:id/chemistry-style — apply a style (Shadow, Hunter, Anchor, etc.)
- POST /collection/:id/position — override a player's position for 500 coins
- POST /collection/:id/training — add +1/+2/+3 OVR training bonus (max +3 total)
- GET /collection now includes chemistry_style, position_override, training_bonus,
effective_overall and effective_position fields per owned card
- Migration 0007 adds three columns to owned_cards with safe defaults
- 10 new integration tests — all 55 pass, clippy clean
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GET /division returns live season stats (points, record, promotion threshold)
- PUT /club allows updating club name and manager_name
- GET /packs/history returns opened packs with full card definitions
- GET /notifications dynamically surfaces completed objectives, expiring loans, season end
- Club model gains manager_name column (migration 0006 already added it)
- Pack model gains opened_cards and opened_at; pack SELECT queries updated
- 9 new integration tests — all 45 pass, clippy clean
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Chemistry v2: FUT-style link scoring with per-player breakdown
(club +3/link cap 6, league +1/link cap 4, nation +1/link cap 3;
player cap 10, team cap 100); chemistry response now includes
per-player breakdown with club/league/nation link counts and pts
- Card pool: 34 new cards across Premier League, La Liga, Bundesliga
with overlapping clubs/nations for meaningful chemistry testing
- Card search: extended GET /cards with nation, league, club,
min_overall, max_overall, limit query params; results sorted by
overall descending
- Match opponent: added "ultimate" difficulty band (85+ OVR);
random formation selection from 6 tactical formations; falls back
to lower OVR pool when not enough cards at the requested band
- Tests: 9 new integration tests (28 total, all passing)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a data-driven event system (#47 schema, #48 activation, #49 TOTW):
- EventDefinition JSON schema (event_type, effects, date range, is_manual)
- data/events/totw_week1.json — TOTW event active by date range (2024–2030),
injects 5 TOTW cards into the market as [EVENT] listings
- data/events/seasonal_events.json — Spring Festival and Icon Weekend,
manual-activation-only example events
- migrations/0004_events.sql — events override table (NULL/1/0 per event)
- services/event — load_event_definitions, compute_is_active (date range +
manual override), get_active_events, get_all_with_status, activate/deactivate
- routes/events — GET /events, GET /events/:id, POST .../activate, .../deactivate
- services/market::refresh_npc_listings now accepts event_defs, injects bonus
market cards from active events at 2× premium price
- 5 new integration tests (events list, single, activate/deactivate cycle,
404 on unknown, market injection verification); 19/19 passing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>