#118 — Redis durch datenbank-gestützte Sessions ersetzen (infra) #121

Closed
opened 2026-08-18 13:14:16 +02:00 by lena · 0 comments
lena commented 2026-08-18 13:14:16 +02:00 (Migrated from git.butzei.de)

Story: Redis durch datenbank-gestützte Sessions ersetzen (infra)

As a Betreiber der App,
I want to dass Sessions in der bestehenden PostgreSQL-Datenbank statt in einer separaten Redis-Instanz
gespeichert werden,
so that der Betrieb eine externe Komponente weniger braucht (Deployment, Backup, Monitoring, ein
zusätzlicher Service in docker-compose.yml), ohne dass sich am Session-Verhalten für Nutzer etwas ändert.

Confirmed by reading the code (2026-08-10): Redis wird aktuell ausschließlich als IDistributedCache-Backend
für AddSession() genutzt (CqsTodo.WebApi/Program.cs:148-150, AddStackExchangeRedisCacheAddSession).
Keine andere Stelle im Code verwendet Redis (kein Output-Caching, kein Rate-Limiter-Backend — der Login-Rate-
Limiter läuft in-memory). Es gibt keinen früheren Umstieg auf DB-Sessions — das war ein Missverständnis; die
Architektur war und ist "PostgreSQL · Redis (sessions)" (siehe ai/roles/00_team_overview.md, "Shared context").

Einordnung: Infrastruktur-Story — läuft laut ai/roles/00_team_overview.md, "Infrastructure cycle", durch
den leichtgewichtigen Zyklus (PO-Scope → Architect-Design-Note → Security-Vorprüfung → Implementierung → QA),
nicht den vollen Feature-Zyklus mit Frontend-Anteil, da rein serverseitig.

Depends on: nichts blockierendes. Berührt aber #59 (Remember-me/persistent login) und dessen
Revocation-Mechanismus (SessionsRevokedBeforeUtc, SessionMaintenanceMiddleware,
DestroyCurrentSessionCommand) — deren Verhalten muss unverändert erhalten bleiben, siehe AC unten.

Acceptance criteria:

  • Sessions werden über eine IDistributedCache-Implementierung auf Basis der bestehenden
    TodoDatabase-Postgres-Instanz gespeichert (z. B. via EF Core und einer neuen Sessions/Cache-Tabelle,
    oder einer geeigneten Postgres-IDistributedCache-Bibliothek — konkrete technische Wahl liegt beim
    Architect, siehe Open Questions).
  • Bestehendes Session-Verhalten bleibt unverändert, insbesondere aus #59:
    • Idle-Timeout (SessionPolicy.MaxLifetime, 30 Tage) und rollierendes Cookie-Refresh
      (SessionMaintenanceMiddleware, 24h-Intervall) funktionieren identisch.
    • "Log out of all devices" (RevokeAllSessionsForCurrentUserCommand + GetSessionsRevokedBeforeUtcQuery)
      funktioniert identisch — dieser Mechanismus existiert gerade weil einzelne Redis-Records nicht adressierbar
      sind (siehe GetSessionsRevokedBeforeUtcQuery.cs-Kommentar); das DB-Backend darf hier keine Abkürzung nehmen,
      die diesen Kommentar falsch macht, ohne ihn zu aktualisieren.
    • DestroyCurrentSessionCommand (Logout, Account-Löschung) leert weiterhin den kompletten Session-Record.
  • Cookie-Sicherheitsattribute unverändert: HttpOnly, SameSite=Strict, Secure (siehe
    ai/roles/00_team_overview.md, "Security baseline").
  • Neue EF-Core-Migration für das Session-Schema — eine Migration pro Commit, wie im Team-Workflow üblich.
  • Kein Erhalt bestehender Session-Daten beim Umstieg nötig — ein einmaliges Ausloggen aller aktiven Nutzer
    beim Deploy dieser Story ist akzeptabel (muss aber im PR/Release-Hinweis explizit stehen, nicht stillschweigend
    passieren).
  • Redis wird vollständig entfernt: docker-compose.yml, docker-compose.dev.yml, Aspire/AppHost.cs,
    .env.dev.example, CqsTodo.WebApi.csproj (StackExchange.Redis-Paket), .gitea/workflows/ci.yml (falls dort
    ein Redis-Service für Tests hochgefahren wird), sowie die "Redis (sessions)"-Erwähnung im Stack-Eintrag von
    ai/roles/00_team_overview.md.
  • Architect bestätigt vorab, dass DB-gestützte Sessions (Lese/Schreib bei jedem authentifizierten Request via
    SessionMaintenanceMiddleware) keine spürbare Zusatzlast auf der ohnehin von der App genutzten
    Postgres-Instanz erzeugen (z. B. durch Wahl/Indexierung des Schemas) — kein separates Lastproblem einführen,
    um ein Betriebsproblem zu lösen.

