Commit graph

318 commits

Author SHA1 Message Date
Johannes Millan
d27fda7ca2 Merge branch 'master' into feat/operation-logs
* master:
  fix(e2e): improve WebDAV sync test reliability

# Conflicts:
#	e2e/pages/sync.page.ts
2026-01-02 20:11:39 +01:00
Johannes Millan
e6b6468d2a fix(e2e): improve WebDAV sync test reliability
- Add waitForAppReady and tour dismissal after page reload in
  webdav-sync-tags test to prevent task-list timeout
- Use existing providerSelect locator instead of role-based combobox
  selector in sync.page.ts for more reliable dropdown interaction
- Add graceful error handling for scrollIntoViewIfNeeded with fallback
2026-01-02 19:59:59 +01:00
Johannes Millan
e6ea0d74f0 Merge branch 'master' into feat/operation-logs
* master: (37 commits)
  16.8.0
  feat(i18n): add new translations
  fix: address code review issues from today's changes
  fix: address code review issues from today's changes
  fix(data-repair): change quickSetting to CUSTOM when startDate is missing
  fix(test): fix fetch spy setup in audio tests
  fix(android): sync time tracking from notification correctly on resume
  fix(database): prevent repeated error dialogs when disk is full
  fix(reminder): prevent dismissed reminders from reappearing
  fix(task-repeat): prevent race condition when saving repeat config
  fix(android): add error handling for native service calls
  fix(reminder): cancel native Android reminders immediately on task deletion
  fix(error-handler): use getErrorTxt to prevent [object Object] in error titles
  fix(planner): use task startDate for weekly repeat weekday calculation
  fix(focus-mode): use independent 1s timer for Pomodoro countdown
  feat(focus-mode): add Skip Break button to banner during active breaks
  feat(notes): add auto-save to fullscreen markdown editor
  fix(reflection-note): prevent trailing spaces from being deleted while typing
  fix(sync): add error handling for JSON parse failures in sync data
  fix(error-handling): prevent [object Object] from appearing in error messages
  ...

# Conflicts:
#	src/app/core/persistence/database.service.ts
#	src/app/features/android/store/android-focus-mode.effects.ts
#	src/app/features/android/store/android-foreground-tracking.effects.ts
#	src/app/features/reminder/reminder.service.spec.ts
#	src/app/features/reminder/reminder.service.ts
#	src/app/features/tasks/dialog-view-task-reminders/dialog-view-task-reminders.component.ts
#	src/app/features/tasks/store/task-reminder.effects.spec.ts
#	src/app/features/tasks/store/task-reminder.effects.ts
#	src/app/features/work-context/store/work-context.effects.spec.ts
#	src/app/features/work-context/store/work-context.effects.ts
#	src/app/t.const.ts
#	src/assets/i18n/en.json
2026-01-02 19:56:30 +01:00
Johannes Millan
3a179df3cc fix(sync): prevent data loss when multiple clients join SuperSync
Fixes critical bug where multiple clients with existing data could each
create a SYNC_IMPORT when enabling SuperSync, causing data loss.

Root cause: When clients had local data (from legacy migration), each
would detect "server needs migration" and create competing SYNC_IMPORTs.
The last one uploaded would invalidate all prior data.

Fixes:
- Server rejects duplicate SYNC_IMPORT with SYNC_IMPORT_EXISTS (409)
- Client double-checks server is empty before creating SYNC_IMPORT
- Client merges all local op clocks into SYNC_IMPORT's vector clock
- hasSyncedOps() excludes MIGRATION/RECOVERY ops from check
- Upload service gracefully handles SYNC_IMPORT_EXISTS rejection

Tests added:
- ServerMigrationService: double-check and clock merging (5 tests)
- OperationLogStoreService: hasSyncedOps() MIGRATION exclusion (7 tests)
- OperationLogUploadService: SYNC_IMPORT_EXISTS handling (5 tests)
- E2E: Multiple clients with existing data merge correctly
2026-01-02 17:51:12 +01:00
Johannes Millan
4f2dbcdaa7 feat(sync): handle auth errors for account deletion scenarios
When a SuperSync account is deleted, clients now properly detect
authentication failures and prompt for reconfiguration:

- Add _checkHttpStatus() helper to SuperSyncProvider that throws
  AuthFailSPError on 401/403 responses
