Achievement
Data Entity
Description
Defines the catalog of earnable achievement badges and milestones available on the platform. Each record represents a single achievement definition — its criteria, display metadata, and unlock conditions. Paired with user_achievements to track which users have earned each badge.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key | PKrequiredunique |
organization_id |
uuid |
Tenant owning this achievement definition. NULL means platform-wide (available to all tenants). | - |
key |
string |
Machine-readable identifier used in code and analytics (e.g. 'first_activity', 'ten_activities', 'annual_wrapped'). Stable across renames. | required |
name |
string |
Display name shown to the user on the badge card. | required |
description |
text |
Short motivational copy explaining what this badge is for and how to earn it. | required |
icon_url |
string |
URL or asset path for the badge icon rendered in BadgeWidget and BadgesScreen. | - |
category |
enum |
Groups badges for display and filtering on BadgesScreen. | required |
trigger_type |
enum |
The event class that can unlock this achievement. | required |
trigger_threshold |
integer |
Numeric threshold required to unlock (e.g. 1, 10, 50 activities). NULL for manual or non-count-based triggers. | - |
trigger_metadata |
json |
Supplementary trigger parameters (e.g. {"activity_type": "home_visit", "period": "calendar_year"}). Interpreted by AchievementService evaluation logic. | - |
points |
integer |
Point value awarded when unlocked, used by the Advantage Calculator for total impact scoring. | required |
is_repeatable |
boolean |
Whether the badge can be earned multiple times (e.g. annual badges). False = one-time only. | required |
repeat_period |
enum |
For repeatable achievements, the period after which the badge resets and can be earned again. | - |
is_active |
boolean |
Soft-disables an achievement definition without deleting existing user_achievements records. | required |
requires_module |
string |
Area/module ID that must be enabled for this tenant before the achievement is visible and unlockable (e.g. 'achievements-gamification', 'certification-training'). | - |
sort_order |
integer |
Display order on BadgesScreen within the same category. | required |
created_at |
datetime |
Record creation timestamp. | required |
updated_at |
datetime |
Last modification timestamp. | required |
Database Indexes
idx_achievements_org_key
Columns: organization_id, key
idx_achievements_category
Columns: category, sort_order
idx_achievements_trigger_type
Columns: trigger_type, is_active
idx_achievements_org_active
Columns: organization_id, is_active
Validation Rules
key_format
error
Validation failed
threshold_required_for_count_triggers
error
Validation failed
icon_url_format
warning
Validation failed
points_non_negative
error
Validation failed
name_not_empty
error
Validation failed
Business Rules
module_gate
An achievement is only visible and unlockable for a tenant if the tenant has the requires_module area enabled (or requires_module is NULL for platform-wide badges). AchievementService filters the catalog against the tenant's active module set at query time.
one_time_per_user
For non-repeatable achievements (is_repeatable = false), a user may only hold one user_achievements record per achievement ID. AchievementService checks for an existing record before inserting.
repeat_period_requires_repeatable
repeat_period may only be set when is_repeatable = true. Saving a non-repeatable achievement with a repeat_period value is rejected.
inactive_not_awarded
Achievements with is_active = false are not evaluated for unlocking and are hidden from BadgesScreen. Existing user_achievements records for inactive achievements are retained but not surfaced.
platform_badge_immutable
Achievements with organization_id = NULL are platform-wide definitions and may only be created or modified by a Global Administrator. Organization-scoped admins cannot alter them.
annual_badge_annual_summary_link
Achievements with trigger_type = 'annual_summary' are unlocked exactly once per calendar year per user, driven by the AnnualSummaryService completing the year's Wrapped generation.