Skip to content

Offline geschriebene Texte bleiben auf dem Gerät und landen beim nächsten Start in Convex (LRN-30) - #21

Open
hernstev97 wants to merge 4 commits into
mainfrom
feat/lrn-30-offline-drafts
Open

hernstev97 wants to merge 4 commits into
mainfrom
feat/lrn-30-offline-drafts

Conversation

@hernstev97

@hernstev97 hernstev97 commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

Für LRN-30: Wer die App ohne Netz startet („Offline weiterlesen“), konnte Übungen bearbeiten, aber beim Neuladen war der Text weg. Für den Erzählkurs ist das ein echtes Hindernis: Du schreibst im Bus kurze Texte, und gerade dort fehlt oft das Netz.

Jetzt legt der Offline-Lesemodus jede Eingabe in einer Übung auf dem Gerät ab. Beim nächsten Start mit Anmeldung landet sie als Entwurf in Convex. Liegt dort schon ein anderer Entwurf, wird nichts überschrieben: Die Übung bietet den offline geschriebenen mit „Offline geschriebener Entwurf verfügbar · Laden“ an, daneben „Verwerfen“.

Erzählkurs, Übung 6 auf 390 px, offline neu geladen: Der Hinweis nennt die neue Regel, der Text im Feld ist noch da

So funktioniert es

  • Offline: saveAnswer schreibt jeden Entwurf zusätzlich nach LocalStorage. Je Bereich, Übung und Fingerprint gibt es einen Schlüssel (learn-offline:draft:v1:<bereich>:<übung>:<fingerprint>), mit der Grenze von 60 KB wie online. prepareDraft lädt ihn nach einem Neuladen ohne Netz wieder.
  • Nächster autorisierter Start: Die neue Mutation adoptDraft speichert einen Entwurf nur, wenn auf dem Server keiner liegt, und antwortet mit saved, same oder different. Die Entscheidung fällt in einer Transaktion, eine eigene Sync-Engine gibt es nicht (LRN-7). Bei saved und same wird die lokale Kopie gelöscht, bei different angeboten. Der Start wartet bis zu 3 s auf diese Übernahme. So zeigt eine sofort geöffnete Übung den Text schon an.
  • Abmelden löscht die lokalen Entwürfe. Sind noch welche nicht übernommen, fragt die Abmeldung vorher nach.
  • Neuer Hinweis im Offline-Modus, docs/CONVEX.md aktualisiert, Callout „So ist dieser Kurs gebaut“ in figuren-motivation angepasst.

Entscheidungen (Steven hat geschlafen, ich habe selbst entschieden)

  • Alle Übungsarten, nicht nur practice/explain/gap. Der Mechanismus hängt am gemeinsamen saveAnswer, deshalb kostet es nichts extra. Ausnahme ist wie bisher scenario, das keinen Entwurf hat.
  • Nur die Abmeldung löscht Offline-Entwürfe. Bei „Kein Zugriff“ und bei einer abgelaufenen Clerk-Sitzung bleiben sie liegen, anders als die Offline-Kopie des Lernstands. Sonst wäre ein Text aus dem Bus nach Ablauf der Sitzung verloren. Auf ein falsches Konto gelangen sie nicht, denn adoptDraft prüft den Eigentümer wie jeder Endpunkt.
  • Ein Angebot bleibt, bis du „Laden“ oder „Verwerfen“ wählst. Weitertippen im gespeicherten Entwurf löscht es nicht. Beide Buttons fragen vorher nach. „Laden“ löscht die lokale Kopie erst, wenn der Server den Entwurf bestätigt hat.
  • Nach einem Reset des Bereichs wird ein älterer Offline-Entwurf nur angeboten und nicht automatisch gespeichert. Er trägt dazu die Reset-Generation seiner Offline-Kopie.
  • Passt der Fingerprint nicht mehr (der Inhalt hat sich inzwischen geändert), bleibt der Entwurf ungenutzt auf dem Gerät. Gespeichert würde er ihn nur dort ablegen, wo keine Übung ihn anzeigt.
  • Notizen bleiben offline gesperrt. Ihr Ablauf (kein Fingerprint, eigenes Angebot „Auf einem anderen Gerät geändert“) passt nicht in denselben kleinen Mechanismus. Optional laut Issue.
  • Der Hinweistext ist kürzer als ein erster Entwurf, denn der hatte auf dem Handy die halbe Höhe belegt: „Offline-Modus, Lernstand vom …. Eingaben in Übungen bleiben auf diesem Gerät, bis du mit Netz startest. Häkchen, gelöste Übungen und Karten gelten nur bis zum Neuladen.“