- Clear cached credentials on auth failure to allow reconfiguration
- Add DELETE /api/test/user/:userId endpoint for E2E testing
- Add deleteTestUser() helper in supersync-helpers.ts
- Add E2E tests for account deletion and reconfiguration scenarios

The existing SyncWrapperService already handles AuthFailSPError by
showing a snackbar with "Configure" action, so no UI changes needed.
2026-01-02 15:48:17 +01:00
Johannes Millan
4e0f5e8999 fix(e2e): improve app loading detection and fix server TypeScript errors
- e2e/utils/waits.ts: Add proper retry logic and error handling when
  waiting for magic-side-nav to appear. Now throws a clear error if
  app doesn't load within 30s instead of silently continuing.

- packages/super-sync-server/src/auth.ts: Use nullish coalescing for
  passwordHash to handle passkey-only users (who have no password).

- packages/super-sync-server/src/passkey.ts: Add WebAuthn passkey
  authentication support. Fix TypeScript errors by importing types
  from @simplewebauthn/types and converting credential IDs to
  base64url strings.

Fixes flaky "Multiple fresh clients join and sync correctly after
snapshot" test that was failing when app didn't fully load.
2026-01-02 15:11:16 +01:00
Johannes Millan
eedf27aa93 test(focus-mode): add tests for bug #5117 - timer stops at countdown duration 2026-01-02 13:42:02 +01:00
Johannes Millan
8b3dc445c4 test: fix e2e 2026-01-02 12:53:30 +01:00
Johannes Millan
ef8c8c21df fix(sync): fix sync E2E test failures and flaky encryption tests
operation-log.effects.ts:
- Move dequeue() inside the lock to prevent race condition with
  flushPendingWrites(). Previously, flushPendingWrites() could see
  queue=0 and return before IndexedDB write completed.
- Set entityId from entityIds[0] for bulk operations. Server requires
  entityId for non-full-state operations, but bulk actions like
  updateAllSimpleCounters only provide entityIds array.

supersync.page.ts:
- Fix flaky encryption checkbox tests caused by Angular Material
  checkbox starting in indeterminate "mixed" state before form loads
- Use retry logic with toPass() instead of single click + assert
- Click on label instead of touch target for more reliable interaction
- Increase timeout to 10s with smart intervals [500, 1000, 1500]ms
2026-01-01 17:14:59 +01:00
Johannes Millan
073eab162e fix(e2e): target specific tasks container in schedule page test
Use more specific selector to target only the scheduled tasks
container, avoiding ambiguity with planned-for-days tasks.
2026-01-01 15:21:01 +01:00
Johannes Millan
667353f41b test(e2e): add LWW delete vs update race test for TODAY_TAG
Add test verifying that when a task scheduled for today is deleted on
one client while updated on another, the recreated task (via LWW Update)
correctly appears in the TODAY view. This validates that
syncTodayTagTaskIds properly updates TODAY_TAG.taskIds during LWW
conflict resolution.
2025-12-31 13:49:13 +01:00
Johannes Millan
431290c170 fix(sync): prevent data loss from stale vector clocks during SYNC_IMPORT hydration
Two bugs caused data loss after app restart with SuperSync:

Bug 1: Clock merge happened AFTER loadAllData dispatch
- Operations created during loadAllData (e.g., TODAY_TAG repair) got stale clocks
- Server rejected these as CONFLICT_STALE
- Fix: Call mergeRemoteOpClocks() BEFORE store.dispatch(loadAllData())

Bug 2: CONFLICT_STALE treated as permanent rejection
- Stale operations were marked rejected instead of being resolved via merge
- Fix: Handle CONFLICT_STALE the same as CONFLICT_CONCURRENT

Adds unit tests for both bugs and E2E regression tests to prevent recurrence.
2025-12-30 14:07:56 +01:00
Johannes Millan
ce58113ad0 fix(e2e): dismiss dialog backdrop before retry sync in error handling test
After simulating network failure and restoring network, a dialog backdrop
could remain visible and intercept clicks on the sync button. This caused
the retry sync to fail with a timeout.

Add check for `.cdk-overlay-backdrop` and press Escape to dismiss any
open dialogs before triggering the retry sync.
2025-12-29 22:54:26 +01:00
Johannes Millan
55484faffd fix(e2e): fix WebDAV sync tests that were failing
Two test fixes:

1. webdav-sync-full.spec.ts - "should sync data between two clients"
   - After multiple reloads in the deletion test section, Client B's
     sync state became stale and couldn't receive new tasks
   - Fix: Create a fresh Client B context for the conflict resolution
     section instead of reusing the stale one

