diff --git a/docs/NOVU_MIGRATION.md b/docs/NOVU_MIGRATION.md new file mode 100644 index 00000000..4b0af4fe --- /dev/null +++ b/docs/NOVU_MIGRATION.md @@ -0,0 +1,304 @@ +# 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) diff --git a/docs/NOVU_SETUP.md b/docs/NOVU_SETUP.md new file mode 100644 index 00000000..e876bf94 --- /dev/null +++ b/docs/NOVU_SETUP.md @@ -0,0 +1,238 @@ +# Novu Cloud Integration Setup Guide + +This guide will help you set up and configure Novu Cloud for the ThrillWiki notification system. + +## Overview + +The notification system uses Novu Cloud for managing multi-channel notifications including: +- In-app notifications +- Email notifications +- Push notifications +- SMS notifications (planned) + +## Prerequisites + +1. A Novu Cloud account (sign up at https://novu.co) +2. Access to the Supabase project +3. Environment variable configuration access + +## Step 1: Create a Novu Cloud Account + +1. Go to https://novu.co and sign up +2. Create a new application in the Novu dashboard +3. Note down your **Application Identifier** from the Settings page + +## Step 2: Configure Environment Variables + +Add the following environment variables to your `.env` file: + +```bash +# Novu Configuration +VITE_NOVU_APPLICATION_IDENTIFIER="your-app-identifier" +VITE_NOVU_SOCKET_URL="wss://ws.novu.co" +VITE_NOVU_API_URL="https://api.novu.co" +``` + +## Step 3: Add Novu API Key to Supabase Secrets + +The Novu API key needs to be stored as a Supabase secret (already done via the setup): + +1. Go to your Novu dashboard +2. Navigate to Settings > API Keys +3. Copy your API Key +4. The secret `NOVU_API_KEY` should already be configured in Supabase + +## Step 4: Create Novu Workflows + +Create the following workflows in your Novu dashboard to match the templates in the database: + +### 1. Review Reply (`review-reply`) +**Trigger Identifier:** `review-reply` +**Channels:** Email, In-App +**Payload Variables:** +- `reviewTitle` - Title of the review +- `replyAuthor` - Name of the person who replied +- `replyContent` - Content of the reply +- `reviewUrl` - Link to the review + +### 2. New Follower (`new-follower`) +**Trigger Identifier:** `new-follower` +**Channels:** Email, In-App, Push +**Payload Variables:** +- `followerName` - Name of the new follower +- `followerProfile` - Link to the follower's profile + +### 3. System Announcement (`system-announcement`) +**Trigger Identifier:** `system-announcement` +**Channels:** Email, In-App, Push +**Payload Variables:** +- `title` - Announcement title +- `content` - Announcement content +- `priority` - Priority level (info, warning, critical) + +### 4. Weekly Digest (`weekly-digest`) +**Trigger Identifier:** `weekly-digest` +**Channels:** Email +**Payload Variables:** +- `userName` - User's name +- `weekStart` - Start date of the week +- `weekEnd` - End date of the week +- `stats` - Activity statistics object +- `highlights` - Array of highlighted content + +### 5. Monthly Digest (`monthly-digest`) +**Trigger Identifier:** `monthly-digest` +**Channels:** Email +**Payload Variables:** +- `userName` - User's name +- `month` - Month name +- `stats` - Monthly statistics object +- `topContent` - Array of popular content + +### 6. Moderation Alert (`moderation-alert`) +**Trigger Identifier:** `moderation-alert` +**Channels:** Email, In-App +**Payload Variables:** +- `itemType` - Type of content (review, photo, etc.) +- `itemId` - ID of the item +- `submitterName` - Name of the submitter +- `moderationUrl` - Link to moderation queue + +### 7. Content Approved (`content-approved`) +**Trigger Identifier:** `content-approved` +**Channels:** Email, In-App +**Payload Variables:** +- `contentType` - Type of content +- `contentTitle` - Title/name of content +- `contentUrl` - Link to the approved content + +### 8. Content Rejected (`content-rejected`) +**Trigger Identifier:** `content-rejected` +**Channels:** Email, In-App +**Payload Variables:** +- `contentType` - Type of content +- `contentTitle` - Title/name of content +- `rejectionReason` - Reason for rejection + +## Step 5: Configure Webhook (Optional) + +To track notification delivery status: + +1. Go to Novu Dashboard > Settings > Webhooks +2. Add a new webhook endpoint: `https://ydvtmnrszybqnbcqbdcy.supabase.co/functions/v1/novu-webhook` +3. Select events: `notification.sent`, `notification.delivered`, `notification.read`, `notification.failed` + +## Step 6: Test the Integration + +Run these tests to ensure everything works: + +### Test Subscriber Creation +```typescript +import { notificationService } from '@/lib/notificationService'; + +await notificationService.createSubscriber({ + subscriberId: 'user-id', + email: 'user@example.com', + firstName: 'John', + lastName: 'Doe', +}); +``` + +### Test Notification Trigger +```typescript +import { notificationService } from '@/lib/notificationService'; + +await notificationService.trigger({ + workflowId: 'review-reply', + subscriberId: 'user-id', + payload: { + reviewTitle: 'Great ride!', + replyAuthor: 'Jane Doe', + replyContent: 'Thanks for the review!', + reviewUrl: 'https://example.com/review/123', + }, +}); +``` + +## Architecture + +### Database Tables + +1. **notification_templates** - Stores workflow configuration +2. **notification_logs** - Tracks sent notifications +3. **notification_channels** - Manages available channels +4. **user_notification_preferences** - User preferences and Novu subscriber mapping + +### Edge Functions + +1. **create-novu-subscriber** - Creates/updates Novu subscribers +2. **update-novu-preferences** - Syncs preferences with Novu +3. **trigger-notification** - Triggers notification workflows +4. **novu-webhook** - Handles Novu webhook events + +### Frontend Components + +1. **NotificationsTab** - User preferences management +2. **NotificationCenter** - In-app notification display +3. **notificationService** - Core notification logic + +## Switching to Self-Hosted Novu + +To switch to a self-hosted Novu instance: + +1. Update environment variables: +```bash +VITE_NOVU_SOCKET_URL="wss://your-novu-instance.com" +VITE_NOVU_API_URL="https://your-novu-instance.com/api" +``` + +2. Update the Novu API key in Supabase secrets to match your self-hosted instance + +3. No code changes required! The system is designed to work with both Cloud and self-hosted versions + +## Troubleshooting + +### Notifications Not Sending + +1. Check that `VITE_NOVU_APPLICATION_IDENTIFIER` is set +2. Verify `NOVU_API_KEY` is configured in Supabase secrets +3. Check edge function logs: https://supabase.com/dashboard/project/ydvtmnrszybqnbcqbdcy/functions +4. Verify workflow IDs match between database and Novu dashboard + +### User Not Receiving Notifications + +1. Check user's notification preferences in the database +2. Verify subscriber was created in Novu +3. Check notification logs table for delivery status +4. Verify user's email/push permission settings + +### Webhook Not Working + +1. Verify webhook URL is correct in Novu dashboard +2. Check that `novu-webhook` edge function has `verify_jwt = false` +3. Review edge function logs for errors + +## Monitoring + +Track notification performance: + +1. View delivery rates in `notification_logs` table +2. Monitor edge function logs for errors +3. Check Novu dashboard analytics +4. Query notification statistics: + +```sql +SELECT + status, + COUNT(*) as count, + AVG(EXTRACT(EPOCH FROM (delivered_at - created_at))) as avg_delivery_time_seconds +FROM notification_logs +WHERE created_at > NOW() - INTERVAL '7 days' +GROUP BY status; +``` + +## Support + +- Novu Documentation: https://docs.novu.co +- Novu Discord: https://discord.gg/novu +- ThrillWiki Support: [Add support contact]