Changeset 6351545 in Klonkt for src/middleware/site.js


Ignore:
Timestamp:
06/14/2026 08:18:50 AM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
07775b7
Parents:
9e27d64
Message:

tenancy: runtime Solo/Hub mode + mode-aware /admin (Phase 1)

Admin can switch live between modes in Admin -> Settings:

  • solo: exactly one site (the primary/owner site), no /sites routing, leaner /admin.
  • hub: main site + /sites/:slug routing (company; /gebruikers + assignment flow = Phase 2).

Switching is non-destructive (hides only, deletes nothing).

  • app_settings (key/value singleton) + SettingsService (cached getTenancy/setTenancy).
  • resolveSite: solo pins to the primary site + disables /sites/:slug + host mapping.
  • /admin/settings (god-only) toggle; /admin dashboard rewritten, mode-aware.

Tested on the demo: solo/hub dashboard tiles, /sites routing per mode, toggle back/forth.

Co-Authored-By: Claude <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/middleware/site.js

    r9e27d64 r6351545  
    1111
    1212import db from '../config/database.js';
     13import { getTenancy } from '../services/SettingsService.js';
    1314
    1415export function resolveSite(req, res, next) {
    15   // Try /sites/:slug pattern
    16   const m = req.path.match(/^\/sites\/([a-zA-Z0-9_-]+)(\/.*)?$/);
    17   if (m) {
    18     const slug = m[1];
    19     const site = db.prepare('SELECT * FROM sites WHERE slug = ?').get(slug);
    20     if (site) {
    21       res.locals.site = site;
    22       // Strip /sites/:slug from req.url so downstream routes see the rest
    23       req.url = (m[2] || '/');
    24       // Also rewrite originalUrl for redirect targets to keep the prefix
    25       res.locals.siteUrlBase = `/sites/${slug}`;
    26       return next();
     16  const tenancy = getTenancy();
     17  res.locals.tenancy = tenancy; // ook beschikbaar voor views
     18
     19  // In HUB-mode mapt /sites/:slug en (later) een subdomein naar een specifieke
     20  // site. In SOLO-mode bestaat er maar één site: we slaan die routing over en
     21  // pinnen altijd op de primaire site.
     22  if (tenancy === 'hub') {
     23    const m = req.path.match(/^\/sites\/([a-zA-Z0-9_-]+)(\/.*)?$/);
     24    if (m) {
     25      const site = db.prepare('SELECT * FROM sites WHERE slug = ?').get(m[1]);
     26      if (site) {
     27        res.locals.site = site;
     28        req.url = (m[2] || '/'); // strip /sites/:slug zodat downstream de rest ziet
     29        res.locals.siteUrlBase = `/sites/${m[1]}`;
     30        return next();
     31      }
     32    }
     33    const host = req.get('host')?.toLowerCase().replace(/:\d+$/, '');
     34    if (host) {
     35      const site = db.prepare('SELECT * FROM sites WHERE slug = ?').get(host);
     36      if (site) {
     37        res.locals.site = site;
     38        res.locals.siteUrlBase = '';
     39        return next();
     40      }
    2741    }
    2842  }
    2943
    30   // Future: subdomain mapping
    31   const host = req.get('host')?.toLowerCase().replace(/:\d+$/, '');
    32   if (host) {
    33     const site = db.prepare('SELECT * FROM sites WHERE slug = ?').get(host);
    34     if (site) {
    35       res.locals.site = site;
    36       res.locals.siteUrlBase = '';
    37       return next();
    38     }
    39   }
    40 
    41   // Default: pick first site
     44  // Solo (of hub zonder match): de primaire/owner-site (eerste aangemaakte).
    4245  const defaultSite = db.prepare('SELECT * FROM sites ORDER BY created_at ASC LIMIT 1').get();
    4346  if (defaultSite) {
Note: See TracChangeset for help on using the changeset viewer.