Achievement Types and Configuration
The Phoenix Gamification Achievement System supports three types of progress tracking conditions—Count, Sum, and Distinct—each designed for different use cases, plus event filtering and reward integration.
Achievement Types and Configuration
The Phoenix Gamification Achievement System supports three types of progress tracking conditions, each designed for different use cases.
Overview
Achievements track user progress toward a goal by processing events. Each achievement definition specifies:
- Event Types: Which events count toward the achievement
- Expression (optional): Filters events based on attributes
- Progress Condition: How to measure progress (Count, Sum, or Distinct)
- Target: The value needed to complete the achievement
- Repeatable: Whether the achievement can be completed multiple times
Progress Condition Types
1. Count Condition
Tracks the number of matching events. Use this for achievements like "Play 100 games" or "Complete 50 quests".
Configuration:
{
"event_types": ["game.completed"],
"condition": {
"type": "count",
"min": 100
},
"target": 100.0
}Example Achievement:
- Name: "Play 100 Games"
- Description: "Play 100 games to unlock this achievement"
- Progress: Counts each
game.completedevent - Completion: When count reaches 100
Use Cases:
- Track number of actions performed
- Count completions of a specific activity
- Simple milestone tracking
2. Sum Condition
Tracks the sum of a numeric field from matching events. Use this for achievements like "Spend $1000" or "Earn 10,000 points".
Configuration:
{
"event_types": ["transaction.completed"],
"expression": {
"condition": {
"field": "attrs.status",
"operator": "eq",
"value": "success"
}
},
"condition": {
"type": "sum",
"field": "attrs.amount",
"min": 1000.0
},
"target": 1000.0
}Key Components:
- field: Path to the numeric field to sum (e.g.,
"attrs.amount","attrs.score") - min: The minimum sum required (must match
target) - expression (optional): Filter events before summing (e.g., only count successful transactions)
Example Achievement:
- Name: "Spend $1000"
- Description: "Spend a total of $1000 to unlock this achievement"
- Progress: Sums
attrs.amountfromtransaction.completedevents whereattrs.status == "success" - Completion: When sum reaches $1000
Use Cases:
- Track total spending
- Accumulate points or currency
- Sum scores or values over time
3. Distinct Condition
Tracks the number of unique values for a field. Use this for achievements like "Play 10 different game types" or "Visit 5 different locations".
Configuration:
{
"event_types": ["game.completed"],
"condition": {
"type": "distinct",
"field": "attrs.game_type",
"min": 10
},
"target": 10.0
}Key Components:
- field: Path to the field containing distinct values (e.g.,
"attrs.game_type","attrs.location") - min: The minimum number of unique values required (must match
target)
Example Achievement:
- Name: "Play 10 Game Types"
- Description: "Play 10 different game types to unlock this achievement"
- Progress: Tracks unique values of
attrs.game_typefromgame.completedevents - Completion: When 10 distinct game types have been played
Use Cases:
- Track variety of activities
- Encourage exploration
- Collect unique items or experiences
Event Filtering with Expressions
You can filter which events count toward an achievement using expressions. Expressions support AND/OR logic and field comparisons.
Simple Expression
Filter events based on a single condition:
{
"event_types": ["transaction.completed"],
"expression": {
"condition": {
"field": "attrs.status",
"operator": "eq",
"value": "success"
}
},
"condition": {
"type": "sum",
"field": "attrs.amount",
"min": 1000.0
},
"target": 1000.0
}This only counts successful transactions.
Complex Expression (AND)
Filter events that meet multiple conditions:
{
"event_types": ["transaction.completed"],
"expression": {
"and": {
"expressions": [
{
"condition": {
"field": "attrs.status",
"operator": "eq",
"value": "success"
}
},
{
"condition": {
"field": "attrs.amount",
"operator": "gte",
"value": 10
}
}
]
}
},
"condition": {
"type": "count",
"min": 50
},
"target": 50.0
}This counts transactions that are successful AND have amount >= $10.
Complex Expression (OR)
Filter events that meet any of multiple conditions:
{
"event_types": ["game.completed"],
"expression": {
"or": {
"expressions": [
{
"condition": {
"field": "attrs.game_type",
"operator": "eq",
"value": "puzzle"
}
},
{
"condition": {
"field": "attrs.game_type",
"operator": "eq",
"value": "strategy"
}
}
]
}
},
"condition": {
"type": "count",
"min": 20
},
"target": 20.0
}This counts games that are either puzzle OR strategy type.
Supported Operators:
eq: Equal tone: Not equal togt: Greater thangte: Greater than or equal tolt: Less thanlte: Less than or equal toin: Value is in arraycontains: Field contains value (for strings/arrays)
Repeatable Achievements
By default, achievements can only be completed once. Set repeatable: true to allow multiple completions.
Configuration:
{
"event_types": ["game.completed"],
"condition": {
"type": "count",
"min": 10
},
"target": 10.0,
"repeatable": true
}Behavior:
- When completed, progress resets to 0
completion_countincrements- Achievement can be completed again
- Useful for daily/weekly challenges
Reward Integration (Rewards v2)
Achievements can grant rewards from the rewards catalog upon completion. When an achievement is completed, the reward is automatically granted through the rewards service, which handles fulfillment (wallet currency, badges, manual fulfillment, or API webhooks).
Configuration:
{
"event_types": ["game.completed"],
"condition": {
"type": "count",
"min": 100
},
"target": 100.0,
"repeatable": false,
"reward_id": "uuid-of-reward-from-catalog"
}How it works:
- Achievement completes →
AchievementEventV1::Completedevent published to NATS - Rewards service consumer listens for completion events
- Reward order created automatically via
reward_service.grant() - Fulfillment executed based on reward type:
- Wallet currency: Added to user's wallet balance
- Wallet badge: Badge granted to user
- Manual: Order status set to
pending_claimfor admin fulfillment - API: Webhook called to external service
Example: Currency Reward
{
"name": "Play 100 Games",
"config": {
"event_types": ["game.completed"],
"condition": { "type": "count", "min": 100 },
"target": 100.0,
"reward_id": "aad70d24-5cfa-44e5-9a2b-614f60fbd108" // Reward from catalog
}
}The reward must exist in the rewards catalog before creating the achievement. The reward_id is validated when creating/updating achievement definitions.
Configuration Validation Rules
Required Fields
event_types: Must have at least one event type (supports wildcards like"game.*")condition: Must specify one of:count,sum, ordistincttarget: Must be positive and match the condition'sminvalue
Condition-Specific Rules
Count:
minmust be a positive integertargetmust equalmin
Sum:
fieldcannot be emptyminmust be positivetargetmust equalmin(within 0.001 tolerance)
Distinct:
fieldcannot be emptyminmust be a positive integertargetmust equalmin
Expression Rules
- Field paths must be valid (e.g.,
"attrs.field_name") - Operators must be supported
- Values must match the field type
Complete Configuration Examples
Example 1: Simple Count Achievement
{
"name": "Play 100 Games",
"description": "Play 100 games to unlock this achievement",
"config": {
"event_types": ["game.completed"],
"condition": {
"type": "count",
"min": 100
},
"target": 100.0,
"repeatable": false
}
}Example 2: Sum Achievement with Filtering
{
"name": "Spend $1000",
"description": "Spend a total of $1000 on successful transactions",
"config": {
"event_types": ["transaction.completed"],
"expression": {
"condition": {
"field": "attrs.status",
"operator": "eq",
"value": "success"
}
},
"condition": {
"type": "sum",
"field": "attrs.amount",
"min": 1000.0
},
"target": 1000.0,
"repeatable": false
}
}Example 3: Distinct Achievement
{
"name": "Play 10 Game Types",
"description": "Play 10 different game types",
"config": {
"event_types": ["game.completed"],
"condition": {
"type": "distinct",
"field": "attrs.game_type",
"min": 10
},
"target": 10.0,
"repeatable": false
}
}Example 4: Repeatable Achievement with Reward
{
"name": "Daily 10 Games",
"description": "Play 10 games each day (repeatable)",
"config": {
"event_types": ["game.completed"],
"condition": {
"type": "count",
"min": 10
},
"target": 10.0,
"repeatable": true,
"reward_id": "uuid-of-reward-from-catalog"
}
}Note: Each time a repeatable achievement completes, the reward is granted again. This allows daily/weekly rewards that reset automatically.
Progress Tracking
The system tracks progress in a Progress object:
{
"count": 75, // For Count condition
"sum": 750.0, // For Sum condition
"distinct": ["type1", "type2", "type3"] // For Distinct condition
}Only the relevant field is used based on the condition type.
API Usage
Create Achievement Definition
POST /v1/tenants/{tenant_id}/achievements
X-API-Key: {api_key}
Content-Type: application/json
{
"name": "Play 100 Games",
"description": "Play 100 games to unlock this achievement",
"config": {
"event_types": ["game.completed"],
"condition": {
"type": "count",
"min": 100
},
"target": 100.0,
"repeatable": false
}
}Query User Progress (Query Gateway)
GET /v1/achievements/user/{user_id}
Authorization: Bearer <JWT>Optional: GET /v1/achievements/user/{user_id}/{definition_id} for a single achievement. Tenant and user are derived from the JWT; paths do not include tenant_id. Response includes current progress, target, completion status, and completion percentage.
Best Practices
-
Choose the Right Condition Type
- Use
countfor simple counting - Use
sumfor accumulating values - Use
distinctfor variety/collection achievements
- Use
-
Use Expressions Wisely
- Filter out invalid events (e.g., failed transactions)
- Combine conditions with AND/OR for complex logic
- Keep expressions simple for performance
-
Set Appropriate Targets
- Balance challenge with achievability
- Consider user engagement patterns
- Test with real event data
-
Consider Repeatability
- Use
repeatable: truefor daily/weekly challenges - Use
repeatable: falsefor one-time achievements - Track
completion_countfor analytics
- Use
-
Integrate Rewards
- Create rewards in the rewards catalog first
- Link achievements to rewards using
reward_id - Provide meaningful incentives
- Balance reward value with achievement difficulty
- For repeatable achievements, rewards are granted on each completion