Files
Learn_System/backend/src/db/migrations/032_coin_log.sql
T
Maxim Dolgolyov 268ea31bb8 feat(gamification): Phase 4 — standalone coin events + coin_log
Coins were always 1:10 of XP. Now they have their own event log + a
helper that dedups by reason within a configurable window.

Backend:
  • migration 032 creates coin_log (user_id, amount, reason, created_at)
    with indices for the 'fired today?' check
  • awardCoins now records into coin_log on every call (reason defaults
    to 'xp_bonus' for the legacy XP-proportional path)
  • awardCoinsOnce(userId, amount, reason, window) — fires the bonus
    only if no row matches in the window:
      'day'     → DATE(created_at) = today
      'week'    → ISO week match
      'forever' → never twice

Wired events (Phase 4 subset of the plan):
  • Daily login — 10 coins, once/day. Hooked in updateStreak so the
    bonus rides on the existing 'daily_activity' XP trigger.
  • Daily goal completion — 15/25/40 coins (easy/medium/hard), once/day.
    Sits next to the existing tier XP bonus in updateDailyGoal.
  • Variant clear — 30 coins, once per (user, variant) forever. Fires
    from the exam-prep attempts endpoint when the user's final correct
    answer fills out a math9 variant.

Deferred (need invasive trigger hooks): weekly goal, paragraph close,
boss defeated, referral.

Verified end-to-end: awardCoinsOnce returns true→false on repeated
calls, coin_log records the first, coins balance moves once.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 20:30:14 +03:00

27 lines
1.4 KiB
SQL

-- ═══════════════════════════════════════════════════════════════
-- 032: coin_log — audit + dedup table for coin-only events
--
-- Until now coins were always a side-effect of XP (1 coin per 10 XP
-- in awardXP), and we had no per-event log for them. Phase 4 adds
-- standalone coin events (daily login, daily-goal completion, variant
-- clear, weekly challenge bonus) that need their own dedup window so
-- a user can't farm the same bonus twice in one day / week.
--
-- The log is also useful for the upcoming /api/shop/coin-history view
-- on the profile page so users can see *where* their coins came from.
--
-- Lookup pattern is (user_id, reason, created_at) — index supports
-- the "did this event already fire today?" query.
-- ═══════════════════════════════════════════════════════════════
CREATE TABLE coin_log (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
amount INTEGER NOT NULL,
reason TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_coin_log_user_reason_date ON coin_log(user_id, reason, created_at);
CREATE INDEX idx_coin_log_user_date ON coin_log(user_id, created_at);