Achievement and Activity System
The Hephaestus gamification engine is split into two distinct Bounded Contexts: the Activity Module (XP tracking) and the Achievement Module (milestone unlocking). This separation ensures that raw event logging and complex achievement evaluation are decoupled.
Architecture and Design Principles
The system follows a CQRS-style architecture where write operations (events) are processed asynchronously to compute XP and evaluate achievement progress, while read operations aggregate these computed values efficiently.
1. Activity Module (Write Path)
The Activity Module is an append-only event log. It is not Event Sourcing; rather, it is an Event Log that computes derived values (like XP) at write time.
- Idempotency: Each event is processed with a unique
event_keyto prevent duplication. - Immutability: Once written,
ActivityEvententities are immutable. No further updates are permitted. - Pre-computed XP: When an event is recorded (e.g.,
ActivitySavedEvent), theExperiencePointCalculatorevaluates the activity and assigns an XP value immediately. This allows for constant-time complexity when querying data.
2. Achievement Module (Event-Driven)
The Achievement Module listens for ActivitySavedEvent messages published by the Activity Module. It evaluates progress based on predefined thresholds and unlocks achievements for the user.
- Entities:
UserAchievementtracks the progress and unlock status for a specific user and achievement. - Evaluators: The system uses a Strategy pattern interface (
AchievementEvaluator) to determine how an event contributes to progress. For instance:StandardCountEvaluator: Increments progress by one for each relevant event.- Specialized Evaluators (e.g.,
SpeedsterEvaluator,NightOwlEvaluator): Implement complex logic for hidden or special achievements.
- Backfill: For new users or retrospective changes, the
AchievementRecalculationServicecan wipe a user's progress and chronologically replay all historical activity events strictly to assign the correct, distinct unlock dates.
3. Leaderboard Module (Read Path)
The Leaderboard acts as the read model in the CQRS architecture. Since XP is pre-computed exactly once upon activity creation, determining leaderboards does not require iterating over or replaying events. Instead, the module directly utilizes native database aggregation functions (like SUM and GROUP BY). This strategy keeps leaderboard queries incredibly fast and ensures page load times remain efficient regardless of how many events are generated over time.
Achievements Configuration
The available achievements are defined externally in a YAML configuration file, keeping business rules out of the database migrations. The source of truth is located at: server/application-server/src/main/resources/achievements/achievements.yml.
YAML Schema Structure
The standard achievement package is validated against a JSON schema (achievements-schema.json). If you add new properties or extend the definition logic, you can regenerate this validation schema mapping by running the corresponding script from the scripts directory (update-achievements-schema.ts).
Each achievement definition specifies its evaluation criteria and progression requirements constraints:
- id: "pr.merged.common.2"
parent: "pr.merged.common.1" # Defines hierarchy/chains
rarity: common
isHidden: false # Set to true for hidden/secret achievements
category: pull_requests
triggerEvents:
- PULL_REQUEST_MERGED
evaluatorClass: StandardCountEvaluator
requirements:
type: LinearAchievementProgress
target: 3
id: The unique identifier for the achievement.parent: Allows defining achievement "chains" (e.g., needing 1 PR merged before unlocking the 3 PRs merged achievement).isHidden: Used for secret achievements.triggerEvents: The specific activity event types that should wake the evaluator.evaluatorClass: The Java class inde.tum.in.www1.hephaestus.achievement.evaluatorthat handles progress parsing.requirements: Determines the progress type. TypicallyLinearAchievementProgress(requires a target count) orBinaryAchievementProgress(unlocks immediately when conditions match).
To add a new achievement, add it to achievements.yml and provide the corresponding evaluatorClass logic in the codebase if relying on custom logic.
Achievement Designer
The layout for the achievement map can be previewed in the Achievement Designer Tool under the admins tab (for workspace admins). There the layout can be adjusted to perfectly fit the newly created achievements.