Index: CLAUDE.md
===================================================================
--- CLAUDE.md	(revision 960f0159a39a973d50321222d1610f881d16e6ae)
+++ CLAUDE.md	(revision 7e9d0ea09d7fd1dfcf481f3a5319b2f4f294a0e0)
@@ -63,6 +63,6 @@
 Tests live in `test/*.test.js` and run against an in-memory SQLite
 (`DATABASE_PATH=':memory:'`), so they never touch real data. Cover new
-permission/tenancy logic with tests — `PermissionsService.canAdminSite` was once
-silently broken; see `test/hub-permissions.test.js`.
+permission logic with tests — `PermissionsService.canAdminSite` was once
+silently broken; see `test/site-permissions.test.js`.
 
 ## Architecture Overview
Index: src/config/database.js
===================================================================
--- src/config/database.js	(revision 960f0159a39a973d50321222d1610f881d16e6ae)
+++ src/config/database.js	(revision 7e9d0ea09d7fd1dfcf481f3a5319b2f4f294a0e0)
@@ -266,6 +266,9 @@
   `);
 
-  // Global app settings (key/value singleton). Includes the tenancy mode
-  // (solo = one site, hub = company site + /user/). Default = solo.
+  // Global app settings (key/value singleton). One instance is one owner, so
+  // there is no tenancy mode here anymore — see SettingsService.
+  // Oudere installaties dragen nog een dode rij key='tenancy' ('solo' of
+  // 'circle'). Niets leest hem; bewust laten staan (shaer-x7c0) in plaats van
+  // er opruimcode voor te schrijven die na één ronde zelf dood is.
   db.exec(`
     CREATE TABLE IF NOT EXISTS app_settings (
@@ -275,5 +278,4 @@
     );
   `);
-  db.prepare("INSERT OR IGNORE INTO app_settings (key, value) VALUES ('tenancy', 'solo')").run();
 
   // ── Statistics (premium) — cookie-free ──────────────────────
Index: src/services/ensurePrimarySite.js
===================================================================
--- src/services/ensurePrimarySite.js	(revision 960f0159a39a973d50321222d1610f881d16e6ae)
+++ src/services/ensurePrimarySite.js	(revision 7e9d0ea09d7fd1dfcf481f3a5319b2f4f294a0e0)
@@ -3,5 +3,5 @@
 
 // A Klonkt instance should ALWAYS have a primary site — it carries the identity
-// (title, theme, profile) and is the anchor point in solo/hub/circle mode.
+// (title, theme, profile) and is the anchor point for the whole instance.
 // The register flow already creates one, but an admin created via a script
 // (or an empty sites table for any reason) left the instance without a site:
@@ -10,5 +10,4 @@
 // This helper runs at boot (and is idempotent): as soon as there is an admin
 // but no site yet, it creates a default site owned by the first god/admin.
-// Tenancy-agnostic — applies to solo, hub, and circle.
 
 function defaultTitle() {
Index: st/hub-permissions.test.js
===================================================================
--- test/hub-permissions.test.js	(revision 960f0159a39a973d50321222d1610f881d16e6ae)
+++ 	(revision )
@@ -1,86 +1,0 @@
-// Unit-tests voor de hub-permissielaag — juist `canAdminSite` was lang stil kapot
-// (las een nooit-gevulde user.siteRoles), dus dit dekt 'm nu af. Draait op de
-// ingebouwde node:test (geen extra deps). In-memory SQLite → raakt geen echte data.
-//
-// Run: npm test   (= node --test)
-
-import { test } from 'node:test';
-import assert from 'node:assert/strict';
-
-// Isoleer van de echte DB: ':memory:' MOET gezet zijn vóór de eerste import van
-// config/database.js (die maakt de singleton-connectie op basis van deze env).
-process.env.DATABASE_PATH = ':memory:';
-
-const dbMod = await import('../src/config/database.js');
-const db = dbMod.default;
-const PermissionsService = (await import('../src/services/PermissionsService.js')).default;
-const { getPrimarySite } = await import('../src/middleware/site.js');
-
-dbMod.initializeDatabase();
-
-// ── Seed ────────────────────────────────────────────────────────────────
-function addUser(id, role) {
-  db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)')
-    .run(id, id, id + '@test', 'x', role);
-}
-function addSite(id, slug, ownerId, isPrimary = 0) {
-  db.prepare('INSERT INTO sites (id, slug, title, owner_id, is_primary) VALUES (?,?,?,?,?)')
-    .run(id, slug, slug, ownerId, isPrimary);
-}
-addUser('u-god', 'god');
-addUser('u-owner', 'member');
-addUser('u-collab', 'member');
-addUser('u-stranger', 'member');
-addSite('s1', 'site-een', 'u-owner', 1);
-
-const god      = { id: 'u-god', role: 'god' };
-const owner    = { id: 'u-owner', role: 'member' };
-const collab   = { id: 'u-collab', role: 'member' };
-const stranger = { id: 'u-stranger', role: 'member' };
-const site = () => db.prepare('SELECT * FROM sites WHERE id = ?').get('s1');
-
-// ── canAdminSite ─────────────────────────────────────────────────────────
-test('canAdminSite: god mag altijd', () => {
-  assert.equal(PermissionsService.canAdminSite(god, site()), true);
-});
-test('canAdminSite: owner mag', () => {
-  assert.equal(PermissionsService.canAdminSite(owner, site()), true);
-});
-test('canAdminSite: vreemde zonder membership mag niet', () => {
-  assert.equal(PermissionsService.canAdminSite(stranger, site()), false);
-});
-test('canAdminSite: collaborator zonder membership mag niet', () => {
-  assert.equal(PermissionsService.canAdminSite(collab, site()), false);
-});
-test('canAdminSite: collaborator MET site_members-admin mag (de gefixte dode code)', () => {
-  db.prepare("INSERT OR REPLACE INTO site_members (site_id, user_id, role) VALUES ('s1','u-collab','admin')").run();
-  assert.equal(PermissionsService.canAdminSite(collab, site()), true);
-});
-test('canAdminSite: site_members met rol "member" (geen admin) mag niet', () => {
-  db.prepare("INSERT OR REPLACE INTO site_members (site_id, user_id, role) VALUES ('s1','u-stranger','member')").run();
-  assert.equal(PermissionsService.canAdminSite(stranger, site()), false);
-});
-test('canAdminSite: null user of null site → false (geen crash)', () => {
-  assert.equal(PermissionsService.canAdminSite(null, site()), false);
-  assert.equal(PermissionsService.canAdminSite(owner, null), false);
-});
-
-// ── Delegatie: canEditPost via canAdminSite ──────────────────────────────
-test('canEditPost: collaborator-admin kan een post van een ander bewerken (via canAdminSite)', () => {
-  const post = { author_id: 'iemand-anders' };
-  assert.equal(PermissionsService.canEditPost(collab, post, site()), true);
-});
-test('canEditPost: vreemde kan een post van een ander NIET bewerken', () => {
-  const post = { author_id: 'iemand-anders' };
-  assert.equal(PermissionsService.canEditPost(stranger, post, site()), false);
-});
-
-// ── getPrimarySite (#3) ──────────────────────────────────────────────────
-test('getPrimarySite: geeft de is_primary-site', () => {
-  assert.equal(getPrimarySite().id, 's1');
-});
-test('getPrimarySite: valt terug op de oudste als geen is_primary gemarkeerd is', () => {
-  db.prepare('UPDATE sites SET is_primary = 0').run();
-  assert.equal(getPrimarySite().id, 's1'); // s1 is de oudste/enige
-  db.prepare("UPDATE sites SET is_primary = 1 WHERE id = 's1'").run(); // herstel
-});
Index: test/site-permissions.test.js
===================================================================
--- test/site-permissions.test.js	(revision 7e9d0ea09d7fd1dfcf481f3a5319b2f4f294a0e0)
+++ test/site-permissions.test.js	(revision 7e9d0ea09d7fd1dfcf481f3a5319b2f4f294a0e0)
@@ -0,0 +1,90 @@
+// Unit-tests voor de site-permissielaag — juist `canAdminSite` was lang stil kapot
+// (las een nooit-gevulde user.siteRoles), dus dit dekt 'm nu af. Draait op de
+// ingebouwde node:test (geen extra deps). In-memory SQLite → raakt geen echte data.
+//
+// Heette hub-permissions.test.js: de hub-modus is weg (72ec6a4), maar wat hier
+// getest wordt niet. canAdminSite, canEditPost en getPrimarySite zijn springlevend
+// en dit bestand is hun enige dekking — alleen de naam verwees nog naar de modus.
+//
+// Run: npm test   (= node --test)
+
+import { test } from 'node:test';
+import assert from 'node:assert/strict';
+
+// Isoleer van de echte DB: ':memory:' MOET gezet zijn vóór de eerste import van
+// config/database.js (die maakt de singleton-connectie op basis van deze env).
+process.env.DATABASE_PATH = ':memory:';
+
+const dbMod = await import('../src/config/database.js');
+const db = dbMod.default;
+const PermissionsService = (await import('../src/services/PermissionsService.js')).default;
+const { getPrimarySite } = await import('../src/middleware/site.js');
+
+dbMod.initializeDatabase();
+
+// ── Seed ────────────────────────────────────────────────────────────────
+function addUser(id, role) {
+  db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)')
+    .run(id, id, id + '@test', 'x', role);
+}
+function addSite(id, slug, ownerId, isPrimary = 0) {
+  db.prepare('INSERT INTO sites (id, slug, title, owner_id, is_primary) VALUES (?,?,?,?,?)')
+    .run(id, slug, slug, ownerId, isPrimary);
+}
+addUser('u-god', 'god');
+addUser('u-owner', 'member');
+addUser('u-collab', 'member');
+addUser('u-stranger', 'member');
+addSite('s1', 'site-een', 'u-owner', 1);
+
+const god      = { id: 'u-god', role: 'god' };
+const owner    = { id: 'u-owner', role: 'member' };
+const collab   = { id: 'u-collab', role: 'member' };
+const stranger = { id: 'u-stranger', role: 'member' };
+const site = () => db.prepare('SELECT * FROM sites WHERE id = ?').get('s1');
+
+// ── canAdminSite ─────────────────────────────────────────────────────────
+test('canAdminSite: god mag altijd', () => {
+  assert.equal(PermissionsService.canAdminSite(god, site()), true);
+});
+test('canAdminSite: owner mag', () => {
+  assert.equal(PermissionsService.canAdminSite(owner, site()), true);
+});
+test('canAdminSite: vreemde zonder membership mag niet', () => {
+  assert.equal(PermissionsService.canAdminSite(stranger, site()), false);
+});
+test('canAdminSite: collaborator zonder membership mag niet', () => {
+  assert.equal(PermissionsService.canAdminSite(collab, site()), false);
+});
+test('canAdminSite: collaborator MET site_members-admin mag (de gefixte dode code)', () => {
+  db.prepare("INSERT OR REPLACE INTO site_members (site_id, user_id, role) VALUES ('s1','u-collab','admin')").run();
+  assert.equal(PermissionsService.canAdminSite(collab, site()), true);
+});
+test('canAdminSite: site_members met rol "member" (geen admin) mag niet', () => {
+  db.prepare("INSERT OR REPLACE INTO site_members (site_id, user_id, role) VALUES ('s1','u-stranger','member')").run();
+  assert.equal(PermissionsService.canAdminSite(stranger, site()), false);
+});
+test('canAdminSite: null user of null site → false (geen crash)', () => {
+  assert.equal(PermissionsService.canAdminSite(null, site()), false);
+  assert.equal(PermissionsService.canAdminSite(owner, null), false);
+});
+
+// ── Delegatie: canEditPost via canAdminSite ──────────────────────────────
+test('canEditPost: collaborator-admin kan een post van een ander bewerken (via canAdminSite)', () => {
+  const post = { author_id: 'iemand-anders' };
+  assert.equal(PermissionsService.canEditPost(collab, post, site()), true);
+});
+test('canEditPost: vreemde kan een post van een ander NIET bewerken', () => {
+  const post = { author_id: 'iemand-anders' };
+  assert.equal(PermissionsService.canEditPost(stranger, post, site()), false);
+});
+
+// ── getPrimarySite (#3) ──────────────────────────────────────────────────
+test('getPrimarySite: geeft de is_primary-site', () => {
+  assert.equal(getPrimarySite().id, 's1');
+});
+test('getPrimarySite: valt terug op de oudste als geen is_primary gemarkeerd is', () => {
+  db.prepare('UPDATE sites SET is_primary = 0').run();
+  assert.equal(getPrimarySite().id, 's1'); // s1 is de oudste/enige
+  db.prepare("UPDATE sites SET is_primary = 1 WHERE id = 's1'").run(); // herstel
+});
