# Push Notifications Setup Guide ## Quick Start ### 1. Install Dependencies ```bash npm install ``` This will install `web-push` which is now in package.json. ### 2. Generate VAPID Keys ```bash npm run vapid:generate ``` Copy the output and add to your `.env` file: ```env VAPID_PUBLIC_KEY=your-generated-public-key VAPID_PRIVATE_KEY=your-generated-private-key VAPID_SUBJECT=mailto:your-email@example.com ``` ### 3. Update Database Schema ```bash npx prisma db push ``` This adds the `PushSubscription` table to your database. ### 4. Add Notification Settings to Profile Page Add the `NotificationSettings` component to your profile page: ```tsx import NotificationSettings from '@/components/NotificationSettings'; export default function ProfilePage() { return (
{/* Your existing profile content */}
); } ``` ### 5. Integrate Notifications into Your Actions Update your existing action files to send notifications: #### In `lib/actions.ts` (or wherever you handle items): ```typescript import { notifyItemAdded, notifyItemRemoved, notifyItemCompleted } from '@/lib/notification-helpers'; // After creating an item: export async function createItem(listId: string, data: ItemData) { // ... your existing code to create item const item = await prisma.item.create({ ... }); // Send notification await notifyItemAdded(listId, item.title, session.user.id); return item; } // After deleting an item: export async function deleteItem(itemId: string) { const item = await prisma.item.findUnique({ where: { id: itemId } }); // ... your existing delete code if (item) { await notifyItemRemoved(item.listId, item.title, session.user.id); } } // After completing an item: export async function toggleItemComplete(itemId: string) { const item = await prisma.item.update({ ... }); if (item.completed) { await notifyItemCompleted(item.listId, item.title, session.user.id); } } ``` #### In `lib/sharing-actions.ts`: ```typescript import { notifyListInvitation, notifyInvitationAccepted, notifyRemovedFromList } from '@/lib/notification-helpers'; // After creating an invitation: export async function inviteToList(listId: string, email: string, permission: string) { // ... your existing code const invitation = await prisma.invitation.create({ ... }); // Send notification await notifyListInvitation(invitation.id, email); return invitation; } // After accepting an invitation: export async function acceptInvitation(invitationId: string) { // ... your existing code await notifyInvitationAccepted(invitationId); } // After removing a collaborator: export async function removeCollaborator(listId: string, userId: string) { const list = await prisma.list.findUnique({ where: { id: listId } }); // ... your existing code if (list) { await notifyRemovedFromList(userId, list.title, session.user.id); } } ``` ## How It Works ### Architecture 1. **Client requests permission** → User clicks "Enable" in NotificationSettings 2. **Service worker subscribes** → Browser creates a push subscription 3. **Subscription saved to DB** → Stored in PushSubscription table 4. **Events trigger notifications** → Server sends push via web-push library 5. **Service worker displays** → User sees notification ### Self-Hosted Solution This implementation uses **VAPID** (Voluntary Application Server Identification), which means: - ✅ No external services required (no Firebase, no third-party APIs) - ✅ Works entirely from your own server - ✅ Free and open-source - ✅ Full control over your data ### Browser Support - ✅ Chrome/Edge (Desktop & Android) - ✅ Firefox (Desktop & Android) - ✅ Safari 16.4+ (iOS & macOS) - **Must be installed to home screen on iOS** - ❌ Safari < 16.4 ## Testing ### Local Testing (Desktop) 1. Start your dev server: `npm run dev` 2. Open Chrome DevTools → Application → Service Workers 3. Go to your profile page and enable notifications 4. Trigger an action (add item, invite someone, etc.) 5. You should see a notification appear ### iOS Testing (Real Device Required) 1. Deploy to a server with HTTPS (required for PWA) 2. Open Safari on iOS 16.4+ 3. Tap Share → Add to Home Screen 4. Open the installed app 5. Enable notifications in profile 6. Test by triggering actions from another device ### Testing Push Manually Use Chrome DevTools to simulate a push: 1. DevTools → Application → Service Workers 2. Find your service worker 3. Click "Push" to simulate receiving a notification ## Notification Events The following events trigger notifications: | Event | Recipient | Trigger | |-------|-----------|---------| | Item Added | All list collaborators (except adder) | Someone adds an item to a shared list | | Item Removed | All list collaborators (except remover) | Someone removes an item | | Item Completed | All list collaborators (except completer) | Someone marks an item complete | | List Invitation | Invitee | Someone invites you to a list | | Invitation Accepted | Inviter | Someone accepts your invitation | | Removed from List | Removed user | Owner removes you from a list | ## Customization ### Notification Content Edit `lib/notification-helpers.ts` to customize notification titles, bodies, and icons. ### Notification Preferences To add per-list notification preferences: 1. Add a `notificationsEnabled` field to the `Collaborator` model 2. Update `NotificationSettings` to show per-list toggles 3. Check this field in `notifyListCollaborators` before sending ### Notification Sounds Add to service worker push event: ```javascript const options = { // ... existing options silent: false, sound: '/notification-sound.mp3', }; ``` ## Troubleshooting ### "Push notifications not configured" error - Check that VAPID keys are in `.env` - Restart your dev server after adding keys ### Notifications not appearing - Check browser permission (should be "granted") - Verify service worker is active (DevTools → Application) - Check browser console for errors - Ensure you're testing on HTTPS (or localhost) ### iOS notifications not working - Must be iOS 16.4 or later - Must be installed to home screen (not in Safari browser) - Check Settings → [Your App] → Notifications ### Subscription fails - Verify VAPID public key matches between client and server - Check service worker is registered and active - Ensure you're on HTTPS (or localhost) ## Security Notes - ⚠️ **Never commit VAPID_PRIVATE_KEY to git** - ✅ VAPID keys are like JWT secrets - keep them secure - ✅ Subscriptions are tied to users - no cross-user notification access - ✅ Expired subscriptions are automatically cleaned up ## Production Checklist - [ ] Generate production VAPID keys - [ ] Add VAPID keys to production environment variables - [ ] Run database migration: `npx prisma db push` - [ ] Test on actual iOS device (if targeting iOS) - [ ] Verify HTTPS is working (required for push) - [ ] Test notification delivery - [ ] Monitor for expired subscriptions in logs ## Performance - Notifications are sent asynchronously (non-blocking) - Failed subscriptions are automatically removed - Multiple devices per user are supported - TTL is set to 24 hours (notifications expire if not delivered) ## Next Steps Consider adding: - Notification preferences per list - Quiet hours (don't notify during certain times) - Notification history/inbox - Rich notifications with action buttons - Notification grouping/batching if