Skip to content

feat: add achievement system for user gamification#3530

Open
AmarTrebinjac wants to merge 6 commits intomainfrom
eng-558-achievements
Open

feat: add achievement system for user gamification#3530
AmarTrebinjac wants to merge 6 commits intomainfrom
eng-558-achievements

Conversation

@AmarTrebinjac
Copy link
Contributor

Summary

  • Adds Achievement and UserAchievement entities with database migrations to track user progress
  • Implements GraphQL schema for querying achievements (available, in-progress, and completed)
  • Integrates CDC workers to track progress across multiple event types (posts, comments, upvotes, profile updates, squad membership, etc.)
  • Adds notification system support for achievement unlock events

Test plan

  • Run migrations to create achievement tables
  • Verify achievement definitions are seeded correctly
  • Test GraphQL queries return expected achievement data
  • Validate CDC workers correctly increment progress counters
  • Confirm notifications trigger when achievements are unlocked

Closes ENG-558

Created by Huginn 🐦‍⬛

Implements a comprehensive achievement system including:
- Achievement and UserAchievement entities with database migrations
- GraphQL schema for querying user achievements
- Achievement progress tracking via CDC workers for various events
  (posts, comments, upvotes, profile updates, squads, etc.)
- Notification system integration for achievement unlocks
- PubSub event for achievement-unlocked notifications

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@pulumi
Copy link

pulumi bot commented Feb 2, 2026

🍹 The Update (preview) for dailydotdev/api/prod (at fc86fae) was successful.

Resource Changes

    Name                                                       Type                                  Operation
~   vpc-native-sync-subscription-with-cio-cron                 kubernetes:batch/v1:CronJob           update
~   vpc-native-update-tag-recommendations-cron                 kubernetes:batch/v1:CronJob           update
~   vpc-native-calculate-top-readers-cron                      kubernetes:batch/v1:CronJob           update
~   vpc-native-temporal-deployment                             kubernetes:apps/v1:Deployment         update
~   vpc-native-deployment                                      kubernetes:apps/v1:Deployment         update
~   vpc-native-ws-deployment                                   kubernetes:apps/v1:Deployment         update
~   vpc-native-generic-referral-reminder-cron                  kubernetes:batch/v1:CronJob           update
~   vpc-native-clean-stale-user-transactions-cron              kubernetes:batch/v1:CronJob           update
~   vpc-native-post-analytics-clickhouse-cron                  kubernetes:batch/v1:CronJob           update
~   vpc-native-user-posts-analytics-refresh-cron               kubernetes:batch/v1:CronJob           update
~   vpc-native-clean-zombie-images-cron                        kubernetes:batch/v1:CronJob           update
~   vpc-native-update-views-cron                               kubernetes:batch/v1:CronJob           update
~   vpc-native-update-source-public-threshold-cron             kubernetes:batch/v1:CronJob           update
~   vpc-native-bg-deployment                                   kubernetes:apps/v1:Deployment         update
~   vpc-native-user-profile-analytics-history-clickhouse-cron  kubernetes:batch/v1:CronJob           update
-   vpc-native-api-clickhouse-migration-6fecb4a5               kubernetes:batch/v1:Job               delete
+-  vpc-native-debezium-deployment                             kubernetes:apps/v1:Deployment         create-replacement
+   vpc-native-api-db-migration-9e463a7e                       kubernetes:batch/v1:Job               create
~   vpc-native-clean-gifted-plus-cron                          kubernetes:batch/v1:CronJob           update
~   vpc-native-personalized-digest-cron                        kubernetes:batch/v1:CronJob           update
~   vpc-native-validate-active-users-cron                      kubernetes:batch/v1:CronJob           update
~   vpc-native-check-analytics-report-cron                     kubernetes:batch/v1:CronJob           update
~   vpc-native-user-profile-analytics-clickhouse-cron          kubernetes:batch/v1:CronJob           update
~   vpc-native-update-source-tag-view-cron                     kubernetes:batch/v1:CronJob           update
+   api-sub-api.achievement-unlocked-notification              gcp:pubsub/subscription:Subscription  create
+   vpc-native-api-clickhouse-migration-9e463a7e               kubernetes:batch/v1:Job               create
~   vpc-native-daily-digest-cron                               kubernetes:batch/v1:CronJob           update
~   vpc-native-update-highlighted-views-cron                   kubernetes:batch/v1:CronJob           update
~   vpc-native-hourly-notification-cron                        kubernetes:batch/v1:CronJob           update
~   vpc-native-post-analytics-history-day-clickhouse-cron      kubernetes:batch/v1:CronJob           update
~   vpc-native-clean-zombie-user-companies-cron                kubernetes:batch/v1:CronJob           update
~   vpc-native-update-current-streak-cron                      kubernetes:batch/v1:CronJob           update
~   vpc-native-clean-zombie-users-cron                         kubernetes:batch/v1:CronJob           update
~   vpc-native-private-deployment                              kubernetes:apps/v1:Deployment         update
~   vpc-native-clean-zombie-opportunities-cron                 kubernetes:batch/v1:CronJob           update
~   vpc-native-expire-super-agent-trial-cron                   kubernetes:batch/v1:CronJob           update
~   vpc-native-update-trending-cron                            kubernetes:batch/v1:CronJob           update
-   vpc-native-api-db-migration-6fecb4a5                       kubernetes:batch/v1:Job               delete
+-  vpc-native-debezium-props                                  kubernetes:core/v1:Secret             create-replacement
~   vpc-native-user-profile-updated-sync-cron                  kubernetes:batch/v1:CronJob           update
~   vpc-native-generate-search-invites-cron                    kubernetes:batch/v1:CronJob           update
... and 4 other changes

