Files
Krystie f50b493df2 feat: Add comprehensive notification system with email support
- Create notification management system with VNotifications class
- Build notification API endpoints (get, mark read, delete, preferences)
- Implement notification bell UI widget with real-time polling
- Add email queue system with digest support (instant/hourly/daily/weekly)
- Create notification trigger helpers for common events
- Add fine-grained user preference controls
- Implement cron script for email processing and cleanup
- Document setup and usage in docs/NOTIFICATIONS.md

Features:
- In-app notifications with dropdown
- Email delivery with batching
- 6 notification types (comment, like, subscribe, upload, mention, system)
- User preference controls per notification type
- Lightweight polling (30s interval)
- Auto-cleanup of old notifications (90 days)
- Production-ready with proper error handling
2026-03-30 17:11:08 -07:00

400 lines
9.7 KiB
Markdown

# Notification System
EasyStream now includes a comprehensive notification system with in-app and email delivery.
## Features
- 🔔 **In-app notifications** with real-time updates
- 📧 **Email notifications** with digest support (instant, hourly, daily, weekly)
- 🎯 **Fine-grained preferences** - users control what they receive
-**Lightweight polling** - updates every 30 seconds without performance impact
- 📱 **Modern UI** - notification bell with dropdown list
- 🎨 **Multiple notification types** - comments, likes, subscribes, uploads, mentions, system
## Setup
### 1. Database Migration
Run the migration to create notification tables:
```bash
docker-compose exec db mysql -u easystream -peasystream easystream < __install/migrations/002_add_notifications_system.sql
```
This creates:
- `db_notifications` - stores all notifications
- `db_notification_preferences` - user notification settings
- `db_email_queue` - queued emails for batched sending
### 2. Add Notification Bell to Header
Include the JavaScript and add the widget container to your header template:
```html
<!-- In your header template -->
<script src="/f_scripts/fe/js/notifications.js"></script>
<!-- Add the notification bell to your navigation -->
<div id="notification-widget"></div>
```
The widget will auto-initialize and start polling for updates.
### 3. Configure Email Sending
By default, the system uses PHP's `mail()` function. For production, integrate with a proper email service:
Edit `f_core/f_classes/class.notifications.php``sendEmail()` method to integrate:
- **SendGrid**
- **Mailgun**
- **Amazon SES**
- **SMTP**
### 4. Set Up Cron Job
Add a cron job to process the email queue:
```bash
# Process email queue every 15 minutes
*/15 * * * * cd /srv/easystream && php app_scripts/cron/process_notification_emails.php >> /var/log/notification-emails.log 2>&1
```
## Usage
### Triggering Notifications
Use the `VNotificationTriggers` helper class for common events:
```php
require_once 'f_core/f_classes/class.notification_triggers.php';
$triggers = new VNotificationTriggers();
// When someone comments on a video
$triggers->notifyVideoComment(
$video_owner_id,
$commenter_id,
$commenter_name,
$video_id,
$video_title,
$comment_text
);
// When someone likes a video
$triggers->notifyVideoLike(
$video_owner_id,
$liker_id,
$liker_name,
$video_id,
$video_title
);
// When someone subscribes
$triggers->notifySubscribe(
$channel_owner_id,
$subscriber_id,
$subscriber_name
);
// When uploading a new video (notifies all subscribers)
$triggers->notifySubscribersNewVideo(
$channel_owner_id,
$channel_name,
$video_id,
$video_title
);
// When mentioning a user in a comment
$triggers->notifyMention(
$mentioned_user_id,
$mentioner_id,
$mentioner_name,
$video_id,
$comment_text
);
// System notification
$triggers->notifySystem(
$user_id,
'Your video was approved',
'Your video "Tutorial" is now live!',
'/watch?v=123'
);
```
### API Endpoints
#### Get Notifications
```http
GET /api/notifications.php?limit=20&offset=0&unread_only=true
```
**Response:**
```json
{
"success": true,
"data": {
"notifications": [
{
"notification_id": 123,
"type": "comment",
"title": "John commented on your video",
"message": "Great tutorial!",
"link": "/watch?v=456#comments",
"is_read": 0,
"created_at": "2026-03-30 17:30:00",
"actor_username": "john",
"actor_avatar": "/avatars/john.jpg"
}
],
"unread_count": 5
}
}
```
#### Get Unread Count (Lightweight)
```http
GET /api/notifications_count.php
```
**Response:**
```json
{
"success": true,
"unread_count": 5
}
```
#### Mark as Read
```http
POST /api/notifications.php?action=mark_read
Content-Type: application/json
{"id": 123}
```
Or mark multiple:
```json
{"id": "123,124,125"}
```
#### Mark All as Read
```http
POST /api/notifications.php?action=mark_all_read
```
#### Delete Notification
```http
DELETE /api/notifications.php?id=123
```
### User Preferences
#### Get Preferences
```http
GET /api/notification_preferences.php
```
**Response:**
```json
{
"success": true,
"data": {
"email_comments": 1,
"email_likes": 1,
"email_subscribes": 1,
"email_uploads": 1,
"email_mentions": 1,
"email_digest": "instant",
"push_enabled": 1,
"push_comments": 1,
"push_likes": 1,
"push_subscribes": 1
}
}
```
#### Update Preferences
```http
POST /api/notification_preferences.php
Content-Type: application/json
{
"email_digest": "daily",
"email_likes": 0,
"push_comments": 1
}
```
## Email Digest Modes
Users can choose how often they receive emails:
- **instant** - Send immediately when notification is created
- **hourly** - Batch and send once per hour
- **daily** - Send once per day (at midnight)
- **weekly** - Send once per week (Monday)
- **never** - No email notifications
## Notification Types
| Type | Description | Example |
|------|-------------|---------|
| `comment` | New comment on video or reply to comment | "John commented on your video" |
| `like` | Someone liked a video | "Sarah liked your video" |
| `subscribe` | New channel subscriber | "Mike subscribed to your channel" |
| `video_upload` | Subscribed channel uploaded new video | "TechChannel uploaded a new video" |
| `mention` | User mentioned in a comment | "@username mentioned you" |
| `system` | Admin/system messages | "Your video was approved" |
## Frontend Integration
The notification widget provides:
- Real-time bell icon with unread count badge
- Dropdown with last 20 notifications
- Mark individual or all as read
- Auto-polling every 30 seconds
- Click notification to navigate and mark as read
### JavaScript API
```javascript
// Access the widget instance
const widget = window.notificationWidget;
// Manually fetch notifications
widget.fetchNotifications();
// Manually fetch unread count
widget.fetchUnreadCount();
// Change poll interval (milliseconds)
widget.pollInterval = 60000; // 1 minute
widget.stopPolling();
widget.startPolling();
// Programmatically mark as read
widget.markAsRead(notification_id);
// Mark all as read
widget.markAllAsRead();
```
## Database Schema
### db_notifications
| Column | Type | Description |
|--------|------|-------------|
| notification_id | INT | Primary key |
| usr_id | INT | User receiving notification |
| type | ENUM | Notification type |
| title | VARCHAR(255) | Short title |
| message | TEXT | Optional detailed message |
| link | VARCHAR(512) | URL to navigate to |
| actor_id | INT | User who triggered notification |
| related_video_id | INT | Associated video |
| related_comment_id | INT | Associated comment |
| is_read | TINYINT | Read status |
| is_seen | TINYINT | Seen status (viewed in UI) |
| email_sent | TINYINT | Email delivery status |
| created_at | DATETIME | Creation timestamp |
| read_at | DATETIME | When marked as read |
### db_notification_preferences
| Column | Type | Description |
|--------|------|-------------|
| usr_id | INT | User ID (unique) |
| email_comments | TINYINT | Email for comments |
| email_likes | TINYINT | Email for likes |
| email_subscribes | TINYINT | Email for subscribes |
| email_uploads | TINYINT | Email for new uploads |
| email_mentions | TINYINT | Email for mentions |
| email_digest | ENUM | Digest frequency |
| push_enabled | TINYINT | Push notifications enabled |
| push_comments | TINYINT | Push for comments |
| push_likes | TINYINT | Push for likes |
| push_subscribes | TINYINT | Push for subscribes |
### db_email_queue
| Column | Type | Description |
|--------|------|-------------|
| queue_id | INT | Primary key |
| usr_id | INT | Recipient user |
| email | VARCHAR(255) | Email address |
| subject | VARCHAR(255) | Email subject |
| body | TEXT | Email HTML body |
| scheduled_for | DATETIME | When to send |
| sent_at | DATETIME | Actual send time |
| attempts | INT | Send attempts |
| last_error | TEXT | Last error message |
## Performance
- **Polling:** Lightweight count query every 30s (~1-2ms)
- **Dropdown:** Full notification list only when opened
- **Email queue:** Batched processing reduces database load
- **Auto-cleanup:** Old read notifications purged after 90 days
## Cleanup
The cron script automatically cleans up:
- Read notifications older than 90 days
- Sent emails from queue
Adjust retention in `app_scripts/cron/process_notification_emails.php`:
```php
$notifications->cleanup(90); // Days to keep
```
## Troubleshooting
### Notifications not appearing
1. Check database tables exist
2. Verify JavaScript is loaded: `window.notificationWidget`
3. Check browser console for errors
4. Verify user is authenticated (session active)
### Emails not sending
1. Check cron job is running
2. View email queue: `SELECT * FROM db_email_queue WHERE sent_at IS NULL`
3. Check email configuration in `class.notifications.php`
4. View logs: `docker-compose logs php | grep email`
### High polling load
Increase poll interval in the frontend:
```javascript
// In notifications.js
this.pollInterval = 60000; // 60 seconds instead of 30
```
## Future Enhancements
- [ ] WebSocket/SSE for true real-time updates (eliminate polling)
- [ ] Push notifications (web push API)
- [ ] Mobile app push notifications (FCM/APNS)
- [ ] Notification grouping (e.g., "5 people liked your video")
- [ ] Rich notification preview with thumbnails
- [ ] Notification filtering/search
- [ ] Mark as unread
- [ ] Snooze notifications
## Learn More
- [Web Push API](https://developer.mozilla.org/en-US/docs/Web/API/Push_API)
- [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
- [Email Best Practices](https://developers.google.com/gmail/design/reference/supported_css)