Skip to content

Under the Hood.de

Doug Blank edited this page Sep 22, 2026 · 2 revisions

🌐 English · Français

Unter der Haube

Implementierungsnotizen, die nicht in den erzählerischen Bogen von Architektur passen — Details, die man kennen sollte, wenn etwas zu debuggen ist, geprüft wird, was die App wo speichert, oder man sich fragt, warum sie sich auf eine bestimmte Weise verhält.

Browser-Speicher: sessionStorage vs. localStorage

Beide sind auf Browser-Profil + Ursprung eingegrenzt, nicht darauf, wer angemeldet ist. Meldet sich Benutzer A ab und Benutzer B im selben Browser an (derselbe Rechner, dasselbe Browser-Profil), startet der Tab von Benutzer B mit dem, was dieser Ursprung an Speicher bereits enthielt — sofern die App es nicht ausdrücklich leert oder mit einem Namensraum versieht. Gramps Connect teilt seinen clientseitigen Speicher genau entlang dieser Linie auf die beiden APIs auf:

sessionStorage (app/src/auth/auth.ts) hält Zugriffstoken, Refresh-Token und Benutzername. logout() leert ausdrücklich alle drei, und sessionStorage selbst übersteht einen geschlossenen Tab ohnehin nicht — eine frische Anmeldung startet also immer sauber, und hier läuft nichts zwischen Benutzern durch.

localStorage hält Oberflächen-Einstellungen, und — anders als die Auth-Token — nichts davon wird bei der Abmeldung gelöscht:

Schlüssel Geltungsbereich Datei
gramps-connect_home_person pro Stammbaum (geschlüsselt nach getTreeId()) app/src/store/homePersonPreference.ts
gramps-connect_column_widths global app/src/store/columnWidths.ts
gramps-connect_tree_manual_expand global app/src/store/treeExpandPreference.ts
gramps-connect_aside_widths global app/src/App.tsx
gramps-connect:map-viewport global app/src/components/visuals/MapCanvas.tsx
gramps-connect_browser_notifications_enabled global app/src/store/browserNotifications.ts

Keiner davon ist nach Benutzer mit einem Namensraum versehen, und nur home_person nach Stammbaum. Praktischer Effekt: auf einem geteilten Rechner erbt die nächste Person, die sich anmeldet (selbst in einem anderen Stammbaum, bei den globalen Schlüsseln), die Spaltenbreiten, Bereichsgrößen, den Kartenausschnitt und die Benachrichtigungs- Einstellung der vorherigen Person — und, falls es derselbe Stammbaum ist, auch deren Ausgangsperson. Nichts Sensibles wird dabei offengelegt (hier liegen keine Stammbaumdaten oder Zugangsdaten, nur Anzeigeeinstellungen), aber es ist ein echtes Verhalten, das jemandem auffallen und wonach gefragt werden könnte.

Wird jemals eine Trennung pro Benutzer gewünscht, ist die Lösung dasselbe Muster, das homePersonPreference.ts bereits für die Abgrenzung pro Stammbaum verwendet — das gespeicherte Objekt nach Benutzer-ID (oder Benutzername) schlüsseln, statt nach oder zusätzlich zu Stammbaum-ID.

Verwandtes/Detail-Bereich: sofortiges Neuzeichnen beim erneuten Besuch

Der Abruf pro Datensatz (fetchObjectExtended, app/src/store/objectDetail.ts) des oberen rechten (und unteren „Referenz-Detail“-)Bereichs wird von einem kleinen, speicherinternen Stale-while-revalidate-Cache unterstützt, geschlüsselt nach Ansicht + Handle und auf 50 Einträge begrenzt (LRU-verdrängt). Von einem Datensatz wegzunavigieren und zu ihm zurückzukehren, zeichnet den zuletzt bekannten Detailstand sofort neu, statt einen Ladekreisel zu zeigen — die zugrunde liegenden Listenansichten (DataTable) haben das bereits über ihren dauerhaften ViewStore/SQLite-Cache getan (siehe Architektur); das schließt dieselbe Lücke für den Detailbereich, der vorher bei jedem einzelnen Mount von Grund auf neu abgerufen hat.

Es ist kein echter Cache im Sinne von „den Abruf überspringen“: jeder Mount ruft weiterhin fetchObjectExtended genau wie vorher auf und überschreibt den Cache-Eintrag mit dem frischen Ergebnis. Wie die localStorage-Schlüssel oben ist es ein modulweiter Cache — nicht bei Abmeldung oder Stammbaum-Wechsel geleert.

Der Bereich ruft außerdem erneut ab, wann immer Live-Synchronisierung irgendeine Stammbaum-Änderung meldet, nicht nur eine Änderung an der eigenen (Ansicht, Handle). Der normale Weg der Live-Synchronisierung erhöht nur die Revision eines ViewStore für eine Änderung, die zu dessen eigener Tabelle/Handle passt, was für Listenansichten präzise, hier aber nicht ausreichend ist: eine Bearbeitung an einem anderen, in die aufgelösten Referenzen dieses Datensatzes eingebetteten Datensatz (der Text einer Notiz, das über extend=all/Backlinks hereingezogene Datum eines Ereignisses) würde sonst keinen erneuten Abruf auslösen und bliebe veraltet, bis der Bereich neu gemountet wird. Bei jeder Stammbaum-Änderung erneut abzurufen, tauscht etwas zusätzlichen Abfrageverkehr gegen Korrektheit, statt neu herzuleiten, welche Handles eingebettet sind — diese Form variiert je nach Objekttyp (siehe Datenmodell und Bearbeitung).

Clone this wiki locally