From 9c04b8652ca6d5d663febf5c152b9fdeb7d63443 Mon Sep 17 00:00:00 2001 From: beo3000 Date: Sat, 21 Feb 2026 15:49:52 +0100 Subject: [PATCH] fix bypass in production --- .claude/settings.local.json | 3 ++- ka-note/.dockerignore | 3 +++ ka-note/.gitignore | 2 ++ ka-note/VERSION | 2 +- ka-note/client/src/lib/sync/syncService.ts | 10 ++++---- ka-note/server/ka-note.db-shm | Bin 32768 -> 32768 bytes roadmap.md | 27 +++++++++++++++++++++ 7 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 ka-note/.dockerignore create mode 100644 roadmap.md diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 72e3c4e..d0e4bd8 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -16,7 +16,8 @@ "Bash(python3:*)", "Bash(echo:*)", "Bash(git -C ka-note check-ignore .env)", - "Bash(git -C . check-ignore ka-note/.env)" + "Bash(git -C . check-ignore ka-note/.env)", + "Bash(git check-ignore:*)" ] } } diff --git a/ka-note/.dockerignore b/ka-note/.dockerignore new file mode 100644 index 0000000..b5345db --- /dev/null +++ b/ka-note/.dockerignore @@ -0,0 +1,3 @@ +**/.env.local +**/.env.*.local +**/node_modules diff --git a/ka-note/.gitignore b/ka-note/.gitignore index 2e9e36f..2af6055 100644 --- a/ka-note/.gitignore +++ b/ka-note/.gitignore @@ -3,6 +3,8 @@ dist/ .svelte-kit/ build/ .env +.env.local +.env.*.local *.db *.sqlite .DS_Store diff --git a/ka-note/VERSION b/ka-note/VERSION index 1fe90ca..2ac8be3 100644 --- a/ka-note/VERSION +++ b/ka-note/VERSION @@ -1 +1 @@ -1.0.9 \ No newline at end of file +1.0.11 \ No newline at end of file diff --git a/ka-note/client/src/lib/sync/syncService.ts b/ka-note/client/src/lib/sync/syncService.ts index 2890642..b07c8a4 100644 --- a/ka-note/client/src/lib/sync/syncService.ts +++ b/ka-note/client/src/lib/sync/syncService.ts @@ -42,25 +42,25 @@ async function pullAndMerge(since: Date | null): Promise { await db.transaction('rw', [db.contexts, db.topics, db.historyEntries, db.ratings], async () => { for (const serverCtx of contexts) { const local = await db.contexts.get(serverCtx.id); - if (!local || serverCtx.version >= local.version) { + if (!local || serverCtx.version > local.version) { await db.contexts.put(serverCtx); } } for (const serverTopic of topics) { const local = await db.topics.get(serverTopic.id); - if (!local || serverTopic.version >= local.version) { + if (!local || serverTopic.version > local.version) { await db.topics.put(serverTopic); } } for (const serverHe of historyEntries) { const local = await db.historyEntries.get(serverHe.id); - if (!local || serverHe.version >= local.version) { + if (!local || serverHe.version > local.version) { await db.historyEntries.put(serverHe); } } for (const serverRating of ratings) { const local = await db.ratings.get(serverRating.id); - if (!local || serverRating.version >= local.version) { + if (!local || serverRating.version > local.version) { await db.ratings.put(serverRating); } } @@ -95,8 +95,8 @@ export async function sync(): Promise { async function doSync(since: Date | null): Promise { syncStatus.set('syncing'); try { - const serverTimestamp = await pullAndMerge(since); await pushAll(); + const serverTimestamp = await pullAndMerge(since); const syncTime = new Date(serverTimestamp); lastSyncAt.set(syncTime); localStorage.setItem('lastSyncAt', syncTime.toISOString()); diff --git a/ka-note/server/ka-note.db-shm b/ka-note/server/ka-note.db-shm index d830deb3d3d8d21524efdbd79b4bbc96603f8bc5..424ea2a132a422b783c942db369c82855ccae5fe 100644 GIT binary patch delta 837 zcmchRTTqN)7{|Z=e-ACKltuAXOOndQI<7ODfpZE9tp2zK`+s$n;!8EC}AW4xf zN|HI$I8bP_7mR%S@ z6Jr?11P-Ew!#JAbIfc_Wi}SdMOSzJ3JN$-R=F>@+`bvOOpPy`uI*6k9MW zFYy*l9Z+qdRX&2_IF0it!!_K(T|7V?p5hf6@Sz=2YBncnv|q7Uz05~ZwZ&=q28lX$ mWq0;uAI5V4lbOchv~dFM%w!hlGl$E#itE&=0xFeTQ}Gjhl<#){ delta 316 zcmZo@U}|V!s+V}A%K!o@K+MR%Ag~5VNCVkLE<7JIHp*R_*Vb#!GqvEs;!Af*AH26N zBvn1gY!CpM`yUBFL>ZVFzATPW&^G_Op~uT8ceeVv={*)vUbM+ diff --git a/roadmap.md b/roadmap.md new file mode 100644 index 0000000..fc8823e --- /dev/null +++ b/roadmap.md @@ -0,0 +1,27 @@ +# Ka-Note Roadmap + +## [LOW] Sync: Soft-delete Restrisiko bei neuem Gerät / DB-Reset + +**Problem** +Wenn ein Gerät noch nie gepusht hat (neues Gerät oder IndexedDB gelöscht), ist `!local = true` für alle Pull-Einträge. Der Pull überschreibt dann keine lokale Version, sondern legt neu an — auch wenn der Eintrag auf einem anderen Gerät bereits gelöscht wurde. Das gelöschte Item erscheint wieder, bis das löschende Gerät seinen Push durchführt. + +**Bereits gefixt** +- Push läuft jetzt vor Pull (`doSync`) +- Merge-Bedingung auf `>` statt `>=` (lokale Änderung gewinnt bei Versionsgleichstand) + +**Restrisiko** +Szenario: Gerät A löscht Item (version N+1), hat aber noch nie gepusht. Gerät B macht Full-Sync: Pull bringt Server-Version N (nicht gelöscht), `!local` → wird eingespielt. Gerät B sieht das Item als vorhanden. + +**Lösungsoptionen** + +1. **Serverseitig: `deletedAt`-Items aus Pull-Response ausfiltern** + Server gibt bei Pull keine soft-deleted Items zurück. Gerät B bekommt das Item gar nicht erst. Problem: Wenn Gerät B das Item schon lokal hat (z.B. eigene ältere Version), wird es nie als gelöscht markiert. + +2. **Tombstone-Tabelle** + Separate Tabelle `deletions(entityId, deletedAt, version)` — wird immer mitübertragen. Client wertet Tombstones aus und löscht lokale Items explizit. Robusteste Lösung, erhöht aber Komplexität. + +3. **Server filtert + Client löscht lokale Einträge die der Server nicht mehr liefert** + Server sendet nur aktive Items. Client vergleicht lokale IDs mit Pull-Response und markiert fehlende als `deletedAt`. Einfacher als Tombstones, aber fehleranfällig bei partiellen Pulls (since-Filter). + +**Empfehlung** +Option 2 (Tombstones) für korrekte Multi-Gerät-Unterstützung. Option 3 als pragmatischer Zwischenschritt wenn Full-Sync (since=null) garantiert ist.