Files
Todo/PUSH_NOTIFICATIONS_SETUP.md
2025-12-07 01:31:33 +00:00

272 lines
7.4 KiB
Markdown

# 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 (
<div>
{/* Your existing profile content */}
<NotificationSettings />
</div>
);
}
```
### 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