Replace separate JWT_EXPIRY_MAGIC_LINK (365d) and JWT_EXPIRY_PASSKEY (7d)
constants with a single JWT_EXPIRY (365d). The auth method only matters
during login — once a JWT is issued, it represents a verified session
regardless of how the user authenticated.
Operations with timestamps beyond maxClockDriftMs (60s) were being
permanently rejected, causing silent data loss when a client's clock
was slightly ahead.
Now these timestamps are clamped to now + maxClockDriftMs and accepted.
A TIMESTAMP_CLAMPED audit log is recorded for debugging.
- Add clamping logic in SyncService.processOperation()
- Remove future timestamp rejection from ValidationService
- Add comprehensive tests verifying clamped values and boundaries
- Update integration test to expect acceptance
Tombstones were used for tracking deleted entities but are no longer
needed with the operation log architecture. This removes:
- Tombstone table from Prisma schema
- Tombstone-related methods from SyncService
- Tombstone mocks and tests from all test files
- Database migration to drop tombstones table
The operation log now handles deletions through DEL operations,
making the separate tombstone tracking redundant.
Code review fixes:
- Fix download memory limit to correctly return success: false
- Add logging when vector clock entries are stripped during sanitization
- Add integration test for partial batch upload recovery (network failure)
parentOpId support for conflict resolution:
- Add parentOpId field to Operation type for conflict chain tracking
- Add parent_op_id column to operations table with migration
- Update sync routes schema to accept parentOpId
- Store and retrieve parentOpId in sync service
Also adds PLUGIN_USER_DATA and PLUGIN_METADATA to allowed entity types.
Remove the acknowledgeOps mechanism and simplify server-side garbage
collection to pure time-based cleanup (delete ops older than 50 days).
Client-side changes:
- Remove acknowledgeOps from OperationSyncCapable interface
- Remove acknowledgeOps implementation from super-sync.ts
- Remove ACK call from download service (with explanatory comment)
- Remove ACK-related tests and mock server methods
Server-side changes:
- Remove ACK endpoint (POST /api/sync/devices/:clientId/ack)
- Remove updateDeviceAck and getMinAckedSeq from sync service
- Simplify deleteOldSyncedOpsForAllUsers to time-based only
- Update status endpoint (pendingOps now always 0)
Documentation updates:
- Update architecture diagrams to remove ACK references
- Update cleanup process to show 50-day time-based cleanup
This simplification was needed because fresh clients couldn't ACK
(device registration only happens on upload), causing 403 errors.
Time-based cleanup at 50 days is simpler and equally effective.
Also fixes DIAGNOSTIC test to expect server-side conflict detection
(test was written before server conflict detection was added).
Add two integration tests for gzip-compressed snapshot uploads:
- Verify compressed snapshots work through full route handler and sync
- Verify backwards compatibility with uncompressed snapshots
Tests simulate real multi-client scenarios where one client uploads
a compressed snapshot and another client retrieves it.