Index: src/services/NotificationService.js
===================================================================
--- src/services/NotificationService.js	(revision c9c6a2d6cf1cf1611a79c699dd70c435bda3c203)
+++ src/services/NotificationService.js	(revision c9c6a2d6cf1cf1611a79c699dd70c435bda3c203)
@@ -0,0 +1,38 @@
+/**
+ * Meldingen — antwoord op je reactie, reactie op je post, like op je post.
+ * Voor élke ingelogde gebruiker (Google-bezoekers/fans én admin). Snapshots van
+ * actor-naam + post-titel zodat de lijst zonder joins te tonen is.
+ */
+import { randomUUID } from 'crypto';
+import db from '../config/database.js';
+
+// Maakt een melding aan. Doet niets als er geen ontvanger is of als je jezelf
+// zou notificeren (eigen reactie/like op eigen post/reactie).
+export function notify({ userId, actorId, actorName, type, postSlug, postTitle, url }) {
+  if (!userId || userId === actorId) return;
+  try {
+    db.prepare(`
+      INSERT INTO notifications (id, user_id, type, actor_id, actor_name, post_slug, post_title, url, read)
+      VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0)
+    `).run(randomUUID(), userId, type, actorId || null, actorName || null, postSlug || null, postTitle || null, url || null);
+  } catch { /* meldingen zijn niet-fataal */ }
+}
+
+export function unreadCount(userId) {
+  if (!userId) return 0;
+  try { return db.prepare('SELECT COUNT(*) AS c FROM notifications WHERE user_id = ? AND read = 0').get(userId).c; }
+  catch { return 0; }
+}
+
+export function list(userId, limit = 50) {
+  if (!userId) return [];
+  try { return db.prepare('SELECT * FROM notifications WHERE user_id = ? ORDER BY created_at DESC LIMIT ?').all(userId, limit); }
+  catch { return []; }
+}
+
+export function markAllRead(userId) {
+  if (!userId) return;
+  try { db.prepare('UPDATE notifications SET read = 1 WHERE user_id = ? AND read = 0').run(userId); } catch { /* noop */ }
+}
+
+export default { notify, unreadCount, list, markAllRead };
Index: src/services/i18n.js
===================================================================
--- src/services/i18n.js	(revision 097da22557ca814590ad9affc1e7910636320b0a)
+++ src/services/i18n.js	(revision c9c6a2d6cf1cf1611a79c699dd70c435bda3c203)
@@ -25,4 +25,7 @@
     'nav.new_post': 'Nieuwe post',
     'nav.language': 'Taal',
+    'nav.notifications': 'Meldingen',
+    'notif.title': 'Meldingen', 'notif.empty': 'Nog geen meldingen.', 'notif.someone': 'Iemand',
+    'notif.reply': '{actor} reageerde op je reactie', 'notif.comment': '{actor} reageerde op je post', 'notif.like': '{actor} vindt je post leuk',
     'switch.agenda': 'Agenda',
     'switch.solo': 'Solo',
@@ -999,4 +1002,7 @@
     'nav.new_post': 'New post',
     'nav.language': 'Language',
+    'nav.notifications': 'Notifications',
+    'notif.title': 'Notifications', 'notif.empty': 'No notifications yet.', 'notif.someone': 'Someone',
+    'notif.reply': '{actor} replied to your comment', 'notif.comment': '{actor} commented on your post', 'notif.like': '{actor} liked your post',
     'switch.agenda': 'Agenda',
     'switch.solo': 'Solo',
@@ -1964,4 +1970,7 @@
     'nav.new_post': 'Neuer Beitrag',
     'nav.language': 'Sprache',
+    'nav.notifications': 'Benachrichtigungen',
+    'notif.title': 'Benachrichtigungen', 'notif.empty': 'Noch keine Benachrichtigungen.', 'notif.someone': 'Jemand',
+    'notif.reply': '{actor} hat auf deinen Kommentar geantwortet', 'notif.comment': '{actor} hat deinen Beitrag kommentiert', 'notif.like': '{actor} gefällt dein Beitrag',
     'switch.agenda': 'Termine',
     'switch.solo': 'Solo',
