ReviewOS

stacks/wildloop

Achievements: unlock engine + endpoints (progress only moves via conquerTerritory)

#982
Closed glennmichael123 opened this 9 days ago ·
9 days ago

Problem

Achievement/UserAchievement models + tables exist but have no routes and no unlock engine; achievement progress only changes as a side effect of the client conquerTerritory. Nothing evaluates achievements from real activities/conquests.

Acceptance

  • Achievement definitions + an engine that evaluates them on activity/conquest events.
  • Endpoints to read a user's achievements/progress; UI reads real data.
9 days ago

Done in 967239c.

Unlock engine (EvaluateAchievementsAction): computes 10 metrics from source-of-truth rows — activities, distinct trails, total miles, total elevation, territories conquered/defended/owned, kudos given, longest day-streak, any sub-7:00 mile split — and upserts user_achievements (one row per pair, guarded by the #972 unique index). Unlocks are sticky: progress can regress (losing land), is_complete/completed_at never revert. Fresh unlocks notify (new achievement notification type).

Event hooks — progress now moves from real events, not the client: activity stored, territory claimed, conquest/defense processed, kudos given. All best-effort (never block the write). The client-side achievement bumps in the store's conquerTerritory are gone.

Endpoints: GET /users/{id}/achievements (public — definitions merged with progress + unlocked count/points) and POST /achievements/evaluate (auth, manual refresh). Profile achievements tab hydrates from the engine via useAchievementCatalog.

Definitions: the 10 badges seeded with category/metric/target/points/badge color, matching the UI set (First Steps → Empire Builder).

Two framework traps found & fixed along the way: ORM writes map by attribute key while reads return column names, so camelCase attrs (targetValue, isComplete…) silently dropped snake_case write keys — renamed to snake_case across Achievement/UserAchievement/Review; UserAchievement also needed explicit user_id/achievement_id FK attrs to persist them at all.

Verified by scripts/verify-achievements.ts (21 checks). All suites green.

Sign in to comment on this issue.