Out of scope for this story:

  • Jede andere denkbare Nutzung von Redis (Caching, Rate-Limiting) — es gibt aktuell keine; falls das in Zukunft
    gewünscht wird, ist das eine neue, separate Story.
  • Migration bestehender aktiver Sessions beim Cutover (siehe AC oben — bewusst nicht erhalten).
  • Multi-Instanz-/Skalierungs-Szenarien über das hinaus, was heute mit einer einzelnen Redis-Instanz möglich war
    (falls DB-Sessions hier andere Grenzen haben, ist das ein Architect-Hinweis, keine neue Anforderung dieser Story).

Open questions (an den Architect):

  • Eigene schlanke IDistributedCache-Implementierung über EF Core/Npgsql, oder eine bestehende
    Postgres-IDistributedCache-Bibliothek? Abwägung: zusätzliche Abhängigkeit vs. selbst zu wartender Code.
  • Passendes Cleanup abgelaufener Session-Zeilen (Redis übernahm TTL/Expiry automatisch; das DB-Backend braucht
    einen äquivalenten Mechanismus, z. B. Lazy-Delete beim Zugriff oder ein periodischer Cleanup-Job).
# Story: Redis durch datenbank-gestützte Sessions ersetzen (infra) **As a** Betreiber der App, **I want to** dass Sessions in der bestehenden PostgreSQL-Datenbank statt in einer separaten Redis-Instanz gespeichert werden, **so that** der Betrieb eine externe Komponente weniger braucht (Deployment, Backup, Monitoring, ein zusätzlicher Service in `docker-compose.yml`), ohne dass sich am Session-Verhalten für Nutzer etwas ändert. **Confirmed by reading the code (2026-08-10):** Redis wird aktuell ausschließlich als `IDistributedCache`-Backend für `AddSession()` genutzt (`CqsTodo.WebApi/Program.cs:148-150`, `AddStackExchangeRedisCache` → `AddSession`). Keine andere Stelle im Code verwendet Redis (kein Output-Caching, kein Rate-Limiter-Backend — der Login-Rate- Limiter läuft in-memory). Es gibt **keinen früheren Umstieg auf DB-Sessions** — das war ein Missverständnis; die Architektur war und ist "PostgreSQL · Redis (sessions)" (siehe `ai/roles/00_team_overview.md`, "Shared context"). **Einordnung:** Infrastruktur-Story — läuft laut `ai/roles/00_team_overview.md`, "Infrastructure cycle", durch den leichtgewichtigen Zyklus (PO-Scope → Architect-Design-Note → Security-Vorprüfung → Implementierung → QA), nicht den vollen Feature-Zyklus mit Frontend-Anteil, da rein serverseitig. **Depends on:** nichts blockierendes. Berührt aber `#59` (Remember-me/persistent login) und dessen Revocation-Mechanismus (`SessionsRevokedBeforeUtc`, `SessionMaintenanceMiddleware`, `DestroyCurrentSessionCommand`) — deren Verhalten muss unverändert erhalten bleiben, siehe AC unten. **Acceptance criteria:** - [ ] Sessions werden über eine `IDistributedCache`-Implementierung auf Basis der bestehenden `TodoDatabase`-Postgres-Instanz gespeichert (z. B. via EF Core und einer neuen `Sessions`/`Cache`-Tabelle, oder einer geeigneten Postgres-`IDistributedCache`-Bibliothek — konkrete technische Wahl liegt beim Architect, siehe Open Questions). - [ ] Bestehendes Session-Verhalten bleibt **unverändert**, insbesondere aus `#59`: - Idle-Timeout (`SessionPolicy.MaxLifetime`, 30 Tage) und rollierendes Cookie-Refresh (`SessionMaintenanceMiddleware`, 24h-Intervall) funktionieren identisch. - "Log out of all devices" (`RevokeAllSessionsForCurrentUserCommand` + `GetSessionsRevokedBeforeUtcQuery`) funktioniert identisch — dieser Mechanismus existiert gerade *weil* einzelne Redis-Records nicht adressierbar sind (siehe `GetSessionsRevokedBeforeUtcQuery.cs`-Kommentar); das DB-Backend darf hier keine Abkürzung nehmen, die diesen Kommentar falsch macht, ohne ihn zu aktualisieren. - `DestroyCurrentSessionCommand` (Logout, Account-Löschung) leert weiterhin den kompletten Session-Record. - [ ] Cookie-Sicherheitsattribute unverändert: `HttpOnly`, `SameSite=Strict`, `Secure` (siehe `ai/roles/00_team_overview.md`, "Security baseline"). - [ ] Neue EF-Core-Migration für das Session-Schema — eine Migration pro Commit, wie im Team-Workflow üblich. - [ ] Kein Erhalt bestehender Session-Daten beim Umstieg nötig — ein einmaliges Ausloggen aller aktiven Nutzer beim Deploy dieser Story ist akzeptabel (muss aber im PR/Release-Hinweis explizit stehen, nicht stillschweigend passieren). - [ ] Redis wird vollständig entfernt: `docker-compose.yml`, `docker-compose.dev.yml`, `Aspire/AppHost.cs`, `.env.dev.example`, `CqsTodo.WebApi.csproj` (StackExchange.Redis-Paket), `.gitea/workflows/ci.yml` (falls dort ein Redis-Service für Tests hochgefahren wird), sowie die "Redis (sessions)"-Erwähnung im Stack-Eintrag von `ai/roles/00_team_overview.md`. - [ ] Architect bestätigt vorab, dass DB-gestützte Sessions (Lese/Schreib bei jedem authentifizierten Request via `SessionMaintenanceMiddleware`) keine spürbare Zusatzlast auf der ohnehin von der App genutzten Postgres-Instanz erzeugen (z. B. durch Wahl/Indexierung des Schemas) — kein separates Lastproblem einführen, um ein Betriebsproblem zu lösen. **Out of scope for this story:** - Jede andere denkbare Nutzung von Redis (Caching, Rate-Limiting) — es gibt aktuell keine; falls das in Zukunft gewünscht wird, ist das eine neue, separate Story. - Migration bestehender aktiver Sessions beim Cutover (siehe AC oben — bewusst nicht erhalten). - Multi-Instanz-/Skalierungs-Szenarien über das hinaus, was heute mit einer einzelnen Redis-Instanz möglich war (falls DB-Sessions hier andere Grenzen haben, ist das ein Architect-Hinweis, keine neue Anforderung dieser Story). **Open questions (an den Architect):** - Eigene schlanke `IDistributedCache`-Implementierung über EF Core/Npgsql, oder eine bestehende Postgres-`IDistributedCache`-Bibliothek? Abwägung: zusätzliche Abhängigkeit vs. selbst zu wartender Code. - Passendes Cleanup abgelaufener Session-Zeilen (Redis übernahm TTL/Expiry automatisch; das DB-Backend braucht einen äquivalenten Mechanismus, z. B. Lazy-Delete beim Zugriff oder ein periodischer Cleanup-Job).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
robert/todo#121
No description provided.