Kein Addon — fixer Core-Bereich (Sidebar nach „Personen") bzw. Standard-Funktionalität. Live seit v0.20.0 (2026-07-27, Phasen B0–B3 in einem Zug); Bereich «Berechtigungen» komplett umgebaut in v0.26.0 (2026-09-01: drei Register, Berechtigungs-Rollen, Owner = Admin, Admin-Meldungen, Spesen-Freigabe hier pflegbar). Konzept mit allen User-Entscheiden: docs/konzept-berechtigungen-portal.md (Nachtrag v0.26.0 am Ende).
Vor v0.20.0 galt in CluCore „eingeloggt = Vollzugriff" (fast alle Views nur @login_required). Seit v0.20.0:
AuthRoleTemplate.access_level: clucore (volle Verwaltung — owner, admin, eigene Vorstands-Rollen) oder portal (nur Clu-Portal — member, eigene Rollen wie Leitung)./clucore/* und /api/* nur noch mit aktiver clucore-Rolle (Superuser ok). Portal-User → Redirect /portal/; APIs → 403. Ausnahmen: logout, password-reset, /portal/*, /zugang/*, Kalender-Magic-Links/ICS./api/ ist automatisch clucore-only — APIs für Mitglieder gehören unter /portal/api/.User.username ist global unique, dieselbe E-Mail kann aber in mehreren Vereinen existieren (interner username bekommt dann ein Suffix). ⚠️ In Tests funktioniert Client.login() damit NICHT (kein request) — Login-POST auf /clucore/ oder force_login verwenden./portal/ (User-Entscheid: auch der Admin soll zuerst seinen Kalender sehen); CluCore-Berechtigte haben dort den Button „Zum Clu-Core". Lesezeichen auf /clucore/ funktionieren direkt.Vor v0.26.0 war alles auf einer Seite: Personenliste plus ein Aufklapp-Panel «Rollen verwalten», in dem Feld-Matrix, Werkzeug-Schalter und Ebenen-Schalter in EINEM Block standen, dazu ein Button «Genehmiger» (wofür? Spesen? Self-Service?). Jetzt:
Liste aller Personen (Vorname, Nachname, primäre E-Mail) mit:
AuthAccess/auth_access):
/zugang/<token>/ (Token nur als SHA-256-Hash gespeichert, Einmalgebrauch; Gültigkeit 3 Wochen bei clucore-Rolle, sonst 3 Monate)user.is_active=False + Session-Kill; der User wird NIE gelöscht — created_by-Referenzen)Links die Rollenliste (Systemrollen Admin und Mitglied mit Erklärtext, darunter die eigenen Rollen mit Personen-Zähler), rechts das Detail in Abschnitten:
Vorlagen beim Anlegen («+ Neue Rolle»): Leitung · Selbstbedienung · Spesen einreichen · Revisor · Verwaltung (Clu-Core) · Leer — jede Vorlage setzt Ebene, Werkzeuge und Selfservice-Modus vor, alles bleibt editierbar. «⊞ Übersicht» zeigt die Matrix Rollen × Werkzeuge auf einen Blick. Deep-Links: ?tab=rollen, ?role=<id>.
Admin hinzufügen oder entfernen, Login eines Admins entfernen oder reaktivieren: Bestätigungs-Popup (beim Entzug der eigenen Admin-Rolle mit Warnung — danach Redirect, das Gate greift sofort), dann Meldung + Mail an alle aktiven Admins und die betroffene Person (notify_admin_change, Meldungstyp admin_change, Link auf den Bereich). Jede Mutation im Bereich (Rolle zuweisen/entziehen, Rolle anlegen/ändern/löschen, Einladen, Login entfernen, Freigabe-Personen) landet mit Vorher/Nachher im AuthMutationAuditLog (context clucore).
Sicherheits-Fix in derselben Version: Die mutierenden Berechtigungs-APIs hingen bis v0.25.x nur am CluCore-Gate — eine eigene Rolle mit Ebene Clu-Core (z.B. «Vorstand») konnte sich damit selbst die Owner-Rolle geben. Jetzt dürfen nur owner/admin ändern (_admin_required, 403); Clu-Core-Rollen ohne Admin sehen den Bereich lesend (Banner, keine Buttons).
owner-Key bleibt in der DB (Onboarding vergibt owner + admin), ist aber nirgends mehr sichtbar oder zuweisbar; aufgeräumt wird er erst, wenn nichts mehr daran hängt./portal/Eigenständige, schlanke Seite in der Vereins-Primärfarbe (aus ClubProfile; bewusst KEINE Einbettung in die extern gerenderte Builder-Webseite — CSP/Proxy):
has_login-Spalte („Login") aus der Personen-Liste entfernt — Zugriffsstatus lebt im Berechtigungen-Bereich.Echte Teilrechte je Bereich für Clu-Core-Rollen (Endziel laut User; ersetzt den Ebenen-Schalter), Werkzeuge der Leitung (Termine für die eigene Gruppe u.ä.), Kassier-Teilrechte in der Buchhaltung.
Der Abschnitt «Clu-Portal (B3)» oben beschreibt den Stand v0.20.0. Seit v0.26.16–.19 ist das Portal ein Dashboard: Termine als Kacheln mit Datumsblock, Info-Pills (Ort als Kartenlink, Organisation, Serie, Teilnehmerzahl) und Kachel-Fuss für Zu-/Absage ohne Neuladen; die Module Meldungen, Dateien, Spesen, Revision, Kalender-Abo, Meine Daten und Konto stehen aufgeklappt auf der Seite, leere Module bleiben sichtbar; Schnellzugriff-Kacheln, Wochenstreifen und «n offen»-Filter wurden wieder entfernt, weil sie doppelt oder verwirrend waren. Sektions-Köpfe mit gemeinsamem SVG-Icon-Set statt Emojis (v0.26.20). Das Warum steht auf Design-Entscheidungen unter «Fluides Layout, Portal-Dashboard und Icon-Set». Seither dazugekommen: Material-Anfragen (Inventar), Werkzeug «Leitung» und Abmelden mit Grund (Kalender), Profilbild unter «Meine Daten» (Personenbilder, siehe Personen).
Was kann es: Login, Logout, Passwort-Reset und alle Links aus Mails gelten nur auf der Vereins-Subdomain. Auf cluhu.ch (Hauptdomain, CLUHU_MAIN_DOMAIN, Vorgabe cluhu.ch) meldet sich nur noch der App-Owner (Superuser) an und landet im Cockpit; ein Vereins-Login mit richtigen Zugangsdaten bekommt den Hinweis «Melde dich auf der Adresse deines Vereins an: verein.cluhu.ch», falsche Zugangsdaten verraten nichts. Passwort vergessen sucht auf der Vereins-Subdomain nur Logins dieses Vereins (gleiche E-Mail in zwei Vereinen → genau eine Mail, die des Hosts), der Bestätigungs-Link ist nur auf einer Domain dieses Vereins einlösbar (sonst 404). Termin-Antwort, Stellvertreter-Link, Abmeldelink und Kalender-Feed vergleichen den Verein des Tokens mit dem Host, sonst 404. Eine unbekannte Subdomain *.cluhu.ch antwortet 404 statt der Landingpage. Mail-Links baut der zentrale Helfer apps/core/sites.py (club_base_url(club), primäre Domain des Vereins) statt vier Kopien, die irgendeine Domain nahmen.
Warum so: Befund K23: Das Login-Formular war auf cluhu.ch erreichbar, der Anmelde-Baustein fand Vereins-Logins global, die Zugehörigkeitsprüfung kam erst beim nächsten Seitenaufruf (403 oder Sackgasse); bei gleicher E-Mail in zwei Vereinen gewann der globale Benutzername vor der E-Mail im Verein. Yves' Leitplanke (D52): Nichts wird vereinsübergreifend durchgereicht, auch nicht bei gleicher E-Mail in zwei Vereinen. ⚠️ TenantEmailBackend: auf der Subdomain gilt neu zuerst die E-Mail im Verein, dann der exakte Benutzername nur, wenn die Person zu diesem Verein gehört; ohne Request (Shell) der Standardweg.
Neben Personen & Logins, Berechtigungs-Rollen und Freigaben: sechs Schalter für Haushalte im Portal (PortalHouseholdSettings, Admin-only, ?tab=mitgliederportal): Haushalt im Portal anzeigen (an/aus), Daten betreuter Personen ändern (nach Feldklasse / alles mit Freigabe / nein), Leere Felder ergänzen (immer direkt / wie ändern), Zugang für betreute Personen aktivieren (ja / nur als Antrag / nein), Zustellung «Wer bekommt was» ändern (Haken direkt, Rechnung als Antrag / alles als Antrag / nein), Meldung an die Admins (jede / erste je Haushalt / keine). «Speichern», «Auf Vorgabe zurücksetzen», Link zum Protokoll unter Mitglieder › Import nachbearbeiten; die Feld-Matrix bleibt im Rollen-Editor. Seit v0.28.128 liest das Mitgliederportal die Schalter «Haushalt im Portal anzeigen», «Daten betreuter Personen ändern», «Leere Felder ergänzen», «Zugang für betreute Personen aktivieren» und «Meldung an die Admins» für die Daten-Karten je Person und den Zugang fürs Kind; seit v0.28.130 auch «Zustellung ändern» für das Modul «Wer bekommt was» (Haken direkt, Rechnung als Antrag / alles als Antrag / nein) — siehe Mitgliedschaften › Mitgliederportal für Haushalte. Das Setzen des Passworts über den Einladungslink setzt seit v0.28.130 den Portal-Haken an den Links der Person (complete_portal_access). Hier stehen sie, weil ein vorsichtiger Verein das Abschalten unter Berechtigungen erwartet (D61). Die Einladung aus dem Portal nutzt denselben Dienst wie «Login aktivieren» (authorization.services.invite_person(club, person, actor, source)), protokolliert «ausgelöst von» und meldet den Admins nach Schalter.