Index: src/middleware/auth.js
===================================================================
--- src/middleware/auth.js	(revision 8cb1dc7b23142c8a8ec44f7659178b51a2da4ddf)
+++ src/middleware/auth.js	(revision 8afbdd6572a947bce4726d5aa0d0aa0d6c7e5067)
@@ -37,7 +37,18 @@
 }
 
+// Een 'kijker' mag ALLES bekijken (incl. Beheer) maar NIETS wijzigen. De
+// schrijf-blokkade zit in de globale guard in server.js; deze helper bepaalt
+// alleen "is dit een alleen-lezen account?". `readonly` is de legacy-vlag die
+// we nog meenemen zodat niet-gemigreerde demo-accounts geblokkeerd blijven.
+export function isViewer(user) {
+  return !!user && (user.role === 'kijker' || !!user.readonly);
+}
+
 export function requireGod(req, res, next) {
   if (!req.session?.user) return loginRedirect(req, res);
-  if (req.session.user.role !== 'god') {
+  const role = req.session.user.role;
+  // god beheert; een kijker mág het Beheer-paneel zien (alleen-lezen) — de
+  // globale guard 403't elke write, dus dit geeft enkel kijk-toegang.
+  if (role !== 'god' && role !== 'kijker') {
     return res.status(403).send('God role required');
   }
@@ -52,5 +63,5 @@
   if (!req.session?.user) return loginRedirect(req, res);
   const u = req.session.user;
-  if (u.role === 'god') return next();
+  if (u.role === 'god' || u.role === 'kijker') return next(); // kijker = alleen-lezen kijk-toegang
   const site = res.locals.site;
   if (site && site.owner_id === u.id) return next();
@@ -62,5 +73,5 @@
   if (!req.session?.user) return loginRedirect(req, res);
   const u = req.session.user;
-  if (u.role === 'god') return next();
+  if (u.role === 'god' || u.role === 'kijker') return next(); // kijker = alleen-lezen kijk-toegang
   const site = db.prepare('SELECT owner_id FROM sites WHERE slug = ?').get(req.params.slug);
   if (site && site.owner_id === u.id) return next();
