Commit graph

53 commits

Author SHA1 Message Date
Johannes Millan
42e6626b76 docs(sync): consolidate sync docs + enforce the contributor model
Collapse the sprawling, partly-stale docs/sync-and-op-log/ tree into a
small authoritative set and make the sync-correctness invariant
partly lint-enforced instead of convention-only.

Docs:
- Delete superseded/duplicate/provably-stale design, plan, and
  background-research docs (quick-reference, the architecture-diagrams
  monolith, the "Hybrid Manifest" docs describing code that does not
  exist, completed long-term plans, LLM-synthesis analyses).
- Salvage load-bearing decision history into the surviving docs before
  deletion: rejected-alternatives rationale -> operation-log-architecture
  ("Why this architecture"); vector-clock pruning incident history ->
  vector-clocks.md; archive-payload optimization -> architecture E.7.
- Add contributor-sync-model.md as the single-invariant entry point
  (one user intent = one op; replayed/remote ops must not re-trigger
  effects), with a decision table mapping to the enforcing linters.
- Repoint external/internal cross-refs; add CONTRIBUTING.md + CLAUDE.md
  pointers; record the migration in a dated docs/plans/ design doc.

Enforcement (new eslint-local-rules):
- no-actions-in-effects (error): effects must inject LOCAL_ACTIONS /
  ALL_ACTIONS, never the raw @ngrx/effects Actions stream.
- no-multi-entity-effect (warn, heuristic): flags a literal returned
  array of >=2 action-creator calls; docstring + valid-case specs pin
  exactly which shapes are and are not detected.
- run-specs.js runner wired into `npm run lint` via test:lint-rules;
  refuses to run under test-framework globals and counts RuleTester.run
  invocations so a spec that asserts nothing fails instead of passing.
- Correct the ALL_ACTIONS JSDoc in local-actions.token.ts to match
  reality (archive-operation-handler uses LOCAL_ACTIONS).

