Badges & Achievements
The Business Platform includes a badge system that rewards users for reaching key milestones. Badges are awarded automatically when a user completes a specific action for the first time.
Available Badges
| Badge | Name | Description |
|---|---|---|
| π Project Created | projectCreated |
Awarded when a user creates their first project |
| β‘ First Action Created | firstActionCreated |
Awarded when a user creates their first action within a project |
| π± First Application Created | firstApplicationCreated |
Awarded when a user creates their first application within a project |
| π₯ First Project Member Invite | firstProjectMemberInvite |
Awarded when a user invites a member to a project for the first time |
| ποΈ First Data Type Created | firstDataTypeCreated |
Awarded when a user creates their first data type within a project |
How Badges Are Earned
Badges are awarded automatically on the server side when a qualifying action is successfully completed. Each badge is awarded only once per user β if a user has already earned a badge, subsequent qualifying actions do not re-award it.
When a badge is newly awarded, the user receives an in-app system notification confirming the achievement.
Trigger Points
| Badge | Trigger |
|---|---|
projectCreated |
POST /api/projects β after a project is successfully created |
firstActionCreated |
POST /api/projects/[projectId]/actions β after an action is successfully created |
firstApplicationCreated |
POST /api/projects/[projectId]/applications β after an application is successfully created |
firstProjectMemberInvite |
Awarded when a project member invitation is sent for the first time |
firstDataTypeCreated |
Awarded when the first data type is created within a project |
Viewing Your Badges
Users can view their earned and locked badges through the profile menu:
- Open the User Profile panel (top-right avatar or profile button).
- Click the Badges button (trophy icon).
- The badges modal displays:
- Earned badges β shown with a green border, the badge icon in full colour, and the date the badge was earned.
- Locked badges β shown with a grey border and a greyscale icon, indicating they have not yet been earned.
The modal also shows a summary count, e.g. Earned Badges: 2 / 5.
Technical Reference
Shared Package
Badge names are defined as constants in packages/shared/src/utils/badge.utils.ts:
import { BADGE_NAMES } from "@smallstack/shared";
BADGE_NAMES.PROJECT_CREATED // "projectCreated"
BADGE_NAMES.FIRST_ACTION_CREATED // "firstActionCreated"
BADGE_NAMES.FIRST_APPLICATION_CREATED // "firstApplicationCreated"
BADGE_NAMES.FIRST_PROJECT_MEMBER_INVITE // "firstProjectMemberInvite"
BADGE_NAMES.FIRST_DATA_TYPE_CREATED // "firstDataTypeCreated"
The BadgeDefinition interface and helper functions getAllBadgeDefinitions() and getBadgeDefinition(name) are also exported from @smallstack/shared.
Earned badges are stored on the User object as an array of EarnedBadge entries:
interface EarnedBadge {
name: string; // badge identifier
earnedAt: number; // Unix timestamp (ms)
}
Server Package
The checkBadge utility in packages/server/src/utils/badge.server.ts handles badge awarding:
import { checkBadge } from "@smallstack/server";
import { BADGE_NAMES } from "@smallstack/shared";
await checkBadge(BADGE_NAMES.PROJECT_CREATED, userId);
checkBadge performs the following steps atomically within a transaction:
- Fetches the latest user record from the database.
- Checks whether the badge has already been earned.
- If not, appends the new
EarnedBadgeentry and persists the update via a patch operation. - Sends a system notification message to the user.
- Returns
trueif the badge was newly awarded, orfalseif it was already present.
Errors during badge awarding are caught and logged, and do not interrupt the parent request.
Adding a New Badge
- Add a new key to
BADGE_NAMESinpackages/shared/src/utils/badge.utils.ts. - Add a corresponding
BadgeDefinitionentry to theBADGE_DEFINITIONSarray (including an icon URL, and i18n label/description keys). - Add the i18n translation strings for the new
labelKeyanddescriptionKey. - Call
checkBadge(BADGE_NAMES.YOUR_NEW_BADGE, userId)at the appropriate server-side endpoint after the qualifying action succeeds.