where: { userId, achievementId },
});

if (!userAchievement) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

})
id: string;

@Column({ default: () => 'now()' })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CreateDateColumn

})
userId: string;

@Column({ default: () => 'now()' })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CreateDateColumn

public async up(queryRunner: QueryRunner): Promise<void> {
// Create achievement_type enum
await queryRunner.query(`
CREATE TYPE "achievement_type_enum" AS ENUM (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, sql side enums are a PITA to work with when they need to be updated, because you can't remove values from it, it has to be re-created

@AmarTrebinjac
Copy link
Contributor Author

@claude Please consider @omBratteng feedback. Specifically about using enums in the database. It'd be better if they were regular strings in our database, and our enum type having the string as values instead.

@claude
Copy link

claude bot commented Feb 3, 2026

Claude finished @AmarTrebinjac's task in 1m 4s —— View job


Refactoring achievement enums to use strings

I've analyzed the current implementation and found that while the entity files are correctly configured, the migration file needs to be updated to remove unused SQL ENUM types.

Analysis

Good news: The TypeScript entity files are already correctly set up:

  • Achievement.ts:9-36: TypeScript enums use string values (AchievementType, AchievementEventType)
  • Achievement.ts:67-73: Database columns use text type (not SQL ENUMs)

Issue: The migration 1770072115384-AchievementSystem.ts creates SQL ENUMs that are never actually used by the schema:

  • Lines 7-15: Creates achievement_type_enum
  • Lines 17-40: Creates achievement_event_type_enum
  • Lines 118-120: Drops these enums in the down migration

These enum types are problematic because:

  1. They're not actually used (the columns are text type)
  2. SQL enums are difficult to modify (can't remove values, must be recreated)
  3. They add unnecessary complexity

Required Changes

Since migration files are protected in this repository, you'll need to manually update src/migration/1770072115384-AchievementSystem.ts:

In the up method, remove lines 7-40:

// Remove this entire section:
// Create achievement_type enum
await queryRunner.query(`
  CREATE TYPE "achievement_type_enum" AS ENUM (
    'instant',
    'streak',
    'milestone',
    'multipart'
  )
`);

// Create achievement_event_type enum
await queryRunner.query(`
  CREATE TYPE "achievement_event_type_enum" AS ENUM (
    'post_upvote',
    'comment_upvote',
    'bookmark_post',
    'profile_image_update',
    'profile_cover_update',
    'profile_location_update',
    'experience_work',
    'experience_education',
    'experience_opensource',
    'experience_project',
    'experience_volunteering',
    'experience_skill',
    'hot_take_create',
    'post_share',
    'post_freeform',
    'squad_join',
    'squad_create',
    'brief_read',
    'reputation_gain'
  )
`);

In the down method, remove lines 118-120:

// Remove these lines:
// Drop enums
await queryRunner.query(`DROP TYPE "achievement_event_type_enum"`);
await queryRunner.query(`DROP TYPE "achievement_type_enum"`);

After these changes:

  • The migration will only create tables with text columns
  • TypeScript enums will provide type safety at the application level
  • No SQL enums will exist in the database
  • Future enum value changes will be trivial (just update TypeScript code)

Summary

The entity files don't need any changes - they're already using the correct pattern. Only the migration file needs to be cleaned up to remove the unused SQL ENUM creation/deletion statements.

--- | Branch: eng-558-achievements

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants