Kanonisches Home für Login, Session, Rollen und API-Gates. Fachliche Admin-/Developer-View: `../functional/fachliche_zielarchitektur.md` §2.7. Privacy-Identität: `../functional/guardrails.md`.
- fachliche Autorisierung auf Reflexionsinhalten jenseits von `profile_id`.
Spätere feinere Rollen oder ein Abo ersetzen diese Schicht nicht. Sie hängen **additiv** daran: Session bleibt die Identität, `require_admin` bleibt der grobe Gate, Entitlements bleiben `check_feature_access`. Keine Feature-Limits in `role` und keine Rolle in `tier_id` mischen.
## 2. Account-Modell
**Status: entschieden**
Ein Login (E-Mail) entspricht einem Profil. Kanshō ist keine Multi-Profil-App auf einem Login und keine Vereinsapp.
Mehrere Nutzer pro Instanz: ja. Jede Session ist an genau ein `profile_id` gebunden. Alle personenbezogenen Tabellen tragen diese Bindung.
Klarnamen, E-Mail und Mapping-Tabellen sind Klasse A (Local Only). Sie verlassen die Trusted Zone nicht als Teil eines External Model Context.
**Additiv 2026-10-12.** Der Benutzername ist eine weitere Login-Kennung desselben Profils, keine zweite Identität. Die zweite E-Mail ist Kontaktadresse, kein Login. Beide bleiben Klasse A.
## 2.1 Kontokennungen und Verifikation
**Status: entschieden** (2026-10-12)
- Login mit primärer E-Mail oder Benutzername. Der Benutzername ist optional, eindeutig, 3–32 Zeichen aus Buchstaben, Ziffern, Punkt und Unterstrich.
- Bestehende primäre Adressen gelten mit der Migration als verifiziert.
- Eine neue oder geänderte Adresse wird erst nach dem Bestätigungslink wirksam. Bis dahin bleibt die bisher verifizierte Adresse die Login-Adresse.
- Solange die primäre Adresse nicht verifiziert ist, zeigt die Oberfläche nur den Kontobereich.
- Die zweite E-Mail erhält Reset- und Hinweismails erst nach eigener Verifikation.
- Passwort-Reset-Link: 60 Minuten, einmalig, nur der SHA-256-Hash liegt in der Datenbank. Danach werden die Sessions des Kontos gelöscht.
- Bestätigungslink: 24 Stunden, einmalig, nur der Hash.
- Öffentliches „Passwort vergessen“ antwortet immer gleich und geht nur an bereits verifizierte Adressen. Höchstens drei neue Links pro Konto und Stunde.
- Ein Admin kann für ein anderes Konto denselben Reset auslösen. Der Link geht an die hinterlegte primäre Adresse und an eine bereits verifizierte zweite Adresse. Der letzte aktive Admin kann weder deaktiviert noch auf `user` gesetzt werden.
- SMTP steht in der Server-`.env`. Fehlt sie, gibt es keinen stillen Versand. In `development` wird der Link nur ins Server-Log geschrieben. Der Mailtext enthält nur den Link und den Produktnamen, keinen Dialoginhalt.
## 2.2 Zwei-Faktor
**Status: Hypothese** (2026-10-12). Kein Schema, kein Endpunkt.
- App-TOTP nach dem Passwort und vor der Session. Kein SMS.
- Geheimnis und Wiederherstellungscodes bleiben lokal, Klasse A. Codes werden nur als Hash gespeichert und sind einmalig.
- Sind App und Wiederherstellungscodes verloren, setzt ein Admin den zweiten Faktor zurück. Das läuft nicht über ein Modell.
1. Login mit E-Mail + Passwort, Rate Limit am Login-Endpoint.
2. Passwortprüfung via bcrypt.
3. Session-Token (`secrets.token_urlsafe`), Speicherung in `sessions` mit `expires_at`.
4. Frontend speichert Token lokal und sendet ihn bei API-Calls (Header-Muster Mitai: `X-Auth-Token`).
5.`require_auth` lädt Session + Profil oder antwortet 401.
6. Logout invalidiert die Session serverseitig.
Session-Dauer: Mitai-Default 30 Tage, profilbezogen konfigurierbar. Für Kanshō **bevorzugte Richtung**, konkreter Default später festzulegen.
Registrierung und E-Mail-Verifizierung: Mitai-Muster übernehmen, SMTP-Konfiguration über Server-`.env`.
## 4. Rollen
| Rolle | Nutzer-PWA | Admin-/Developer View | Status |
|---|---|---|---|
| `user` | eigene Reflexionsdaten | nein | entschieden |
| `admin` | eigenes Nutzerkonto plus Verwaltungs- und Diagnosezugriff | ja | entschieden |
Konkretes feineres Rollenmodell (Hauptadmin vs. Entwickler) ist fachlich offen (`produktvision_und_produktidentitaet.md` Entscheidungsstand). Technisch v0.1: zwei Rollen wie Mitai. Weitere Rollen nur nach fachlicher Entscheidung.
UI-Guard analog `RequireAdmin.jsx`. Backend-Guard analog `require_admin`. Die UI ist kein Ersatz für den API-Guard.
## 5. Bewusst nicht übernehmen (Mitai-Lücke)
Mitai dokumentiert eine bekannte Schwäche: ein Profile-Header (`X-Profile-Id`) ohne harte Bindung an die Session ermöglicht IDOR.
**Status: verworfen für Kanshō**
Regeln:
- Die aktive Identität kommt ausschließlich aus der Session.
- Kein Client-Header darf ein anderes `profile_id` wählen.
- Jede Query auf personenbezogene Daten filtert mit dem Session-Profil.
Historische Multi-Profil-Endpunkte von Mitai (`/profiles` als Umschalter) werden nicht nachgebaut.
## 6. Token-Speicherung im Client
Mitai nutzt `localStorage`. Das ist für eine First-Party-PWA akzeptabel, aber XSS-sensitiv.
**Status: bevorzugte Richtung** – gleiches Muster wie Mitai für den Rahmen, mit der Maßgabe, später HttpOnly-Cookie vs. localStorage zu bewerten (`security.md`).
Keine Secrets, API-Keys oder Identity-Mappings im Frontend-Bundle.
## 7. Entscheidungsstand
| Thema | Stand | Status |
|---|---|---|
| Server-Sessions | opaque Token in DB | entschieden |
| Rollen | `user` \| `admin` | entschieden |
| 1 Login = 1 Profil | ja | entschieden |
| IDOR-Header-Profilwahl | nicht übernehmen | verworfen |
| JWT/SSO | nicht Rahmen | verworfen für v0.1 |
| Session-Länge | ~30 Tage | bevorzugte Richtung |
| Feineres Rollenmodell | später | offen |
| Token-Ablage Client | localStorage wie Mitai | bevorzugte Richtung |