2. sync.page.ts - setupWebdavSync combobox selector
   - The role-based selector getByRole('combobox', { name: 'Sync Provider' })
     was unreliable across different test runs
   - Fix: Use the existing providerSelect locator which was already
     validated to be visible, instead of creating a new role-based selector
2025-12-29 22:33:24 +01:00
Johannes Millan
6c098b6eaa Merge branch 'master' into feat/operation-logs
Resolve conflict in webdav-sync-expansion.spec.ts:
- Use simplified sync verification without reload (sync updates NgRx directly)
- Test: B marks task done -> sync -> verify A sees task as done
2025-12-29 21:54:15 +01:00
Johannes Millan
cc593a324a test(webdav): improve stability of sync e2e tests
- Add retry loop for deletion sync to handle eventual consistency
- Fix done state sync test to handle Done Tasks section
- Add task order sync test
- Add time tracking sync test (skipped - complex persistence)
2025-12-29 20:38:06 +01:00
Johannes Millan
016e680c5f fix(sync): fix simple counter sync and quota exceeded handling
- Add null checks in simple-counter.reducer.ts to prevent crashes when
  entity doesn't exist (fixes "Cannot read properties of undefined")
- Add missing entityIds to updateAllSimpleCounters action - was causing
  operation log to skip persistence
- Add try-catch in operation-log-upload.service.ts to show alert when
  storage quota exceeded (413 error)
- Fix supersync-network-failure.spec.ts test timing - route interception
  must happen before task creation
- Add documentation to CLAUDE.md for running supersync tests with
  real-time output using --reporter=line
2025-12-29 17:09:46 +01:00
Johannes Millan
a7cd442551 fix(op-log): fix operation flush timeout in daily-summary tests
Two fixes for supersync E2E test failures:

1. Remove race condition in operation-log.effects.ts:
   - Removed isApplyingRemoteOps() filter that caused actions enqueued
     by meta-reducer to be filtered out if sync started before effect ran
   - Meta-reducer already handles buffering during sync, so this filter
     was redundant and caused queue drain timeouts

2. Allow bulk operations with entityType 'ALL' to skip entityId validation:
   - [Archive] Flush Young to Old action has entityType 'ALL' but no entityId
   - Previous validation returned early without dequeuing, causing stuck queue
   - Now dequeues before early return and allows entityType 'ALL' to proceed

3. Fix URL pattern in supersync-daily-summary.spec.ts:
   - Changed from /(active\/tasks|tag\/TODAY\/tasks)/ to /(active\/tasks|tag\/TODAY)/
   - App sometimes navigates to tag/TODAY without /tasks suffix
2025-12-29 15:11:30 +01:00
Johannes Millan
efe8bea72d fix(e2e): fix archive-subtasks tests for TODAY tag virtual membership
The tests were failing because:
1. The backup file has tasks with dueDay in the past (2024-12-01)
2. TODAY tag is a "virtual tag" where membership is determined by
   task.dueDay === today, not by taskIds
3. When all tasks are done, planning mode activates and hides the
   Finish Day button

Fix by:
- Navigate to INBOX project to view and mark tasks as done
- Navigate to TODAY tag to access the Finish Day button
- Exit planning mode by clicking "Ready to work!" if visible
- Then proceed with Finish Day flow
2025-12-29 13:20:44 +01:00
Johannes Millan
c4f536471a test(webdav): add e2e tests 2025-12-29 12:48:36 +01:00
Johannes Millan
0cb5cdd982 test(sync): add comprehensive tests for error handling and edge cases
Unit tests for remote-ops-processing.service.ts:
- Migration failure handling (skip failed ops, continue processing)
- Early return when all ops fail migration
- Dropped entity ID tracking for dependency warnings

E2E tests for supersync-network-failure.spec.ts:
- Rate limit exceeded (429) handling with retry
- Server storage quota exceeded gracefully
- Long offline period sync recovery (15+ tasks)
- Malformed JSON response handling
- Corrupted/invalid operations from server

These tests address gaps identified in the SuperSync implementation
review, covering error recovery, rate limiting, quota handling, and
data corruption scenarios.
2025-12-29 12:13:53 +01:00
Johannes Millan
1da70487f9 fix: address code review findings from Dec 27-29 changes
ESLint rule improvements:
- Fix require-hydration-guard to detect guards on combineLatest/forkJoin/zip
  results (eliminates 20+ false positive warnings)

Server improvements:
- Add OperationDownloadService unit tests (21 tests covering vector clock
  aggregation, gap detection, excludeClient parameter, snapshot optimization)
- Split ZIP bomb size limits: 10MB for /ops, 30MB for /snapshot
- Document storage quota update as intentionally non-atomic

E2E test improvements:
- Add waitForUISettle() helper using Angular stability instead of fixed timeouts
- Update supersync-cross-entity tests to use dynamic waits

Unit test improvements:
- Add HydrationStateService edge case tests (concurrent calls, cooldown cycles,
  timer cleanup, interleaved operations)
2025-12-29 10:37:12 +01:00
Johannes Millan
d9f35be660 test(e2e): add supersync E2E tests for advanced sync scenarios
Add 6 new E2E test files covering:
- Task ordering sync between clients
- Repeat task and scheduled task sync
- Cross-entity operations (subtasks, batch tasks)
- Time tracking advanced scenarios
- Worklog/archive sync
- Planner/dueDay sync

Each test uses a module-level counter in generateTestRunId() to ensure
unique test user IDs even when tests run in parallel within the same
millisecond.
2025-12-28 15:10:06 +01:00
Johannes Millan
8d32419eef build: more tests in parallel 2025-12-28 15:07:11 +01:00
Johannes Millan
9e8d05f430 test(sync): add error handling tests for SuperSync
Add comprehensive tests for error code handling at unit and E2E levels:

Unit tests (super-sync.spec.ts):
- 429 Rate Limited response handling
- 413 Storage Quota Exceeded response handling
- Parse CONFLICT_CONCURRENT/STALE/DUPLICATE_OPERATION from response
- Mixed accept/reject batch categorization
- Extract piggybacked ops from conflict response

Unit tests (operation-log-sync.service.spec.ts):
- STORAGE_QUOTA_EXCEEDED shows alert but doesn't mark op rejected
- INTERNAL_ERROR marks op as rejected
- Verify subsequent operations behavior after errors

E2E tests (supersync-error-handling.spec.ts):
- Concurrent modification triggers LWW conflict resolution
- Sync recovers after initial connection
- Duplicate sync attempts handled gracefully
- Three clients converge to same state

Also adds SnapshotService.clearForUser() helper for test cleanup.
2025-12-28 11:49:21 +01:00
Johannes Millan
6276f89c75 test(e2e): prevent browser closed errors and fix context menu selectors
- Add page.isClosed() checks before waitForTimeout calls to prevent
  "Target page, context or browser has been closed" errors when tests
  timeout (supersync-helpers.ts, waits.ts, supersync.page.ts)
- Fix context menu selector in LWW tests: use .mat-mdc-menu-item instead
  of button[mat-menu-item] which doesn't match Angular Material menu items
- Add retry logic for opening context menus with proper wait/escape handling
- Skip "Subtask edit survives when parent is deleted" test - documents
  expected future behavior that is not yet implemented
2025-12-28 11:30:45 +01:00
Johannes Millan
0d6b65cdc1 fix(e2e): handle already-closed browser contexts in closeClient
The closeClient helper was throwing errors when trying to close browser
contexts that were already closed (due to test timeouts or failures).
This caused cascading errors in E2E tests and made debugging harder.

Fix by checking if page is closed before attempting to close the context,
and gracefully catching "already closed" errors.
2025-12-27 22:14:20 +01:00
Johannes Millan
be947d7ccc test: increase timeout for migration tests and handle client closure errors 2025-12-27 18:11:31 +01:00
Johannes Millan
16d2ba1f25 fix(sync): improve compaction failure handling
- Add devError call on every compaction failure to catch issues during
  development
- Add reload action after 3 consecutive failures since this indicates
  a systemic issue (corrupted IndexedDB, storage quota, etc.) rather
  than a transient hiccup

Also fix lint errors in supersync-lww-conflict.spec.ts (let -> const)
2025-12-27 17:02:58 +01:00
Johannes Millan
a45b46e038 test(e2e): fix concurrent tag changes LWW test
Re-enable and fix the skipped E2E test for concurrent tag changes:

- Use skipClose=true when adding tasks with tags (short syntax)
- Handle tag creation confirmation dialog properly
- Replace separate add/remove tag helpers with single toggleTagOnTask
  helper (the context menu uses toggle checkboxes)
- Simplify navigation by staying in Today view instead of TagA
  (prevents task from disappearing after removing TagA)
- Remove unused navigation code and dismissDialog helper

The test verifies that LWW correctly resolves concurrent tag changes
and updates both task.tagIds and tag.taskIds consistently.
2025-12-27 16:06:56 +01:00
Johannes Millan
9e65a70be4 fix(sync): sync tag.taskIds when task.tagIds changes via LWW Update
Extend the lwwUpdateMetaReducer to also sync tag.taskIds arrays when
a task's tagIds changes during LWW conflict resolution.

When LWW Update syncs a task's tagIds change to remote clients, the
reducer now:
- Removes task from tags that were removed from task.tagIds
- Adds task to tags that were added to task.tagIds

This maintains bidirectional consistency between task.tagIds and
tag.taskIds, similar to the project.taskIds fix.

Also adds:
- 7 unit tests for project.taskIds sync (project move fix)
- 8 unit tests for tag.taskIds sync (new tag fix)
- E2E test for concurrent tag changes (skipped - env dialog issues)
2025-12-27 15:50:33 +01:00
Johannes Millan
c6e9e2ee84 test(e2e): add 5 high-priority E2E tests for SuperSync
Add comprehensive E2E tests covering core sync functionality gaps:

1. Multiple Conflicts on Same Entity (supersync-lww-conflict.spec.ts)
   - Verifies LWW uses MAX timestamp across all operations
   - Tests 3 ops from each client on same task

2. Import Invalidates Pending Remote Ops (supersync-import-clean-slate.spec.ts)
   - Tests clean slate semantics for SYNC_IMPORT
   - Pending ops from other clients are filtered as CONCURRENT

3. Partial Sync Failure with Retry (supersync-network-failure.spec.ts)
   - Creates 10 tasks, fails mid-batch, retries
   - Verifies all tasks sync without duplicates

4. Tag Deletion Atomic Cleanup (supersync-models.spec.ts)
   - Creates tag with 10 tasks
   - Deletes tag, verifies atomic removal from all tasks

5. Concurrent Project Move (supersync-lww-conflict.spec.ts)
   - Tests moving same task to different projects concurrently
   - NOTE: Currently reveals bug - task projectId becomes inconsistent

Tests 1-4 pass. Test 5 exposes a real sync bug to investigate.
2025-12-27 15:16:52 +01:00
Johannes Millan
c9e78b79d7 test(sync): make e2e test work again 2025-12-27 10:38:18 +01:00
Johannes Millan
dd5741faa7 fix(sync): prevent orphan subtasks when archiving via remote sync
Add defensive fix for race condition where subtasks could become
orphaned during archive sync:
1. Client A adds subtask to parent
2. Client B does SYNC_IMPORT before parent.subTaskIds synced
3. Client A archives parent (with stale subTaskIds in operation)
4. Client B receives archive - subtask left orphaned

The fix in deleteTaskHelper now looks up subtasks from state by
parentId in addition to the payload's subTaskIds, ensuring all
subtasks are removed even if the operation payload is stale.

Adds devError logging when orphan subtasks are detected to help
diagnose upstream issues.

Tests added:
- Unit tests for orphan subtask removal in task.reducer.spec.ts
- Integration tests documenting the race condition scenario
- E2E tests for archive subtask sync across clients
2025-12-26 19:54:49 +01:00
Johannes Millan
3bf1cc348f fix(export): read archiveYoung/archiveOld from ModelCtrl for export
The PfapiStoreDelegateService was reading archive data from NgRx store,
but archives are stored in ModelCtrl (pf database), not NgRx. The NgRx
archive state is only populated on loadAllData (import) and is never
updated when ArchiveService writes to ModelCtrl during finish day.

This caused exports to contain empty/stale archiveYoung data after
archiving tasks via "Finish Day", resulting in lost subtasks.

The fix reads archiveYoung and archiveOld from ModelCtrl (via
pfapiService.m.archiveYoung.load()) instead of NgRx selectors, since
that's where the actual archive data lives.

Includes E2E test to verify subtasks are preserved in archive after
legacy data import and finish day flow.
2025-12-26 18:43:46 +01:00
Johannes Millan
6191c782f0 test(archive): add failing tests for legacy import subtask loss
Add E2E and integration tests documenting a bug where tasks with
subtasks are lost when:
1. Importing legacy data (pre-operation logs)
2. Archiving via "Finish Day"
3. Exporting again

The archiveYoung ends up empty in the export. Tests will pass
once the bug is fixed.

Files added:
- e2e/fixtures/legacy-archive-subtasks-backup.json
- e2e/tests/import-export/legacy-archive-subtasks.spec.ts
- integration/legacy-archive-subtasks.integration.spec.ts
2025-12-26 16:02:34 +01:00
Johannes Millan
5d6c211f11 test(e2e): add clean slate semantics tests for SYNC_IMPORT
Add E2E tests verifying that SYNC_IMPORT operations properly implement
clean slate semantics:

1. "Import drops ALL concurrent work from both clients" - verifies that
   when Client A imports a backup, all pre-import tasks from both
   Client A and Client B are dropped after sync propagates.

2. "Late joiner synced ops are dropped after import" - verifies that
   even if Client B synced its work before Client A imported, those
   operations are NOT replayed after receiving the SYNC_IMPORT.

These tests validate the intentional design where imports represent
explicit user actions to restore ALL clients to a specific state.
2025-12-26 12:30:40 +01:00
Johannes Millan
22ded5e048 test(e2e): improve password change test reliability
- Make snackbar detection more resilient (allow quick auto-dismiss)
- Use dialog close as primary success indicator
- Re-enable password change e2e test (was skipped)
- Use distinct task names to avoid substring matching issues
2025-12-24 21:13:50 +01:00
Johannes Millan
6a26d914b5 test: skip tmp 2025-12-24 16:27:12 +01:00
Johannes Millan
72608a4aaa feat(migration): implement pre-migration dialog and backup functionality 2025-12-24 13:49:37 +01:00
Johannes Millan
1bd96a9182 fix(sync): refresh storage cache after cleanup and add serverTime to response
Address two issues identified in code review:

1. Storage cache not refreshed after cleanup:
   - Modified deleteOldSyncedOpsForAllUsers() to return { totalDeleted, affectedUserIds }
   - Cleanup job now calls updateStorageUsage() for each affected user
   - Prevents stale quota checks after nightly cleanup

2. serverTime missing from download response:
   - Added serverTime: Date.now() to DownloadOpsResponse
   - Enables client-side clock drift detection

Tests:
- Added serverTime response test in sync-fixes.spec.ts
- Added deleteOldSyncedOpsForAllUsers return structure tests
- Updated legacy SQLite tests for new return type (excluded from CI)
2025-12-23 18:31:57 +01:00
Johannes Millan
a405b6ee6d fix: address code review issues from sync and UX changes
Critical fixes:
- fix(sync): handle empty newOps with hasMorePiggyback flag
- fix(sync): handle skippedOps (stale operations) in sync service
- fix(tasks): replace requestAnimationFrame with RxJS delay(0)

High priority fixes:
- fix(sync): add rollback recovery for password change failures
- fix(e2e): improve password change verification robustness
- fix(sync): add try-catch to WebDAV test connection
- fix(sync): improve encrypted restore error message with guidance
- fix(android): add startWith() to fix pairwise() initial state

Medium priority fixes:
- fix(sync): add diagnostics to flush timeout error
- docs: document focus delay constants and rationale
- docs: add TODO for Android reminder native action handlers
2025-12-22 21:09:18 +01:00
Johannes Millan
064c2452ca fix(sync): handle piggyback limit in high-volume sync
When syncing 100+ operations, the server's piggyback limit (100 ops)
was causing Client B to miss operations. The server returned 100 piggybacked
ops but latestSeq was set to the actual server sequence (e.g., 199).
Client B then updated lastServerSeq to 199, so subsequent download got 0 ops.

Changes:
- Server: Add hasMorePiggyback flag to UploadOpsResponse when piggyback limit
  is reached and more ops exist
- Client: When hasMorePiggyback is true, store lastServerSeq as the max
  piggybacked op's serverSeq instead of latestSeq, ensuring subsequent
  download fetches remaining ops
- Effects: Change switchMap to mergeMap in autoAddTodayTagOnMarkAsDone to
  ensure ALL mark-as-done actions trigger planTasksForToday
- Flush service: Implement two-phase wait strategy (poll queue + acquire lock)
  to ensure all pending writes complete before upload
- Add diagnostic logging for operation counts at key stages

