Skip to content

Conversation

@brandonkachen
Copy link
Collaborator

@brandonkachen brandonkachen commented Jan 26, 2026

📊 Impact: +71 / -75 lines (excluding tests and autogenerated files)

Summary

This PR changes the referral program from granting recurring monthly credits to one-time bonus credits that never expire. Existing (legacy) recurring referral bonuses are grandfathered and will continue to renew monthly.

Changes

Core Feature

  • Referral grants are now one-time, non-expiring: New referral bonuses set expires_at: null instead of the user's next quota reset date
  • Added is_legacy column: Tracks whether a referral grant is legacy (recurring monthly) or new (one-time)
  • New referral_legacy grant type: Separate grant type for grandfathered recurring referrals with priority 30 (consumed first)
  • Database migration: Adds the is_legacy column and referral_legacy enum value

Grant Priority Changes

  • referral_legacy (priority 30): Consumed first, renews monthly for grandfathered users
  • referral (priority 50): One-time bonus, never expires, preserved longer

UI Updates

  • Profile referrals section now shows "per month" only for legacy referrals
  • Legacy referrals display "(legacy)" label in the referral list
  • Usage display shows "Referral Bonus (Legacy)" for recurring grants

API Changes

  • /api/referrals now returns is_legacy field
  • redeemReferralCode creates grants with type: 'referral', expiresAt: null, is_legacy: false
  • calculateTotalLegacyReferralBonus only counts referrals where is_legacy = true

Files Changed

  • common/src/types/grant.ts - Added referral_legacy grant type
  • common/src/constants/grant-priorities.ts - Updated priorities
  • packages/billing/src/grant-credits.ts - Use referral_legacy for monthly renewal
  • packages/internal/src/db/schema.ts - Added is_legacy column
  • web/src/app/api/referrals/helpers.ts - One-time grants with null expiry
  • web/src/app/api/referrals/route.ts - Added is_legacy to response
  • web/src/app/profile/components/referrals-section.tsx - Badge & label updates
  • web/src/app/profile/components/usage-display.tsx - Added referral_legacy display

@brandonkachen brandonkachen changed the title feat(billing): convert referral bonuses from monthly recurring to one-time feat(billing): Convert referral bonuses from monthly recurring to one-time credits Jan 27, 2026
- Add referral_legacy to GrantType union and GrantTypeValues array
- Update GRANT_PRIORITIES: referral_legacy=30 (consumed first, renews monthly), referral=50 (one-time, preserved longer)
- Add consumption order comment for clarity
- Add is_legacy boolean column to referral table (default false)
- Migration adds referral_legacy enum value to grant_type
- Backfills existing referrals as is_legacy=true (grandfathered users)
- Migrates existing credit_ledger referral grants with expiry to referral_legacy type
…rals

- Rename calculateTotalReferralBonus to calculateTotalLegacyReferralBonus
- Filter by is_legacy=true to only count grandfathered referrals
- Use referral_legacy type for monthly renewal grants
- Update test mocks to include referral_legacy in breakdown/principals
- Set expiresAt: null for new referral grants (never expire)
- Set is_legacy: false for new referrals (new program)
- Remove unnecessary user.next_quota_reset query
- Consolidate duplicate grant code into reusable grantForUser helper
- Add referral_legacy to grantTypeInfo with emerald color and Legacy label
- Update description: referral is now "One-time bonus from referrals"
- Move referral from expiringTypes to nonExpiringTypes
- Add referral_legacy to expiringTypes (renews monthly)
- Add is_legacy field to referrals API response
- Update CreditsBadge to show "per month" for legacy, "(one-time)" for new
- Add "(legacy)" label next to legacy referrals in the list
- Change main description to "one-time bonus" instead of "per month"
- Add defensive default for is_legacy in Zod schema
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