Badge
Data Entity
Description
Represents a named achievement or recognition milestone that can be awarded to peer mentors and coordinators. Badges are platform-defined definitions; actual awards are recorded in user_achievements. Part of the Achievements & Gamification system inspired by Spotify Wrapped and volunteer recognition goals.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key — stable identifier referenced by user_achievements | PKrequiredunique |
slug |
string |
URL-safe unique identifier used in deep links and API paths (e.g. 'first-activity', 'century-club') | requiredunique |
name |
string |
Display name shown in the Badges Gallery and award notifications | required |
description |
text |
Human-readable explanation of what must be achieved to earn this badge, shown in gallery and award screen | required |
category |
enum |
Logical grouping for gallery display and filtering | required |
tier |
enum |
Prestige level controlling visual treatment (border, glow) in gallery | required |
icon_asset_key |
string |
Key referencing the badge icon in the app asset bundle or CDN path (e.g. 'badges/century_club.svg') | required |
award_criteria |
json |
Machine-readable criteria evaluated by badge-award-service. Structure varies by category: { type: 'activity_count', threshold: 100 } | { type: 'consecutive_months', threshold: 6 } | { type: 'manual' } | required |
is_repeatable |
boolean |
Whether a user can earn this badge multiple times (e.g. annual badges reset yearly) | required |
is_active |
boolean |
Soft-disables a badge definition without deleting it. Inactive badges are hidden from the gallery and excluded from award evaluation. | required |
is_visible_before_award |
boolean |
Controls whether locked badge appears greyed-out in gallery (true) or is hidden entirely until awarded (false) | required |
sort_order |
integer |
Display ordering within category in Badges Gallery Screen | - |
valid_from |
datetime |
Earliest timestamp from which this badge can be awarded. Null means no lower bound (available immediately). | - |
valid_until |
datetime |
Last timestamp at which this badge can be awarded. Used for seasonal/limited-time badges. Null means perpetual. | - |
created_at |
datetime |
Record creation timestamp | required |
updated_at |
datetime |
Last modification timestamp | required |
Database Indexes
idx_badges_slug
Columns: slug
idx_badges_category_sort
Columns: category, sort_order
idx_badges_active
Columns: is_active
idx_badges_valid_window
Columns: valid_from, valid_until
Validation Rules
slug_format
error
Validation failed
slug_unique
error
Validation failed
valid_window_ordering
error
Validation failed
icon_asset_key_not_empty
error
Validation failed
award_criteria_valid_json
error
Validation failed
Business Rules
no_delete_awarded_badge
A badge definition that has been awarded to at least one user (has rows in user_achievements) cannot be hard-deleted. It must be deactivated via is_active=false to preserve referential integrity and award history.
inactive_badge_excluded_from_evaluation
Badge award evaluation cron/trigger must skip badges where is_active=false. Avoids awarding badges that have been retired.
seasonal_badge_validity_window
A badge with valid_from/valid_until set may only be awarded within that window. Evaluation must check current timestamp against the window before creating a user_achievements record.
non_repeatable_once_per_user
If is_repeatable=false, badge-award-service must verify no existing user_achievements row exists for (user_id, badge_id) before awarding. Duplicate award attempts are silently skipped, not errored.
criteria_schema_must_match_category
award_criteria JSON structure must be valid for the badge's category. Activity badges require 'threshold' integer; manual badges require type='manual'. Enforced at creation/update.