Prüfungen

  • pnpm lint, pnpm typecheck, pnpm test (339 Tests, neu: LocalStorage-Funktionen, adoptDraft samt Autorisierung)
  • pnpm test:pwa:e2e 6/6, neuer Fall: offline starten, Prosa-Text schreiben, offline neu laden, Text noch da; wieder online „Erneut verbinden“ bei nicht erreichbarer Anmeldung, Text bleibt auf dem Gerät
  • pnpm test:convex:e2e 15/15, neuer Fall: fehlender Entwurf wird übernommen, ein anderer gespeicherter bleibt und wird angeboten, „Laden“ speichert, Entwurf von vor einem Reset wird nur angeboten, „Verwerfen“ löscht
  • pnpm test:e2e 59/59
  • Unabhängiges Review vor dem PR: kein Datenverlust im Normalbetrieb, sechs Randfälle gefunden und im zweiten Commit behoben (Reset-Generation, Fingerprint, Löschen erst nach Bestätigung, Wartezeit beim Start, Löschen nur bei unverändertem Text, Rückfrage bei „Laden“)

CI: Alle Jobs außer e2e sind grün (check, verify, convex). e2e scheitert an einem einzigen Test, „real content fits phone, tablet and desktop viewports“, und zwar auch auf unverändertem main: Lauf 39690603895 scheitert genauso (net::ERR_INSUFFICIENT_RESOURCES nach einigen hundert Seitenaufrufen). Am 20.10. war derselbe Stand von main grün. Lokal ist pnpm test:e2e grün (59/59). Ein Versuch, den Test robuster zu machen, half nicht und ist wieder zurückgenommen (7a87626, e72f331). Der Inhalt des Branches entspricht damit dem geprüften Stand. Weiter geht es in LRN-31.

Nicht geprüft: Auf dem echten Handy im Flugmodus mit echter Clerk-Sitzung. Das geht nur mit Stevens Konto. Vorschlag: Offline starten, im Erzählkurs Übung 6 etwas schreiben, neu laden, dann online starten und auf einem zweiten Gerät nachsehen.

Closes LRN-30

🤖 Generated with Claude Code

hernstev97 and others added 2 commits October 21, 2026 23:55
Offline reading mode now stores exercise drafts in LocalStorage, one key per
area, exercise and fingerprint (60 KB limit as online). The next authorized
start hands them to the new adoptDraft mutation, which saves a draft only
where none exists; a different saved draft stays and the exercise offers the
offline one ("Offline geschriebener Entwurf verfügbar · Laden"/"Verwerfen").
Signing out deletes the local drafts and asks first if some are not adopted.

Updates the offline notice, docs/CONVEX.md and the callout in the narrative
course. Notes stay unavailable offline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Offline drafts carry the reset generation of their offline copy; after a
  reset they are offered instead of coming back on their own.
- Drafts whose fingerprint no longer matches the exercise stay on the device
  instead of being saved where no exercise shows them.
- "Laden" asks first and forgets the local copy only once the server has
  confirmed the draft; a held draft no longer overwrites it.
- A local copy is removed only while it still holds the adopted text.
- The start waits up to three seconds for adoption, so an exercise opened
  right away already shows the adopted text.
- Shorter offline notice; it took half a phone screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9fe0c14f-ec0e-4d99-b642-48428a9eff70
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

hernstev97 and others added 2 commits October 22, 2026 00:31
Some 300 dev-server navigations in one tab ran the CI browser out of
resources (net::ERR_INSUFFICIENT_RESOURCES, then a page module failed to
load); the nightly run on main failed the same way. Each width now gets a
fresh tab, and a page that did not load is tried once more. The test
checks layout, not loading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fresh tab and retry did not help on CI: the runner was short of
resources for the PostgreSQL, pytest and VM tests in the same run too, and
the retries only used up the test's time budget. The flakiness exists on
main as well and gets its own issue instead of riding along with LRN-30.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant