fix: sync subscription tier on admin override (refs #58)
Add adminOverrideTier() method to SubscriptionsService that atomically updates both subscriptions.tier and user_profiles.subscription_tier using database transactions. Changes: - SubscriptionsRepository: Add updateTierByUserId() and createForAdminOverride() methods with transaction support - SubscriptionsService: Add adminOverrideTier() method with transaction wrapping for atomic dual-table updates - UsersController: Replace userProfileService.updateSubscriptionTier() with subscriptionsService.adminOverrideTier() This ensures admin tier changes properly sync to both database tables, fixing the Settings page "Current Plan" display mismatch. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -728,6 +728,67 @@ export class SubscriptionsService {
|
||||
return 'free';
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin override of subscription tier (bypasses Stripe)
|
||||
* Updates both subscriptions.tier and user_profiles.subscription_tier atomically
|
||||
* Creates subscription record if user doesn't have one
|
||||
*
|
||||
* Note: Admin feature depends on Subscriptions for tier management
|
||||
* This is intentional - admin has oversight capabilities
|
||||
*/
|
||||
async adminOverrideTier(userId: string, newTier: SubscriptionTier): Promise<Subscription> {
|
||||
const pool = this.repository.getPool();
|
||||
const client = await pool.connect();
|
||||
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
|
||||
logger.info('Admin overriding subscription tier', { userId, newTier });
|
||||
|
||||
// Check if user has a subscription record
|
||||
let subscription = await this.repository.findByUserId(userId);
|
||||
|
||||
if (!subscription) {
|
||||
// Create subscription record for user (admin override bypasses Stripe)
|
||||
logger.info('Creating subscription record for admin override', { userId, newTier });
|
||||
subscription = await this.repository.createForAdminOverride(userId, newTier, client);
|
||||
} else {
|
||||
// Update existing subscription tier
|
||||
const updated = await this.repository.updateTierByUserId(userId, newTier, client);
|
||||
if (!updated) {
|
||||
throw new Error('Failed to update subscription tier');
|
||||
}
|
||||
subscription = updated;
|
||||
}
|
||||
|
||||
// Sync tier to user_profiles table (within same transaction)
|
||||
await client.query(
|
||||
'UPDATE user_profiles SET subscription_tier = $1 WHERE auth0_sub = $2',
|
||||
[newTier, userId]
|
||||
);
|
||||
|
||||
await client.query('COMMIT');
|
||||
|
||||
logger.info('Admin subscription tier override complete', {
|
||||
userId,
|
||||
newTier,
|
||||
subscriptionId: subscription.id,
|
||||
});
|
||||
|
||||
return subscription;
|
||||
} catch (error: any) {
|
||||
await client.query('ROLLBACK');
|
||||
logger.error('Failed to admin override subscription tier', {
|
||||
userId,
|
||||
newTier,
|
||||
error: error.message,
|
||||
});
|
||||
throw error;
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get invoices for a user's subscription
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user