# 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
``` 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)