Sprint 7: engagement mechanics — points wallet, leaderboards, streaks - #19
Merged
Conversation
…ds, streaks) Scope decided with Steve: all three mechanics in thin slices. Points from achievements (pointsValue) + per-event rules (project.pointRules), awarded inside the ingestion transaction; computed balances; client-tz-offset streak days; pk read endpoints for wallet/streak/leaderboard; Leaderboard widget; demo + compose-stack e2e. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Nine tasks in dependency order: contracts (wallet/streak/leaderboard schemas, tz offset) → core (pure engagement calc, EngagementWrite/Store ports, ingest widening) → adapter-db (migration 0006, transactional awards, FOR UPDATE streaks, engagement reads) → cms (pointsValue, pointRules, endpoint, seed) → adapter-strapi → api (award wiring + three endpoints) → sdk → widgets (Leaderboard) → demo/e2e/docs DoD. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds pure engagement domain logic (localDayFromOffset, applyStreak, pointsForEvent) plus the port shapes downstream adapters will implement: ConfigStore.getPointRules, EngagementWrite/EngagementStore, and a 5th ingestEvent param carrying computed engagement data into the existing ingestion transaction. AchievementDefinition gains a required pointsValue field. Known break (expected, not fixed here): adapter-db, adapter-strapi, and apps/api no longer typecheck until Tasks 3/5/6 implement the widened ports and add pointsValue to their AchievementDefinition construction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ation 0006) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rd endpoints Wires point-rule/achievement point awards into POST /v1/events (fail-open config fetch, safe defsById lookup, no second config-plane round trip) and adds the three engagement read endpoints (wallet, streak, leaderboard) backed by PgEngagementStore. Ends the known typecheck-break chain from the upstream core/adapter-db/contracts changes; workspace typecheck is fully green again. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…minism and portability nits Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the Sprint 7 plan (
docs/superpowers/plans/2026-07-08-sprint-7-engagement.md) — the v1.x engagement trio in thin, demo-visible slices, built on the transactional ingestion substrate from Sprint 5:points_ledgerwritten inside the ingestion transaction (dedup/rollback semantics inherited — a replayed event or unlock awards nothing); points flow from per-event rules (project.pointRules) and achievement unlock bonuses (pointsValue);GET /v1/users/:id/walletreturns the computed balance + last 20 entriesGET /v1/leaderboard?window=all|7d|30d&limit=1..100—SUM(delta)ranked, deterministic ties, windowed by ledger timestamps;<Leaderboard>widget highlights the current userSELECT ... FOR UPDATE(race-tested); the SDK auto-sends the device tz offset per event, with an always-lenient schema (catch(undefined)) so an invalid offset degrades to UTC-day rather than 400ing the trackgetWallet(),getStreak(),getLeaderboard(opts),currentUserIdgetterBehavior notes
tzOffsetMinutesis additive; three new pk endpoints (rate-limit + auth middleware inherited)identify()for pseudonymity. Wallet/streak reads for arbitrary userIds match the pre-existingGET /v1/users/:id/achievementsposture — not a new grant, but the leaderboard makes id discovery easierDELETE /v1/users/:idnow also removespoints_ledger+user_streaksrows (counts additive in the response)Test plan
Review notes
Nine tasks through the full gate cycle (four fix→re-review loops: zod idiom equivalents, seed coherence, api boundary tests) plus a final whole-branch review — verdict ready to merge with fixes; fix wave
53606d0applied and re-approved: the erasure gap (the one Critical — erased users would have persisted on the leaderboard), spec-lenient tz schema, multiplier docs, wallet-order determinism, Node-portability nit,Math.floorguard. Delivers the third v1.x roadmap slice (leaderboards, streaks, points/XP wallet).🤖 Generated with Claude Code