fix(documents): persist offline document edits by sending relativePath - #34
Merged
Conversation
Document edits and creates route through the offline sync path (default on) and are POSTed to /api/documents/sync. The backend gates every document create/update op on a required, folder-unique `relativePath` (`if (!id || !relativePath) continue;`) yet always returns 200, so the client silently believed the push succeeded: it cleared the outbox and marked the doc synced while the server dropped the op. The edit lived only in the optimistic cache until the next full pull merged the untouched server row back over it — so an edited doc reverted to its created-date state and never reached the server. The client `SyncOpData` already had a `relativePath` field; it was just never populated. Populate it at all three document op sites: - Document: decode `relativePath` from the sync response so pulled docs carry their real server path. - AppDataStore.updateDocumentOffline: echo the existing doc's path, falling back to "<id>.md" for rows cached before the field existed. - AppDataStore.createDocumentOffline: generate a collision-safe "<id>.md" (UUID basename can't violate @@unique([folderId, relativePath])). - DocumentSyncConflict.makeConflictCopy: give conflict copies a path too — they would otherwise fail to push for the same reason. Add tests covering the pushed create/update/conflict ops and the new model field, and log the backend defect (should not require relativePath on update; should fall back on create; 200-on-drop blind spot) as ask A7 in the-gaps.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ATYNi3UKZpQH28AH6tCTup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Editing an existing document (or creating one) appeared to save on-device but silently never reached the server, and the doc later reverted to its created-date state. Root cause: the offline sync path (on by default) POSTs ops to
/api/documents/sync, whose backend handler drops any document create/update op lacking a required, folder-uniquerelativePath— while still returning200. The client never sentrelativePath, so every edit was silently discarded; the optimistic edit lived only in local cache until the next full pull merged the untouched server row back over it.The client's
SyncOpDataalready had arelativePathfield — it was simply never populated. This PR populates it everywhere a document create/update op is built.What's included
relativePathonDocumentfrom the sync response; populate it on every offline sync op —updateDocumentOfflineechoes the doc's existing path (falls back to"<id>.md"for pre-field cached rows),createDocumentOfflinegenerates a collision-safe"<id>.md", andDocumentSyncConflict.makeConflictCopygives conflict copies a path (they'd otherwise fail to push too). (commit 9990a0d)relativePath, that updates echo the server path, and thatDocumentdecodesrelativePath. (commit 9990a0d)the-gaps.md(server should not requirerelativePathon update, should fall back on create likePOST /api/documents, and the200-on-silent-drop blind spot). (commit 9990a0d)Testing
xcodebuild build(iPhone 16 simulator) — BUILD SUCCEEDEDxcodebuild test -parallel-testing-enabled NO -skip-testing:InterlinedListTests/E2EReadOnlyTests— 805 tests, 0 failuresCaveats / follow-ups
il-sync, web) and to close the silent-failure blind spot.syncCyclepulls-then-pushes and never re-pulls after a push, so a future silent per-op server rejection would still go undetected.🤖 Generated with Claude Code