Test: High volume sync with 50 tasks + 49 mark-as-done (197 ops total)
now correctly syncs all done states via piggyback (100) + download (97).
2025-12-22 20:31:35 +01:00
Johannes Millan
c4cc32da29 feat(sync): add encryption password change feature for SuperSync
Implements the ability to change the encryption password by deleting
all server data and uploading a fresh snapshot with the new password.

Server changes:
- Add DELETE /api/sync/data endpoint to delete all user sync data
- Add deleteAllUserData() method to SyncService

Client changes:
- Add deleteAllData() to OperationSyncCapable interface
- Implement deleteAllData() in SuperSync provider
- Add EncryptionPasswordChangeService to orchestrate password change
- Add DialogChangeEncryptionPasswordComponent with validation
- Add "Change Encryption Password" button to sync settings (visible
  when encryption is enabled)
- Add translations for all new UI strings

Testing:
- Add 10 unit tests for EncryptionPasswordChangeService
- Add 14 unit tests for DialogChangeEncryptionPasswordComponent
- Add 5 E2E tests for complete password change flow
- Add changeEncryptionPassword() helper to SuperSyncPage

Also fixes:
- Add missing deleteAllData() to MockOperationSyncProvider
- Fix typo S_FINISH_DAY_SYNC_ERROR -> FINISH_DAY_SYNC_ERROR
2025-12-22 13:31:19 +01:00
Johannes Millan
c757ff500d test(sync): re-enable sync after import in tests and adjust baseURL fallback 2025-12-22 12:08:04 +01:00
Johannes Millan
329a50957b test(e2e): add comprehensive SuperSync encryption tests
Add 4 new E2E tests for SuperSync encryption coverage:
- Multiple tasks sync correctly with encryption
- Bidirectional sync works with encryption
- Task update syncs correctly with encryption
- Long encryption password works correctly

Also clean up outdated TODO comments from header - encryption
is now working correctly.
2025-12-22 12:06:35 +01:00
Johannes Millan
58fc0b65b3 refactor(e2e): fix and improve supersync stress tests
- Fix selector bug: .check-btn -> .task-done-btn for marking tasks done
- Add required .hover() before clicking done button
- Add waitForTask() verification for stability
- Create createQuietClient() helper to suppress non-error console logs
- Reduce task counts to ensure reliable test completion
- Move stress tests from supersync-edge-cases.spec.ts to supersync-stress.spec.ts
- Bulk sync test: 10 tasks, 13 operations (~30s)
- High volume test: 20 tasks, 39 operations (~60s)
2025-12-20 11:41:56 +01:00
Johannes Millan
155e03b84c docs: remove outdated sync documentation and deprecated file
- Delete docs/ai/sync/server-sync-architecture.md which incorrectly
  stated "Status: Not Started" when server sync is fully implemented
- Delete deprecated src/app/features/time-tracking/store/archive.effects.ts
  which was empty and marked for removal
- Update local-actions.token.ts comment to reference the correct
  archive-operation-handler.effects.ts file
2025-12-20 11:09:49 +01:00
Johannes Millan
c1ea6f27b0 fix(sync): prevent deadlock when repair operation needs lock
The sp_op_log lock is non-reentrant. When validation/repair code was
called from inside the lock (during sync or conflict resolution),
createRepairOperation() tried to acquire the lock again, causing a
deadlock.

Add callerHoldsLock/skipLock parameter through the call chain:
- operation-log-sync.service.ts passes callerHoldsLock: true when inside lock
- conflict-resolution.service.ts passes callerHoldsLock: true
- validate-state.service.ts accepts and forwards the flag
- repair-operation.service.ts skips lock when skipLock: true

Also adds high-volume sync E2E test (499 operations) and fixes test
isolation in meta-reducer-ordering integration tests.
2025-12-20 10:15:38 +01:00
Johannes Millan
61e32e72b3 fix(sync): prevent false clock drift warnings and cascade conflicts
Two critical sync fixes:

1. Clock drift detection now uses serverTime from response instead of
   receivedAt from old operations. Previously, downloading 12-hour-old
   ops would falsely trigger "clock drift" warnings.

2. User interactions during sync are now blocked from creating operations.
   When HydrationStateService.startApplyingRemoteOps() is called, the
   operation-capture meta-reducer skips capturing local actions, preventing
   stale vector clocks and cascade conflicts on slow devices.

Includes comprehensive tests for both fixes and a bulk sync e2e test.
2025-12-20 01:31:07 +01:00