Reviewed via parallel multi-agent review; findings W1/W2/W4 and a
dangling doc anchor addressed.
2026-05-15 16:51:50 +02:00
johannesjo
ee71f4fe8e docs: restore recognition cues in CLAUDE.md sync rules
Add back the "why/symptom" tails that were over-trimmed: selector-based
effects fire on every store change, multi-entity meta-reducer example,
TODAY_TAG.taskIds ordering-only role, store.dispatch non-blocking
behavior, and SYNC_IMPORT "by design" framing. Rules stay one-liners
but now carry enough context for Claude to recognize when they apply.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 23:07:44 +02:00
johannesjo
eddcea7070 docs: trim CLAUDE.md and split E2E reference into e2e/CLAUDE.md
Drop the architecture overview (derivable from code and already
covered in docs/sync-and-op-log/ and ARCHITECTURE-DECISIONS.md),
collapse the long sync invariants into one-liners with pointers,
and dedupe the anti-patterns table against the rule lists. Move
the SuperSync docker-compose block and E2E iteration tips into
e2e/CLAUDE.md where the rest of the E2E reference lives. Tighten
the new docs/documentation-guide.md by dropping content that
duplicates docs/wiki/0.00-Wiki-Structure-and-Organization.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 23:04:03 +02:00
johannesjo
f8efc5d9c9 docs: require wiki updates for user-facing changes in CLAUDE.md
Add a documentation-update rule to CLAUDE.md and extract the
detailed guidance into docs/documentation-guide.md, mirroring the
styling-guide pattern. Defaults wiki edits to Reference (3.XX) notes
and points to 0.00-Wiki-Structure-and-Organization.md as required
reading.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 22:50:01 +02:00
novikov1337danil
1abb15b804
refactor(backup): unify backup filename format (#7141)
* refactor(backup): implement consistent timestamp for backup filenames

* refactor(i18n): rename PRIVACY_EXPORT key to PRIVACY_EXPORT_DESCRIPTION

* refactor(i18n): add PRIVACY_EXPORT key for data export in multiple languages

* refactor(backup): standardize backup filename prefix

* refactor(backup): update backup filename format to use underscore separator

* refactor(i18n): update translations

* refactor(backup): move getBackupTimestamp utility to a shared location for consistency

* test(backup): add unit tests for getBackupTimestamp utility

* fix(e2e): move MIGRATION_BACKUP_PREFIX to migration.const

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(tests): move jasmine.clock().install() to beforeEach for consistency

* refactor(backup): consolidate backup filename constants and update imports

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-21 14:09:09 +02:00
Johannes Millan
87f66fea9c refactor(date): centralize startOfNextDay offset behind DateService
Replaces ad-hoc `Date.now() - _dateService.startOfNextDayDiff` arithmetic
scattered across services with a small set of offset-aware helpers on
DateService, and makes the raw field private so TypeScript prevents
future regressions.

Public surface added to DateService:
  - getLogicalTodayDate(): Date — offset-aware "today"
  - getLogicalTomorrowMs(): number — logical today + 1 calendar day,
    DST-safe via setDate (naive +24h stayed on the same local date
    during fall-back transitions)
  - getStartOfNextDayDiffMs(): number — read-only accessor for the
    service-boundary case where pure utilities need the raw offset

The raw `startOfNextDayDiff` field is now `private`; TypeScript
catches both member access and destructuring from outside.

Migrated call sites (all semantic-identical except the DST fix):
  - planner.service.ts: tomorrow$ and ensureDayLoaded
  - add-tasks-for-tomorrow.service.ts: addAllDueToday/Tomorrow
    (+ offset-aware spec coverage)
  - daily-summary.component.ts: isIncludeYesterday
  - global-config.effects.ts + app-state.effects.ts: setTodayString
    payloads now read via the accessor

Preserved for sync-replay determinism:
  - isTodayWithOffset pure util in src/app/util/is-today.util.ts
  - reducers/selectors continue to take startOfNextDayDiffMs as an
    explicit argument from action payloads

Deferred with an in-file TODO: task-due.effects.ts:170 — the effect
is selector-driven (replay-sensitive per CLAUDE.md #8) and its spec is
xdescribe'd, so verification is impossible in this pass.

Documented in CLAUDE.md (Important Development Notes #14 + an
anti-patterns row).

A broader audit surfaced 10 pre-existing sites elsewhere in the
codebase that bypass the logical clock (planner daysToShow$,
argument-less getDbDateStr in pipes, simple-counter streak, plugin
counter). Those are tracked separately and not part of this refactor.
2026-04-17 18:13:02 +02:00
Johannes Millan
772f3f9d97 fix(security): redact user-entered content from remaining log call sites
Remove task titles from reminder dialog trigger, reminder worker
  postMessage, and mobile notification success logs. Add log privacy
  comment to Log class and anti-pattern entry to CLAUDE.md.

  Co-authored-by: Rob Williamson <rob@robwilliamson.com>
2026-03-28 16:35:01 +01:00
Johannes Millan
02dfb9472c docs: add styling guide and reference from CLAUDE.md
Extract styling rules, CSS variable reference, and design token
patterns into docs/styling-guide.md for a consistent design language.
CLAUDE.md now points to the guide for all styling changes.
2026-03-18 13:14:10 +01:00
Johannes Millan
c70ced204e fix(sync): fix stale comments, doc refs, and preserve lastSeq on clean-slate
Remove references to deleted docs/ai/ files, update stale comments about
protectedClientIds and pruning-aware comparison to reflect current REPLACE
semantics, fix MAX=30→20 heading, client_0..29→19 comment, use ?? over ||,
preserve lastSeq in server clean-slate path to prevent sequence reuse, and
add clarifying comments for mock limitations and validation guards.
2026-02-12 16:27:56 +01:00
Johannes Millan
0b73461690 fix(sync): fix vector clock comparison parity and validation consistency
- Fix client/server comparison divergence: remove isVectorClockEmpty
  short-circuit that caused {} vs {a:0} to return LESS_THAN on client
  but EQUAL on shared impl. Now delegates all comparisons to shared.
- Align server value cap with client: raise from 10M to MAX_SAFE_INTEGER
  to prevent silent clock entry stripping on long-term usage.
- Make client validation require integers (Number.isInteger) matching
  server-side validation.
- Add deterministic tie-breaking (localeCompare) to pruning sort for
  equal counter values.
- Fix stale comments: MAX references and CLAUDE.md DoS cap (5x→2.5x).
2026-02-12 16:27:55 +01:00
Johannes Millan
f37280e082 refactor(sync): reduce MAX_VECTOR_CLOCK_SIZE from 30 to 20
Lower the cap to leave headroom for future increases and surface
size-related edge cases earlier. All pruning logic is MAX-agnostic
so this is a safe constant change with documentation updates.
2026-02-12 16:27:55 +01:00
Johannes Millan
29541951a3 refactor(sync): increase MAX_VECTOR_CLOCK_SIZE from 10 to 30 and remove defense layers
At MAX=10, pruning triggered frequently enough (11+ unique client IDs from
reinstalls/new browsers) to require 4 defense layers compensating for
information loss: pruning-aware comparison, protected client IDs with
migration, isLikelyPruningArtifact heuristic, and same-client check.

At MAX=30, pruning almost never triggers (needs 31+ unique client IDs).
A 30-entry clock is ~500 bytes — negligible bandwidth. This allows removing
most defense layers while keeping two cheap backward-compat checks for old
10-entry pruned data still on servers.

Removed:
- Pruning-aware mode in compareVectorClocks (standard comparison now)
- Protected client IDs mechanism (storage, migration, preservation)
- selectProtectedClientIds function
- Clock normalization in SyncImportFilterService

Kept temporarily (backward compat with old 10-entry data):
- isLikelyPruningArtifact with LEGACY_MAX=10
- Same-client check (always mathematically correct)
2026-02-12 16:27:55 +01:00
Johannes Millan
fc56aabec4 docs(sync): fix stale DoS cap references from 3x to 5x MAX_VECTOR_CLOCK_SIZE
The sanitizeVectorClock() DoS cap was changed to 5x MAX (50 entries) but
comments in CLAUDE.md, vector-clocks.md, sync.types.ts, and
validation.service.ts still referenced the old 3x MAX (30) value.
2026-02-10 20:38:32 +01:00
Johannes Millan
a774c46700 fix(sync): remove client-side vector clock pruning from ConflictResolutionService and fix rejection counting
- Remove limitVectorClockSize from ConflictResolutionService (same
  infinite loop risk as SupersededOperationResolverService)
- Include retry-exceeded ops in permanentRejectionCount so sync status
  accurately reflects data loss
- Fix stale JSDoc (100 -> 30 entries) in sanitizeVectorClock
- Remove dead getProtectedClientIds mocks from spec files
- Extract _getEntityKey helper, remove redundant guards, optimize
  Object.keys calls in server pruning log
2026-02-09 17:55:12 +01:00
Johannes Millan
fdc942babb
fix(sync): prevent infinite loop when concurrent modification resolution keeps failing (#6434)
* fix(sync): prevent infinite loop when concurrent modification resolution keeps failing

When vector clock pruning makes it impossible to create a dominating clock
(e.g., entity clock has MAX entries and client ID isn't among them), the cycle
"upload → CONFLICT_CONCURRENT → merge clocks → upload → reject again" repeats
endlessly. This adds a per-entity retry counter (MAX_CONCURRENT_RESOLUTION_ATTEMPTS=3)
that permanently rejects ops after exceeding the limit, breaking the sync loop.

The counter resets when a sync cycle completes with no rejections (healthy state).

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

* fix(sync): move vector clock pruning after conflict detection to fix root cause

The infinite sync loop happens because it's mathematically impossible to build
a dominating clock with MAX_VECTOR_CLOCK_SIZE entries when the entity's clock
already has MAX entries and the client's ID isn't among them. The merged clock
needs MAX+1 entries (all entity clock IDs + client ID), but client-side pruning
drops one entity clock ID. The server's pruning-aware comparison then sees the
dropped key as non-shared and returns CONCURRENT instead of GREATER_THAN.

Fix: Move limitVectorClockSize from validation (before comparison) to
processOperation (after comparison, before storage). The full unpruned clock
is now used for conflict detection — all entity clock IDs are present so
bOnlyCount=0 → GREATER_THAN. Storage still gets the pruned clock.

Client-side: Stop pruning in SupersededOperationResolverService. The server
handles pruning after conflict detection.

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

* fix(sync): tighten vector clock sanitize limit from 100 to 3x MAX_VECTOR_CLOCK_SIZE

The old sanitize cap of 100 entries was unnecessarily wide. Since conflict
resolution clocks are at most ~12-15 entries (entity clock MAX=10 + client ID
+ a few merged), cap at 3x MAX (30) for DoS protection while leaving ample
room for legitimate clocks.

Also update server-side pruning tests to use realistic clock sizes (20 entries
instead of 50) to stay within the new sanitize limit.

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

* docs(sync): document vector clock pruning invariant and infinite loop fix

- Add "Pruning and the Pruning-Aware Comparison" section to vector-clocks.md
  explaining the critical invariant: server prunes AFTER comparison, not before
- Add rule 13 to CLAUDE.md to prevent future regressions
- Update conflict resolution key files table with rejected-ops-handler and
  superseded-operation-resolver services

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

* docs(sync): update last-updated date in conflict resolution docs

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

* test(sync): update pruning tests to reflect server-side pruning design

Client no longer prunes vector clocks during conflict resolution — the
server handles pruning after conflict detection. Tests now verify the
merged clock is sent unpruned with all keys preserved.

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

* test(sync): fix client-side pruning tests and add server-side regression test

- Update 7 SupersededOperationResolverService tests to verify client
  does NOT prune (server handles pruning after conflict detection)
- Remove redundant `newClock` alias in superseded-operation-resolver
- Add regression test: MAX+1 entry clock accepted as GREATER_THAN
  when it dominates a MAX entry entity clock (the core infinite loop fix)

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-09 12:01:43 +01:00
Johannes Millan
200525c752 docs: clarify commit message convention for test changes
Reserve `fix` type for actual code/bug fixes. Test-related changes
should always use `test:`, e.g., `test(e2e):` not `fix(e2e):`.
2026-02-08 14:16:06 +01:00
Johannes Millan
702f768784 docs: clarify test commit message convention 2026-01-21 14:34:45 +01:00
Johannes Millan
038a722ed8 style: apply prettier formatting 2026-01-10 17:09:14 +01:00
Johannes Millan
74fe0c01a0 Merge branch 'master' into feat/operation-logs
* master:
  16.9.4
  docs: add Angular commit message guidelines to CLAUDE.md
  fix(ci): update references for repo migration to super-productivity org
  build(ci): improve android build release upload reliability
  16.9.3
  fix(calendar): display proper error messages instead of [object Object]
  fix(e2e): fix keyboard shortcut delete test and reduce sync test flakiness
  fix(tasks): add subscription cleanup to delete confirmation dialog
  fix(schedule): maintain visibility during task overlap on schedule (#5887)
  16.9.2

# Conflicts:
#	e2e/pages/sync.page.ts
2026-01-10 13:06:20 +01:00
Johannes Millan
7179e3d6f8 docs: add Angular commit message guidelines to CLAUDE.md 2026-01-10 12:57:32 +01:00
Johannes Millan
cdf52cc4e5 fix(e2e): split docker-compose files for standalone webdav tests
docker-compose.e2e.yaml was failing when used standalone because the
supersync service only had a port override without a base definition.
Split into separate files so e2e:docker:webdav works without errors.
2026-01-09 17:27:30 +01:00
Johannes Millan
dd79f54c23 fix: address code review findings from pfapi-to-oplog refactor
- Update CLAUDE.md to reference /src/app/op-log/persistence/ instead
  of deleted /src/app/pfapi/ directory
- Fix boolean coercion in archive-migration.service.ts (same pattern
  as bug fixed in 183bf2c18 for LegacyPfDbService)
- Replace deprecated .toPromise() with firstValueFrom() in
  archive.service.ts for RxJS 8 compatibility
2026-01-07 16:21:18 +01:00
Johannes Millan
3f3f0685eb Merge branch 'master' into feat/operation-logs
* master: (21 commits)
  test: increase timeout for encryption
  16.8.3
  fix(e2e): use pressSequentially for time input in task-detail tests
  fix(sync): resolve 25-second initial sync timeout race condition
  feat(e2e): add Docker-based E2E test isolation
  fix(schedule): start tracking selected task when pressing Y in schedule view
  fix(tasks): clear reminder when clicking "today" button on already-today tasks
  fix(e2e): use format-agnostic time change in task-detail tests
  16.8.2
  fix(test): reset selector overrides to prevent test pollution
  build: update CLAUDE.md
  fix(calendar): add periodic refresh for planner and scheduler views
  feat(effects): consolidate task update actions in PluginHooksEffects
  fix(sync): show skip button immediately when offline
  fix(db): add missing _afterReady guard to loadAll method
  feat(android): add alarm sound and vibration to task reminders
  feat(sync): add skip button to loading screen when waiting for sync
  fix(pomodoro): allow manual session end to start break early
  fix(i18n): add missing translate pipe to play button tooltip
  fix(tasks): handle undefined tasks in reminder effect
  ...

# Conflicts:
#	CLAUDE.md
#	docker-compose.e2e.yaml
#	e2e/tests/task-detail/task-detail.spec.ts
#	package.json
#	src/app/features/tasks/store/task-reminder.effects.spec.ts
#	src/app/features/tasks/store/task-reminder.effects.ts
#	src/app/plugins/plugin-hooks.effects.ts
2026-01-04 18:20:10 +01:00
Johannes Millan
d8a6a7dc62 build: update CLAUDE.md 2026-01-04 14:52:35 +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
8fff1325b4 docs: fix SYNC_IMPORT filtering section to match implementation
- Fix CLAUDE.md path reference from docs/op-log/ to docs/sync-and-op-log/
- Rewrite section 2c in architecture diagrams to reflect actual implementation:
  - Was: UUIDv7 timestamp replay (removed feature)
  - Now: Vector clock filtering with clean slate semantics
- Update service reference from removed _replayLocalSyncedOpsAfterImport()
  to SyncImportFilterService.filterOpsInvalidatedBySyncImport()
- Clarify that CONCURRENT ops are dropped, not replayed
2025-12-27 13:15:47 +01:00
Johannes Millan
b4ce9d5da6 docs: reorganize sync and operation-log documentation
Move scattered architecture docs into centralized locations:

- Move operation-log docs from src/app/core/persistence/operation-log/docs/
  to docs/op-log/
- Flatten docs/sync/sync/ nested structure to docs/sync/
- Move supersync-encryption-architecture.md from docs/ai/ to docs/sync/
- Copy pfapi sync README to docs/sync/pfapi-sync-overview.md
- Update all cross-references to use new paths

This improves discoverability and keeps architecture documentation
separate from source code.
2025-12-27 10:54:13 +01:00
Johannes Millan
3a390f5e59 docs(claude): update E2E testing instructions for improved efficiency 2025-12-26 18:45:33 +01:00
Johannes Millan
9f6bb4e7ac fix(sync): implement clean slate semantics for SYNC_IMPORT/BACKUP_IMPORT
SYNC_IMPORT and BACKUP_IMPORT now represent a complete fresh start:
- All operations without knowledge of the import are dropped
- CONCURRENT ops from "unknown clients" are no longer preserved
- Local synced ops are NOT replayed after import

This ensures a true "restore to point in time" semantic where all
clients start fresh from the imported state, with no concurrent
work preserved.

Changes:
- Simplify SyncImportFilterService to filter ALL CONCURRENT/LESS_THAN ops
- Remove _replayLocalSyncedOpsAfterImport() method and related code
- Remove _checkOperationEntitiesExist() helper method
- Update tests to expect new behavior
- Document semantics in CLAUDE.md
2025-12-26 11:20:05 +01:00
Johannes Millan
d48694d0ce feat(docs): add command for running SuperSync E2E tests 2025-12-24 14:15:29 +01:00
Johannes Millan
7f24d13bd6 docs: add event loop yield pattern to development notes
Document the pattern of yielding to the event loop after bulk NgRx
dispatches to prevent state updates from being lost during rapid
dispatch sequences (50+ operations).
2025-12-22 12:07:44 +01:00
Johannes Millan
ee6a766a46 fix(sync): add vector-clock dominance check to late-joiner replay
- Add missing vector-clock comparison in _replayLocalSyncedOpsAfterImport
  that filters ops dominated (LESS_THAN) by SYNC_IMPORT's clock
- Replace local MAX_REJECTED_OPS_BEFORE_WARNING with imported constant
- Fix CLAUDE.md doc path reference to operation-log-architecture-diagrams.md
- Add 6 comprehensive tests for vector-clock dominance behavior
2025-12-12 20:48:40 +01:00
Johannes Millan
149947b8ae fix(sync): suppress selector-based effects during hydration/replay
Selector-based effects (like preventParentAndSubTaskInTodayList$) were
firing during operation replay because they subscribe directly to store
selectors rather than actions. LOCAL_ACTIONS filtering only works for
action-based effects.

This caused duplicate operations to be captured during hydration, growing
the operation queue unnecessarily and impacting performance.

- Add HydrationStateService to track when remote ops are being applied
- Wrap OperationApplierService.applyOperations() with hydration state
- Filter preventParentAndSubTaskInTodayList$ during hydration
- Document selector-based effects anti-pattern in CLAUDE.md
2025-12-12 20:48:13 +01:00
Johannes Millan
d3061fc15b docs: add effects anti-pattern to CLAUDE.md
Highlight the rule that effects should NEVER run for remote operations
in the anti-patterns section for better visibility.
2025-12-12 20:47:48 +01:00
Johannes Millan
3e8242bc55 refactor(sync): add ArchiveOperationHandler for remote archive ops
Establish general rule: effects should NEVER run for remote operations.
Side effects happen exactly once on the originating client.

- Create ArchiveOperationHandler service for remote archive side effects
- Integrate handler into OperationApplierService (called after dispatch)
- Change archive.effects.ts to use LOCAL_ACTIONS only
- Update CLAUDE.md with the general rule about effects
- Add Section 8 to architecture diagrams documenting the pattern

For archive operations:
- moveToArchive: local writes BEFORE dispatch, remote via handler AFTER
- restoreTask: local via effect, remote via handler
- flushYoungToOld: local via effect, remote via handler
2025-12-12 20:47:48 +01:00
Johannes Millan
78c65acf4d test(e2e): add sd:today to tasks for TODAY view visibility
Tasks created without explicit dueDay don't appear in TODAY view
due to recent selector changes. Add sd:today short syntax to ensure
tasks have dueDay set and appear correctly in tests.
2025-12-12 20:47:48 +01:00
Johannes Millan
02323dd33d docs: add atomic multi-entity changes guideline to CLAUDE.md
Add note #8 explaining when to use meta-reducers instead of effects
for multi-entity state changes to ensure sync consistency.
2025-12-12 20:47:48 +01:00
Johannes Millan
04a9ef1e34 refactor(sync): migrate move operations to anchor-based positioning
Replace newOrderedIds (full list) with afterTaskId (anchor) for sync-friendly
drag-drop operations. Concurrent moves now merge correctly instead of
conflicting.

Actions migrated:
- moveProjectTaskInBacklogList
- moveProjectTaskToBacklogList
- moveProjectTaskToRegularList
- moveTaskInTodayList (PROJECT and TAG contexts)

Also includes:
- deleteProject payload slim-down (projectId + noteIds instead of full Project)
- Helper functions: moveItemAfterAnchor(), getAnchorFromDragDrop()
- Comprehensive tests for all anchor-based moves
- Documentation updates in todo.md
2025-12-12 20:46:41 +01:00
Johannes Millan
ac8ada84f0 fix(op-log): add error handling for critical failure paths
- Add clientId validation before persisting operations
- Track compaction failures and notify user after 3 consecutive failures
- Add hydration recovery notification when both hydration and recovery fail
- Wrap conflict resolution in try-catch for atomicity
- Add HYDRATION_FAILED, COMPACTION_FAILED, CONFLICT_RESOLUTION_FAILED translations
- Update CLAUDE.md: only edit en.json for translations
2025-12-12 20:46:21 +01:00
Johannes Millan
f8e0160801 docs: plan operation logs again 1 2025-12-12 20:46:05 +01:00
Johannes Millan
9f2c786e41 refactor: move tests 2025-08-02 11:37:25 +02:00
Johannes Millan
41b287fd9d refactor(e2e): simplify Playwright commands to essentials
- Keep only the most useful commands:
  - e2e:playwright - run all tests with minimal output
  - e2e:playwright:file - run single file with detailed output
  - e2e:playwright:ui/debug/headed/report - existing useful commands
- Remove complexity: test-summary.js, minimal config, redundant commands
- Use line reporter by default for cleaner output
- Update CLAUDE.md documentation

BREAKING CHANGE: Removed e2e:playwright:quick, e2e:playwright:failures, and e2e:playwright:summary commands
2025-08-01 18:44:33 +02:00
Johannes Millan
fadff3bc19 test(e2e): add command to run single test file
- Add npm run e2e:playwright:file command for running individual test files
- Update CLAUDE.md documentation with all Playwright commands
- Example usage: npm run e2e:playwright:file tests/work-view/work-view.spec.ts
2025-08-01 18:44:33 +02:00
Johannes Millan
69cb6d7e5a docs: add Playwright E2E test commands to CLAUDE.md 2025-08-01 18:44:33 +02:00
Johannes Millan
4ea38843d0 feat: add npm commands for single file operations with minified output
- Add 'npm run checkFile <file>' to run prettier and lint on a single file
- Add 'npm run prettier:file <file>' for formatting individual files
- Add 'npm run lint:file <file>' for linting individual files
- Add 'npm run test:file <file>' for running tests on individual spec files
- Create wrapper scripts that show minimal output on success, full output on errors
- Update CLAUDE.md to emphasize using checkFile command frequently
- Add 25-second timeout for test execution to prevent hanging
2025-07-12 10:48:51 +02:00
Johannes Millan
4caf7b4fa5 build: update CLAUDE.md 2025-07-03 20:16:53 +02:00
Johannes Millan
d676c4086a build: update claude instructions 2025-06-12 12:06:48 +02:00
Johannes Millan
db4f2c213b Merge branch 'feat/merge-issue-provider-logic'
* feat/merge-issue-provider-logic: (42 commits)
  docs: add comment explaining GitLab issue ID format and remove debug logs
  fix: extract numeric issue ID from malformed GitLab issue IDs
  debug: add logging to GitLab issueLink to debug URL construction
  fix: update all references from searchIssues$ to searchIssues Promise method
  fix: update all references from issueLink$ to issueLink Promise method
  fix: correct GitLab issue URL format
  fix: change ISSUE_REFRESH_MAP to use issueProviderId as key
  outline
  refactor: convert pollTimer$ to simple pollInterval number
  refactor: convert searchIssues$ to return Promise instead of Observable
  refactor: convert getById$ to return Promise instead of Observable
  refactor: convert issueLink$ to return Promise instead of Observable
  refactor: convert testConnection$ to return Promise instead of Observable
  feat(issue): further improve
  refactor: improve typing for comment parameters in issue-content component
  feat(issue): further simplify and make some conditions work as they should
  refactor(issue): merge IssueFieldConfig field and getValue into unified value property
  refactor(issue): use proper issue interface types instead of any casts
  feat(issue): more adjustments
  feat(issue): more adjustments
  ...
2025-06-11 09:51:31 +02:00
Johannes Millan
c916bd558d build: update claude.md 2025-06-11 09:49:48 +02:00
Johannes Millan
8fbd7bab0a feat: add prettier stuff 2025-06-10 10:17:50 +02:00