Files
thrilltrack-explorer/docs/NOVU_MIGRATION.md
2025-10-01 12:29:31 +00:00

305 lines
8.1 KiB
Markdown

# Migrating from Legacy to Novu Notifications
This guide covers migrating from the old notification system to the new Novu-powered system.
## Migration Overview
The new notification system:
- Uses Novu for multi-channel delivery
- Supports granular preferences per workflow
- Includes frequency controls
- Provides delivery tracking
- Backwards compatible with existing preferences
## Data Migration
### Step 1: Migrate Existing User Preferences
The system automatically migrates old preferences from `user_preferences.email_notifications` and `user_preferences.push_notifications` to the new `user_notification_preferences` table.
Run this migration script to batch migrate existing users:
```sql
-- Migrate existing users to new notification preferences
INSERT INTO user_notification_preferences (
user_id,
channel_preferences,
workflow_preferences,
frequency_settings
)
SELECT
user_id,
jsonb_build_object(
'in_app', true,
'email', COALESCE((email_notifications->>'system_announcements')::boolean, true),
'push', COALESCE((push_notifications->>'browser_enabled')::boolean, false),
'sms', false
),
jsonb_build_object(
'review-reply', COALESCE((email_notifications->>'review_replies')::boolean, true),
'new-follower', COALESCE((email_notifications->>'new_followers')::boolean, true),
'system-announcement', COALESCE((email_notifications->>'system_announcements')::boolean, true),
'weekly-digest', COALESCE((email_notifications->>'weekly_digest')::boolean, false),
'monthly-digest', COALESCE((email_notifications->>'monthly_digest')::boolean, true)
),
jsonb_build_object(
'digest', 'daily',
'max_per_hour', 10
)
FROM user_preferences
WHERE NOT EXISTS (
SELECT 1 FROM user_notification_preferences
WHERE user_notification_preferences.user_id = user_preferences.user_id
);
```
### Step 2: Create Novu Subscribers for Existing Users
Create a batch script to register all existing users as Novu subscribers:
```typescript
import { supabase } from '@/integrations/supabase/client';
import { notificationService } from '@/lib/notificationService';
async function migrateUsersToNovu() {
const { data: profiles, error } = await supabase
.from('profiles')
.select('user_id, username, display_name')
.is('banned', false);
if (error) {
console.error('Error fetching profiles:', error);
return;
}
for (const profile of profiles) {
// Get user's auth data for email
const { data: { user } } = await supabase.auth.admin.getUserById(profile.user_id);
if (user?.email) {
await notificationService.createSubscriber({
subscriberId: profile.user_id,
email: user.email,
firstName: profile.display_name?.split(' ')[0],
lastName: profile.display_name?.split(' ').slice(1).join(' '),
data: {
username: profile.username,
},
});
console.log(`Migrated user: ${profile.username}`);
// Rate limit to avoid overwhelming Novu API
await new Promise(resolve => setTimeout(resolve, 100));
}
}
console.log('Migration complete!');
}
```
## Code Migration
### Updating Notification Triggers
**Old Way:**
```typescript
// Direct database insert (legacy)
await supabase
.from('notifications')
.insert({
user_id: userId,
type: 'review_reply',
content: 'Someone replied to your review',
});
```
**New Way:**
```typescript
// Using Novu via notificationService
import { notificationService } from '@/lib/notificationService';
await notificationService.trigger({
workflowId: 'review-reply',
subscriberId: userId,
payload: {
reviewTitle: 'Great ride!',
replyAuthor: 'Jane Doe',
replyContent: 'Thanks for the review!',
reviewUrl: `/reviews/${reviewId}`,
},
});
```
### Updating Preference Management
**Old Way:**
```typescript
await supabase
.from('user_preferences')
.update({
email_notifications: {
review_replies: false,
},
})
.eq('user_id', userId);
```
**New Way:**
```typescript
import { notificationService } from '@/lib/notificationService';
await notificationService.updatePreferences(userId, {
channelPreferences: {
in_app: true,
email: true,
push: false,
sms: false,
},
workflowPreferences: {
'review-reply': false,
},
frequencySettings: {
digest: 'daily',
max_per_hour: 10,
},
});
```
## Rollback Plan
If you need to rollback to the old system:
1. **Keep Old Tables**: Don't drop `user_preferences.email_notifications` or `push_notifications` columns
2. **Disable Novu**: Clear `VITE_NOVU_APPLICATION_IDENTIFIER` environment variable
3. **Revert Code**: The notification service gracefully handles missing Novu config
## Testing the Migration
### Test Checklist
- [ ] All existing users have entries in `user_notification_preferences`
- [ ] User preferences match their previous settings
- [ ] Test users receive notifications on all enabled channels
- [ ] Webhook is receiving delivery events
- [ ] Notification logs are being created
- [ ] User preference changes sync to Novu
- [ ] Unsubscribe links work correctly
- [ ] Email templates render correctly
- [ ] Push notifications work in supported browsers
- [ ] In-app notifications display correctly
### Test Script
```typescript
// Test notification delivery
import { notificationService } from '@/lib/notificationService';
async function testNotifications(testUserId: string) {
console.log('Testing notification delivery...');
// Test each workflow
const workflows = [
{
id: 'review-reply',
payload: {
reviewTitle: 'Test Review',
replyAuthor: 'Test User',
replyContent: 'Test reply content',
reviewUrl: '/test',
},
},
{
id: 'new-follower',
payload: {
followerName: 'Test Follower',
followerProfile: '/profile/test',
},
},
];
for (const workflow of workflows) {
const result = await notificationService.trigger({
workflowId: workflow.id,
subscriberId: testUserId,
payload: workflow.payload,
});
console.log(`${workflow.id}: ${result.success ? '✓' : '✗'}`);
if (!result.success) {
console.error(`Error: ${result.error}`);
}
}
}
```
## Performance Considerations
### Batch Operations
When migrating large numbers of users:
1. **Rate Limiting**: Add delays between API calls
2. **Batch Size**: Process in chunks of 100-500 users
3. **Error Handling**: Log failures and retry
4. **Progress Tracking**: Store migration state
### Optimization Tips
1. **Cache Templates**: Load notification templates once at startup
2. **Async Processing**: Use edge functions for heavy operations
3. **Database Indexes**: Already created on `user_notification_preferences`
4. **Connection Pooling**: Supabase handles this automatically
## Monitoring Post-Migration
Track these metrics after migration:
```sql
-- Delivery success rate
SELECT
DATE(created_at) as date,
COUNT(*) FILTER (WHERE status = 'delivered') * 100.0 / COUNT(*) as success_rate
FROM notification_logs
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY DATE(created_at)
ORDER BY date DESC;
-- Channel usage
SELECT
channel,
COUNT(*) as total_sent,
COUNT(*) FILTER (WHERE status = 'delivered') as delivered,
COUNT(*) FILTER (WHERE read_at IS NOT NULL) as read
FROM notification_logs
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY channel;
-- User engagement
SELECT
COUNT(DISTINCT user_id) as active_users,
AVG(EXTRACT(EPOCH FROM (read_at - delivered_at))) as avg_time_to_read_seconds
FROM notification_logs
WHERE read_at IS NOT NULL
AND created_at > NOW() - INTERVAL '7 days';
```
## Support During Migration
1. **Backup Data**: Export old notification preferences before migration
2. **Phased Rollout**: Enable for a subset of users first
3. **Feature Flag**: Use admin settings to control Novu enablement
4. **User Communication**: Notify users of new notification features
5. **Monitor Logs**: Watch edge function logs during migration
## Timeline
Recommended migration timeline:
- **Week 1**: Test with internal users
- **Week 2**: Rollout to 10% of users
- **Week 3**: Rollout to 50% of users
- **Week 4**: Complete rollout
- **Week 5**: Remove legacy code (optional)