Skip to content

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 d44a174) was successful.

Resource Changes

    Name                                                       Type                                  Operation
~   vpc-native-check-analytics-report-cron                     kubernetes:batch/v1:CronJob           update
~   vpc-native-update-views-cron                               kubernetes:batch/v1:CronJob           update
~   vpc-native-post-analytics-clickhouse-cron                  kubernetes:batch/v1:CronJob           update
~   vpc-native-deployment                                      kubernetes:apps/v1:Deployment         update
~   vpc-native-update-trending-cron                            kubernetes:batch/v1:CronJob           update
~   vpc-native-clean-zombie-user-companies-cron                kubernetes:batch/v1:CronJob           update
~   vpc-native-hourly-notification-cron                        kubernetes:batch/v1:CronJob           update
~   vpc-native-user-profile-analytics-clickhouse-cron          kubernetes:batch/v1:CronJob           update
~   vpc-native-calculate-top-readers-cron                      kubernetes:batch/v1:CronJob           update
~   vpc-native-clean-gifted-plus-cron                          kubernetes:batch/v1:CronJob           update
~   vpc-native-user-profile-analytics-history-clickhouse-cron  kubernetes:batch/v1:CronJob           update
-   vpc-native-api-db-migration-c6add5ab                       kubernetes:batch/v1:Job               delete
~   vpc-native-sync-subscription-with-cio-cron                 kubernetes:batch/v1:CronJob           update
+   vpc-native-api-db-migration-478f04d7                       kubernetes:batch/v1:Job               create
-   vpc-native-api-clickhouse-migration-c6add5ab               kubernetes:batch/v1:Job               delete
~   vpc-native-update-source-tag-view-cron                     kubernetes:batch/v1:CronJob           update
~   vpc-native-personalized-digest-deployment                  kubernetes:apps/v1:Deployment         update
~   vpc-native-update-tags-str-cron                            kubernetes:batch/v1:CronJob           update
~   vpc-native-validate-active-users-cron                      kubernetes:batch/v1:CronJob           update
~   vpc-native-update-tag-recommendations-cron                 kubernetes:batch/v1:CronJob           update
+   api-sub-api.achievement-unlocked-notification              gcp:pubsub/subscription:Subscription  create
~   vpc-native-temporal-deployment                             kubernetes:apps/v1:Deployment         update
~   vpc-native-clean-zombie-images-cron                        kubernetes:batch/v1:CronJob           update
~   vpc-native-personalized-digest-cron                        kubernetes:batch/v1:CronJob           update
~   vpc-native-bg-deployment                                   kubernetes:apps/v1:Deployment         update
+   vpc-native-api-clickhouse-migration-478f04d7               kubernetes:batch/v1:Job               create
~   vpc-native-generic-referral-reminder-cron                  kubernetes:batch/v1:CronJob           update
~   vpc-native-generate-search-invites-cron                    kubernetes:batch/v1:CronJob           update
~   vpc-native-clean-zombie-users-cron                         kubernetes:batch/v1:CronJob           update
~   vpc-native-update-highlighted-views-cron                   kubernetes:batch/v1:CronJob           update
~   vpc-native-update-current-streak-cron                      kubernetes:batch/v1:CronJob           update
~   vpc-native-clean-zombie-opportunities-cron                 kubernetes:batch/v1:CronJob           update
~   vpc-native-user-profile-updated-sync-cron                  kubernetes:batch/v1:CronJob           update
~   vpc-native-expire-super-agent-trial-cron                   kubernetes:batch/v1:CronJob           update
~   vpc-native-ws-deployment                                   kubernetes:apps/v1:Deployment         update
~   vpc-native-clean-stale-user-transactions-cron              kubernetes:batch/v1:CronJob           update
-   vpc-native-user-posts-analytics-refresh-cron               kubernetes:batch/v1:CronJob           delete
~   vpc-native-update-source-public-threshold-cron             kubernetes:batch/v1:CronJob           update
~   vpc-native-post-analytics-history-day-clickhouse-cron      kubernetes:batch/v1:CronJob           update
~   vpc-native-daily-digest-cron                               kubernetes:batch/v1:CronJob           update
~   vpc-native-private-deployment                              kubernetes:apps/v1:Deployment         update
... and 2 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