fix: Kontowechsel ließ Push dauerhaft mit 404 scheitern

Nach einem Login mit korrigierter Groß-/Kleinschreibung (siehe vorheriger Fix zur userId-
Stabilität) bezog sich die lokale Versionsverfolgung je Entität (BasedOnServerSeq-Cache) und der
Pull-Cursor weiterhin auf das alte Konto - ServerSeq-Werte sind aber nur innerhalb des Event-Logs
EINES Kontos gültig. Der Push wurde zu Recht abgelehnt, der Server kannte die Entität unter der
neuen userId aber gar nicht (404 beim Nachladen), und HandleRejectedAsync gab bei einem 404
bisher einfach auf, ohne den veralteten Cache-Eintrag zu bereinigen - derselbe Fehlschlag bei
jedem weiteren Sync-Versuch.

Dreiteiliger Fix: (1) ein 404 beim Nachladen löscht jetzt den stale Cache-Eintrag, sodass der
nächste Push die Entität korrekt als neu behandelt und selbstheilend durchgeht; (2) der
"Vollständigen Sync erzwingen"-Button setzt jetzt auch die Push-Versionsverfolgung zurück, nicht
nur den Pull-Cursor; (3) SyncLogin erkennt einen echten Kontowechsel künftig proaktiv anhand der
kanonischen userId aus der Server-Antwort und resettet automatisch, bevor der Folgefehler
überhaupt auftreten kann.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 00:05:24 +02:00
co-authored by Claude Sonnet 5
parent ba8786906a
commit 979511ab6a
9 changed files with 229 additions and 13 deletions
+35
View File
@@ -1772,6 +1772,18 @@ die Docker-Verifikation unter 10.2.4 (kein Docker im Entwicklungsstand verfügba
"abgehängten" Gerät einmal "Vollständigen Sync erzwingen" (10.1.10) nutzen, damit es den
unter der korrekten `userId` bereits vorhandenen Bestand nachlädt.
**Nachtrag (Folgefehler nach dem Re-Login — 10.3.5):** Nach der Korrektur landete ein
Gerät in einer Endlosschleife: jeder Push desselben `Unit`-Ereignisses wurde mit einem 404
abgelehnt ("aktueller Server-Stand konnte nicht nachgeladen werden"). Ursache: die lokale
Versionsverfolgung je Entität (`EventQueue.entity_versions`, `BasedOnServerSeq`) UND der
Pull-Cursor (`GetLastServerSeq`) bezogen sich noch auf das ALTE (falsch geschriebene) Konto
— ServerSeq-Werte sind aber ausschließlich innerhalb des Event-Logs EINES Kontos
bedeutungsvoll. Der Push wurde deshalb zu Recht abgelehnt (`BasedOnServerSeq` passte nicht
zum neuen, leeren Konto), aber `GetLatestForEntity` kannte die Entität unter der neuen
`userId` gar nicht (404) — und `HandleRejectedAsync` gab bei einem 404 bisher einfach auf,
ohne den stale Cache-Eintrag zu bereinigen: derselbe Fehlschlag bei jedem weiteren Versuch.
Siehe 10.3.5 unten für den Fix.
### 10.3 Verschlüsselung
- [x] **10.3.1** Schlüsselübertragung auf ein zweites Gerät (QR-Code oder Passphrase).
@@ -1844,6 +1856,29 @@ die Docker-Verifikation unter 10.2.4 (kein Docker im Entwicklungsstand verfügba
akzeptiert (Einzel-/Wenig-Geräte-Nutzung) — falls das je zum echten Problem wird, müsste der
Event-Applier dieselben Validierungen wie die Repository-Save-Methoden durchlaufen, ohne
dabei erneut ein Sync-Ereignis auszulösen.
- [x] **10.3.5** Stale lokale Versionsverfolgung nach einem Kontowechsel (direkte Folge von
10.3.4 + 10.2.5, siehe Nachtrag zu 10.2.5).
**Fix, dreiteilig:**
1. `SyncEngine.HandleRejectedAsync`: ein 404 von `GET /api/sync/entity/{type}/{id}`
bedeutet, der Server kennt die Entität unter der aktuellen `userId` gar nicht — statt
endlos mit demselben Fehler zu scheitern, wird jetzt `EventQueue.ClearKnownServerSeq`
für genau diese Entität aufgerufen; der nächste Push behandelt sie korrekt als neu und
wird vom (für sie leeren) Konto angenommen. Selbstheilend, ohne Nutzeraktion nötig.
2. `EventQueue.ResetKnownServerSeqs()` (löscht die gesamte `entity_versions`-Collection) im
"Vollständigen Sync erzwingen"-Button (10.1.10) ergänzt — der Button setzt jetzt sowohl
den Pull-Cursor als auch die Push-Versionsverfolgung zurück.
3. `SyncLogin` erkennt einen Kontowechsel jetzt proaktiv: `SyncAuthService.LoginAsync`
liefert neben dem Token auch die KANONISCHE `userId` aus der Server-Antwort zurück (nicht
den beim Login eingegebenen Namen). Weicht sie von der zuletzt gespeicherten
(`SyncSettingsService.LastUserId`) ab, werden Pull-Cursor und Versionsverfolgung
automatisch zurückgesetzt — zukünftige Kontowechsel (oder Schreibweisen-Korrekturen wie
hier) lösen den Folgefehler dadurch gar nicht erst aus.
Neue Tests: `EventQueueTests` (`ClearKnownServerSeq`, `ResetKnownServerSeqs`),
`SyncEngineTests.PushAsync_AbgelehnterPushServerKenntEntitaetNicht_
LoeschtStaleCacheUndErholtSichSelbst` (Ende-zu-Ende: abgelehnter Push mit stale Cache →
Selbstheilung → zweiter Push erfolgreich), `SyncSettingsServiceTests` (`LastUserId`
persistiert/bleibt bei fehlendem `userId`-Argument unverändert).
**Verifikation:** `dotnet build LehrerApp.sln && dotnet test LehrerApp.sln` grün (591 Tests,
inkl. `EventApplierTests`, `ChangeHookCascadeTests`, `AttachmentSyncerTests`,