mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-22 06:41:46 +00:00
feat(notifications): add unified multi-channel notification system
Introduces a fully featured notification system with three delivery channels (in-app, email, webhook), normalized per-user/per-event/ per-channel preferences, admin-scoped notifications, scheduled trip reminders and version update alerts. - New notificationService.send() as the single orchestration entry point - In-app notifications with simple/boolean/navigate types and WebSocket push - Per-user preference matrix with normalized notification_channel_preferences table - Admin notification preferences stored globally in app_settings - Migration 69 normalizes legacy notification_preferences table - Scheduler hooks for daily trip reminders and version checks - DevNotificationsPanel for testing in dev mode - All new tests passing, covering dispatch, preferences, migration, boolean responses, resilience, and full API integration (NSVC, NPREF, INOTIF, MIGR, VNOTIF, NROUTE series) - Previous tests passing
This commit is contained in:
@@ -12,22 +12,19 @@ import {
|
||||
deleteAll,
|
||||
respondToBoolean,
|
||||
} from '../services/inAppNotifications';
|
||||
import * as prefsService from '../services/notificationPreferencesService';
|
||||
import { getPreferencesMatrix, setPreferences } from '../services/notificationPreferencesService';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/preferences', authenticate, (req: Request, res: Response) => {
|
||||
const authReq = req as AuthRequest;
|
||||
res.json({ preferences: prefsService.getPreferences(authReq.user.id) });
|
||||
res.json(getPreferencesMatrix(authReq.user.id, authReq.user.role, 'user'));
|
||||
});
|
||||
|
||||
router.put('/preferences', authenticate, (req: Request, res: Response) => {
|
||||
const authReq = req as AuthRequest;
|
||||
const { notify_trip_invite, notify_booking_change, notify_trip_reminder, notify_webhook } = req.body;
|
||||
const preferences = prefsService.updatePreferences(authReq.user.id, {
|
||||
notify_trip_invite, notify_booking_change, notify_trip_reminder, notify_webhook
|
||||
});
|
||||
res.json({ preferences });
|
||||
setPreferences(authReq.user.id, req.body);
|
||||
res.json(getPreferencesMatrix(authReq.user.id, authReq.user.role, 'user'));
|
||||
});
|
||||
|
||||
router.post('/test-smtp', authenticate, async (req: Request, res: Response) => {
|
||||
@@ -38,9 +35,10 @@ router.post('/test-smtp', authenticate, async (req: Request, res: Response) => {
|
||||
});
|
||||
|
||||
router.post('/test-webhook', authenticate, async (req: Request, res: Response) => {
|
||||
const authReq = req as AuthRequest;
|
||||
if (authReq.user.role !== 'admin') return res.status(403).json({ error: 'Admin only' });
|
||||
res.json(await testWebhook());
|
||||
const { url } = req.body;
|
||||
if (!url || typeof url !== 'string') return res.status(400).json({ error: 'url is required' });
|
||||
try { new URL(url); } catch { return res.status(400).json({ error: 'Invalid URL' }); }
|
||||
res.json(await testWebhook(url));
|
||||
});
|
||||
|
||||
// ── In-app notifications ──────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user