feat(users): SSO-Nutzer-Personalisierung + Admin-Endpunkte

Hintergrund: SSO-Nutzer (va.linix.de) werden bereits beim ersten Besuch
automatisch registriert, hatten aber keinen echten Namen im LLM-Kontext
und konnten vom Admin nicht vorbereitet werden.

Änderungen:
- ws.py + chat.py: Nutzeridentität (display_name + Erinnerungen) wird als
  führende System-Message bei jeder Anfrage injiziert; für anonyme
  Dev-Nutzer (AUTH_ENABLED=false) wird diese Injection übersprungen
- store.py: update_display_name() im ABC und SQLiteStore
- schemas.py: UserUpdate (display_name)
- admin.py:
  - PUT /api/admin/users/{id}: Anzeigenamen eines SSO-Nutzers setzen
  - POST /api/admin/users/{id}/memories: initiale Erinnerungen vorbelegen
- BEDIENUNGSANLEITUNG §7.2: neuer Abschnitt "SSO-Nutzer — automatische
  Registrierung" mit vollständigem Workflow; §7.3/7.4 neu nummeriert;
  Anhang B.5 mit neuen Endpunkten ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-18 17:55:05 +02:00
commit 68b02f42a1
6 changed files with 157 additions and 14 deletions

View file

@ -6,7 +6,7 @@ from fastapi.responses import JSONResponse, StreamingResponse
from app.config import settings
from app.errors import RoutingError
from app.auth import require_user
from app.store import User, SessionOwnershipError
from app.store import ANONYMOUS_USER_ID, User, SessionOwnershipError
from app.dependencies import (
resolve_route,
build_orchestrator,
@ -75,11 +75,15 @@ async def chat(
raise HTTPException(status_code=422, detail=str(exc))
llm_context = list(conversation)
user_context_parts = []
if user.id != ANONYMOUS_USER_ID:
user_context_parts.append(f"Du sprichst mit {user.display_name}.")
if memories:
memory_text = "Was du ueber den Nutzer weisst:\n" + "\n".join(
f"- {m.content}" for m in memories
user_context_parts.append(
"Was du ueber den Nutzer weisst:\n" + "\n".join(f"- {m.content}" for m in memories)
)
llm_context = [{"role": "system", "content": memory_text}] + llm_context
if user_context_parts:
llm_context = [{"role": "system", "content": "\n".join(user_context_parts)}] + llm_context
# Notfall-Erkennung zuerst (immer eskalieren, auch bei Quota-Limit).
emergency = handle_emergency(user, payload.text, store)