Index: src/routes/admin-seo.js
===================================================================
--- src/routes/admin-seo.js	(revision 662345333cce064d12731d86e9a2ede2f4b6805c)
+++ src/routes/admin-seo.js	(revision 662345333cce064d12731d86e9a2ede2f4b6805c)
@@ -0,0 +1,99 @@
+/**
+ * Admin: geavanceerde SEO-instellingen van de primaire site.
+ *
+ * GET  /admin/seo   -> formulier met alle SEO/social-velden van de hoofdsite
+ * POST /admin/seo   -> opslaan (god-only)
+ *
+ * Deze velden worden al door de <head> (shell.ejs) en de JSON-LD/OpenGraph-
+ * tags geconsumeerd, maar waren tot nu toe nergens te bewerken. De basis-
+ * velden (titel/bio/robots) blijven in Uiterlijk; dit is de geavanceerde laag:
+ * titel-sjabloon, canonical, social-share-afbeelding, verificatie-metas,
+ * publisher/JSON-LD en OpenGraph-locale.
+ *
+ * Werkt op de PRIMAIRE site (solo = de enige site; hub = de bedrijfssite).
+ */
+
+import express from 'express';
+import db from '../config/database.js';
+import { renderPage } from '../middleware/render.js';
+import { requireGod } from '../middleware/auth.js';
+import { getPrimarySite } from '../middleware/site.js';
+
+const router = express.Router();
+
+function trimOrNull(v, max) {
+  const s = (v == null ? '' : String(v)).trim();
+  return s ? s.slice(0, max) : null;
+}
+
+// ==================== FORM ====================
+router.get('/', requireGod, (req, res) => {
+  const primary = getPrimarySite();
+  if (!primary) {
+    return res.redirect('/admin/sites/new?error=' + encodeURIComponent('Maak eerst een site aan'));
+  }
+  const site = db.prepare('SELECT * FROM sites WHERE id = ?').get(primary.id);
+
+  renderPage(req, res, 'pages/admin-seo', {
+    pageTitle: 'SEO',
+    bodyClass: 'on-admin',
+    site,
+    success: req.query.success || null,
+    error: req.query.error || null,
+  });
+});
+
+// ==================== SAVE ====================
+router.post('/', requireGod, (req, res) => {
+  const primary = getPrimarySite();
+  if (!primary) return res.redirect('/admin/seo?error=' + encodeURIComponent('Geen site gevonden'));
+
+  const f = req.body;
+  const schemaType = f.schema_type === 'Organization' ? 'Organization' : 'Person';
+
+  db.prepare(`
+    UPDATE sites SET
+      robots_index = ?,
+      title_template = ?,
+      canonical = ?,
+      default_description = ?,
+      og_image_default = ?,
+      og_locale = ?,
+      author = ?,
+      twitter = ?,
+      facebook_app_id = ?,
+      google_verification = ?,
+      bing_verification = ?,
+      pinterest_verification = ?,
+      yandex_verification = ?,
+      schema_type = ?,
+      publisher_name = ?,
+      publisher_url = ?,
+      publisher_logo = ?,
+      updated_at = CURRENT_TIMESTAMP
+    WHERE id = ?
+  `).run(
+    f.robots_index ? 1 : 0,
+    (f.title_template || '{title} — {site}').slice(0, 200),
+    trimOrNull(f.canonical, 200),
+    trimOrNull(f.default_description, 500),
+    trimOrNull(f.og_image_default, 500),
+    trimOrNull(f.og_locale, 32),
+    trimOrNull(f.author, 120),
+    trimOrNull(f.twitter, 64),
+    trimOrNull(f.facebook_app_id, 64),
+    trimOrNull(f.google_verification, 200),
+    trimOrNull(f.bing_verification, 200),
+    trimOrNull(f.pinterest_verification, 200),
+    trimOrNull(f.yandex_verification, 200),
+    schemaType,
+    trimOrNull(f.publisher_name, 200),
+    trimOrNull(f.publisher_url, 200),
+    trimOrNull(f.publisher_logo, 500),
+    primary.id,
+  );
+
+  res.redirect('/admin/seo?success=' + encodeURIComponent('SEO-instellingen opgeslagen'));
+});
+
+export default router;
Index: src/routes/admin-sites.js
===================================================================
--- src/routes/admin-sites.js	(revision 74544fb18421ccb5681758c4cc7c47ac951c7e8b)
+++ src/routes/admin-sites.js	(revision 662345333cce064d12731d86e9a2ede2f4b6805c)
@@ -303,7 +303,4 @@
       feed_view_default = ?, feed_view_switch = ?,
       show_search = ?, show_archive_link = ?,
-      title_template = ?, twitter = ?, canonical = ?,
-      google_verification = ?, bing_verification = ?,
-      pinterest_verification = ?, yandex_verification = ?,
       custom_css = ?, custom_head_html = ?, custom_foot_html = ?,
       updated_at = CURRENT_TIMESTAMP
@@ -330,11 +327,4 @@
     f.show_search ? 1 : 0,
     f.show_archive_link ? 1 : 0,
-    (f.title_template || '{title} — {site}').slice(0, 200),
-    (f.twitter || '').slice(0, 64) || null,
-    (f.canonical || '').slice(0, 200) || null,
-    (f.google_verification    || '').slice(0, 200) || null,
-    (f.bing_verification      || '').slice(0, 200) || null,
-    (f.pinterest_verification || '').slice(0, 200) || null,
-    (f.yandex_verification    || '').slice(0, 200) || null,
     f.custom_css      || null,
     f.custom_head_html || null,
