Index: src/middleware/auth.js
===================================================================
--- src/middleware/auth.js	(revision 6a2abb1aa992cd6440164fde90a55dabfac2022c)
+++ src/middleware/auth.js	(revision 98ecf51d81042b5773ac053aa13dfc773dbdf4e9)
@@ -4,4 +4,5 @@
 
 import db from '../config/database.js';
+import PermissionsService from '../services/PermissionsService.js';
 
 /**
@@ -65,5 +66,6 @@
   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();
+  // owner OF toegewezen mede-beheerder (site_members) — canAdminSite dekt beide.
+  if (site && PermissionsService.canAdminSite(u, site)) return next();
   return res.status(403).send('Geen toegang tot deze site.');
 }
@@ -74,6 +76,6 @@
   const u = req.session.user;
   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();
+  const site = db.prepare('SELECT id, owner_id FROM sites WHERE slug = ?').get(req.params.slug);
+  if (site && PermissionsService.canAdminSite(u, site)) return next();
   return res.status(403).send('Geen toegang tot deze site.');
 }
Index: src/routes/admin-sites.js
===================================================================
--- src/routes/admin-sites.js	(revision 6a2abb1aa992cd6440164fde90a55dabfac2022c)
+++ src/routes/admin-sites.js	(revision 98ecf51d81042b5773ac053aa13dfc773dbdf4e9)
@@ -137,4 +137,24 @@
 }
 
+/** Geldige user-id voor owner-toewijzing, of null bij leeg/onbekend. */
+function validOwnerId(raw) {
+  const id = (raw || '').toString().trim();
+  if (!id) return null;
+  return db.prepare('SELECT 1 FROM users WHERE id = ?').get(id) ? id : null;
+}
+
+/** Geef een user admin-rechten op een site (idempotent upsert). */
+function grantSiteAdmin(siteId, userId) {
+  db.prepare(`
+    INSERT INTO site_members (site_id, user_id, role) VALUES (?, ?, 'admin')
+    ON CONFLICT(site_id, user_id) DO UPDATE SET role = 'admin'
+  `).run(siteId, userId);
+}
+
+/** Kandidaat-owners voor het owner-keuzeveld (god-only). */
+function listOwnerCandidates() {
+  return db.prepare('SELECT id, username, role FROM users ORDER BY username').all();
+}
+
 // ==================== LIST ====================
 router.get('/', requireGod, (req, res) => {
@@ -163,5 +183,6 @@
     bodyClass: 'on-admin',
     isNew: true,
-    site: { slug: '', ...siteEditableFields() },
+    site: { slug: '', owner_id: req.session.user.id, ...siteEditableFields() },
+    users: listOwnerCandidates(),
     palettes: ThemeService.listPalettes(),
     accents: ThemeService.listAccents(),
@@ -187,4 +208,10 @@
 
   const f = { ...siteEditableFields(), ...req.body };
+
+  // Owner: god mag de site aan een ANDERE gebruiker toewijzen — dit is de kern
+  // van hub-modus (elke gebruiker z'n eigen, zelf te beheren Klonkt). Leeg of
+  // ongeldig → de aanmakende god zelf.
+  const ownerId = validOwnerId(req.body.owner_id) || req.session.user.id;
+
   const siteId = uuid();
   db.prepare(`
@@ -200,5 +227,5 @@
     (f.description || '').slice(0, 500),
     (f.tagline || '').slice(0, 200),
-    req.session.user.id,
+    ownerId,
     f.language || 'nl',
     f.palette || 'sage',
@@ -213,10 +240,9 @@
   );
 
-  // The site_members entry lets the god/owner show up in canAdminSite checks.
-  db.prepare(`
-    INSERT INTO site_members (site_id, user_id, role) VALUES (?, ?, 'admin')
-  `).run(siteId, req.session.user.id);
-
-  res.redirect(`/admin/sites/${slug}/edit?success=` + encodeURIComponent('Site created'));
+  // De OWNER (niet per se de aanmaker) krijgt een site_members-admin-rij → zo komt
+  // 'ie door canAdminSite + de requireSiteManager-gates en beheert 'ie z'n site.
+  grantSiteAdmin(siteId, ownerId);
+
+  res.redirect(`/admin/sites/${slug}/edit?success=` + encodeURIComponent('Site aangemaakt'));
 });
 
@@ -236,4 +262,5 @@
     isNew: false,
     site,
+    users: listOwnerCandidates(),
     palettes: ThemeService.listPalettes(),
     accents: ThemeService.listAccents(),
@@ -314,5 +341,15 @@
   );
 
-  res.redirect(`/admin/sites/${req.params.slug}/edit?success=` + encodeURIComponent('Saved'));
+  // Owner (her)toewijzen — ALLEEN god. Een site-owner die z'n eigen site bewerkt
+  // kan de eigenaar niet wijzigen (het veld wordt voor niet-god ook niet getoond).
+  if (req.session.user.role === 'god') {
+    const newOwner = validOwnerId(req.body.owner_id);
+    if (newOwner) {
+      db.prepare('UPDATE sites SET owner_id = ? WHERE id = ?').run(newOwner, site.id);
+      grantSiteAdmin(site.id, newOwner);
+    }
+  }
+
+  res.redirect(`/admin/sites/${req.params.slug}/edit?success=` + encodeURIComponent('Opgeslagen'));
 });
 
Index: src/services/PermissionsService.js
===================================================================
--- src/services/PermissionsService.js	(revision 6a2abb1aa992cd6440164fde90a55dabfac2022c)
+++ src/services/PermissionsService.js	(revision 98ecf51d81042b5773ac053aa13dfc773dbdf4e9)
@@ -3,4 +3,6 @@
  * Used in templates to show/hide edit buttons, delete buttons, etc.
  */
+
+import db from '../config/database.js';
 
 class PermissionsService {
@@ -54,9 +56,13 @@
    */
   static canAdminSite(user, site) {
-    if (!user) return false;
+    if (!user || !site) return false;
     if (user.role === 'god') return true;
     if (user.id === site.owner_id) return true;
-    // Check site_members table
-    return user.siteRoles && user.siteRoles[site.id] === 'admin';
+    // Toegewezen mede-beheerder (collaborator) via site_members. Dit werd
+    // voorheen via een nooit-gevulde user.siteRoles gelezen → dode code; nu
+    // direct op de tabel (paar checks per pagina, indexed = goedkoop).
+    return !!db.prepare(
+      "SELECT 1 FROM site_members WHERE site_id = ? AND user_id = ? AND role = 'admin' LIMIT 1"
+    ).get(site.id, user.id);
   }
 
Index: src/views/pages/admin-site-edit.ejs
===================================================================
--- src/views/pages/admin-site-edit.ejs	(revision 6a2abb1aa992cd6440164fde90a55dabfac2022c)
+++ src/views/pages/admin-site-edit.ejs	(revision 98ecf51d81042b5773ac053aa13dfc773dbdf4e9)
@@ -24,4 +24,16 @@
         <input type="text" name="title" value="<%= site.title || '' %>" required maxlength="200">
       </label>
+      <%# Eigenaar (her)toewijzen — ALLEEN god. In hub-modus geef je zo elke
+          gebruiker z'n eigen, zelf te beheren Klonkt. Niet-god ziet dit niet. %>
+      <% if (user && user.role === 'god') { %>
+      <label>
+        <span>Eigenaar <small class="form-hint-inline">— wie deze Klonkt zelf mag beheren</small></span>
+        <select name="owner_id">
+          <% (typeof users !== 'undefined' ? users : []).forEach(function(u){ %>
+            <option value="<%= u.id %>" <%= (site.owner_id === u.id) ? 'selected' : '' %>><%= u.username %><%= u.role === 'god' ? ' (god)' : '' %></option>
+          <% }); %>
+        </select>
+      </label>
+      <% } %>
       <label>
         <span>Tagline <small class="form-hint-inline">— korte oneliner</small></span>
