Multi-User-Plattform: jeder Benutzer hat eigene, isolierte Daten
- Auth via Session-Cookie + Login-Seite (scrypt, lib/password.js, sessions-Tabelle) - AsyncLocalStorage (lib/context.js) propagiert aktuellen Benutzer durch alle Libs - user_id auf allen Datentabellen (FK->users ON DELETE CASCADE), per-user PK/UNIQUE (app_state, settings, prompts, design, jobangebote) und per-user Dateispeicher (data/<dir>/<userId>/) - Alle Queries in server.js + lib/api.js nach user_id scope-iert - Pro-Benutzer-Konfiguration (Ollama/Mail/CalDAV/API-Token) in app_state, Live gelesen via config.get(); Hintergrund-Loops (IMAP/CalDAV) iterieren alle Benutzer - REST-API /api/v1: X-API-Key loest den Token zu einem Benutzer auf, Anfragen operieren nur auf dessen Daten - Admin-Panel /admin: Benutzer anlegen, Passwort zuruecksetzen, loeschen (mit Daten) - Idempotente Migration (lib/migrate-multiuser.js + scripts/migrate-to-multiuser.js): bestehende Daten werden dem Benutzer admin:admin zugeordnet Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
// Per-request user context.
|
||||
//
|
||||
// The web UI authenticates a user via a signed session cookie (see the
|
||||
// /login flow + auth middleware in server.js). The middleware stores the
|
||||
// resolved user object in an AsyncLocalStorage, so any code running during the
|
||||
// request — including the libs (config, mailer, caldav, chat) called deep in
|
||||
// the stack — can read the *current user* without threading it through every
|
||||
// function signature. Background jobs (IMAP poll, CalDAV sync) set the same
|
||||
// context per user while iterating, so each user's config/data is used in turn.
|
||||
//
|
||||
// This is the keystone of the multi-tenant split: config.get() reads the current
|
||||
// user's cfg rows, and the per-user query helpers below filter every SELECT/INSERT
|
||||
// by the current user, guaranteeing isolation between users.
|
||||
|
||||
const { AsyncLocalStorage } = require('async_hooks');
|
||||
|
||||
const userContext = new AsyncLocalStorage();
|
||||
|
||||
// The current user object ({ id, username, is_admin }) or null outside a request
|
||||
// (e.g. during boot). Anything that needs the user id must call this and decide
|
||||
// how to behave when it is absent.
|
||||
function currentUser() {
|
||||
return userContext.getStore() || null;
|
||||
}
|
||||
|
||||
// Convenience: the current user's id, or null when no user is set.
|
||||
function currentUserId() {
|
||||
const u = currentUser();
|
||||
return u ? u.id : null;
|
||||
}
|
||||
|
||||
module.exports = { userContext, currentUser, currentUserId };
|
||||
Reference in New Issue
Block a user