mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-17 16:37:43 +00:00
refactor(op-log): merge LWWOperationFactory into ConflictResolutionService
- Consolidate LWWOperationFactory methods (createLWWUpdateOp, mergeAndIncrementClocks) into ConflictResolutionService to reduce service count - Remove redundant caching in SuperSyncProvider (SyncCredentialStore already caches) - Remove _onBlurWhenNotTracking$ sync trigger from SyncTriggerService - Add documentation for dueDay/dueWithTime mutual exclusivity pattern - Change docker-compose postgres port to 55432 to avoid conflicts
This commit is contained in:
parent
6fbda9d25f
commit
bfdac6d19a
16 changed files with 861 additions and 425 deletions
141
ARCHITECTURE-DECISIONS.md
Normal file
141
ARCHITECTURE-DECISIONS.md
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
# Architecture Decision Records
|
||||
|
||||
This document tracks significant architectural decisions and patterns in the Super Productivity codebase. When making changes that affect these patterns, reference this document and update it if needed.
|
||||
|
||||
## Active Patterns & Decisions
|
||||
|
||||
### 1. dueDay/dueWithTime Mutual Exclusivity Pattern
|
||||
|
||||
**Status**: ✅ Active (since commit `400ca8c1`, 2026-01-29)
|
||||
|
||||
**Decision**: The `task.dueDay` and `task.dueWithTime` fields are mutually exclusive in new data. When setting `dueWithTime`, `dueDay` must be cleared (set to `undefined`). When reading, `dueWithTime` takes priority over `dueDay`.
|
||||
|
||||
**Rationale**:
|
||||
|
||||
- Prevents state inconsistency bugs where both fields had conflicting values
|
||||
- Single source of truth for task scheduling
|
||||
- Simpler state management
|
||||
|
||||
**Implementation**:
|
||||
|
||||
- **Writing**: Clear `dueDay` when setting `dueWithTime` (in meta-reducers)
|
||||
- **Reading**: Check `dueWithTime` first; only check `dueDay` if `dueWithTime` is not set (in selectors)
|
||||
- **Legacy Data**: Old data with both fields works via priority pattern (no migration needed)
|
||||
|
||||
**Documentation**: [`docs/ai/dueDay-dueWithTime-mutual-exclusivity.md`](docs/ai/dueDay-dueWithTime-mutual-exclusivity.md)
|
||||
|
||||
**Key Files**:
|
||||
|
||||
- [`task.model.ts`](src/app/features/tasks/task.model.ts) - Field definitions with JSDoc
|
||||
- [`task-shared-scheduling.reducer.ts`](src/app/root-store/meta/task-shared-meta-reducers/task-shared-scheduling.reducer.ts) - Write implementation
|
||||
- [`work-context.selectors.ts`](src/app/features/work-context/store/work-context.selectors.ts) - Read pattern
|
||||
- [`planner.selectors.ts`](src/app/features/planner/store/planner.selectors.ts) - Read pattern
|
||||
- [`task.selectors.ts`](src/app/features/tasks/store/task.selectors.ts) - Read pattern
|
||||
|
||||
**When to Update This Pattern**:
|
||||
|
||||
- Adding new date/time scheduling fields
|
||||
- Modifying task scheduling logic
|
||||
- Working with task selectors that check due dates
|
||||
|
||||
---
|
||||
|
||||
### 2. TODAY_TAG Virtual Tag Pattern
|
||||
|
||||
**Status**: ✅ Active (established pattern)
|
||||
|
||||
**Decision**: `TODAY_TAG` (ID: `'TODAY'`) is a **virtual tag** whose membership is determined by `task.dueWithTime` or `task.dueDay`, not by `task.tagIds`. The tag's `taskIds` field stores only the ordering of tasks, not membership.
|
||||
|
||||
**Key Invariant**: `TODAY_TAG.id` must NEVER be added to `task.tagIds`
|
||||
|
||||
**Rationale**:
|
||||
|
||||
- Uniform move operations across all tags (virtual and regular)
|
||||
- Single source of truth for "today" membership (date fields, not tagIds)
|
||||
- Self-healing ordering (stale entries automatically filtered)
|
||||
- Natural integration with planner (which uses date fields)
|
||||
|
||||
**Documentation**: [`docs/ai/today-tag-architecture.md`](docs/ai/today-tag-architecture.md)
|
||||
|
||||
**Related**: Uses the dueDay/dueWithTime mutual exclusivity pattern (Decision #1)
|
||||
|
||||
**Key Files**:
|
||||
|
||||
- [`tag.const.ts`](src/app/features/tag/tag.const.ts) - TODAY_TAG definition
|
||||
- [`work-context.selectors.ts`](src/app/features/work-context/store/work-context.selectors.ts) - Membership computation
|
||||
- [`task-shared-helpers.ts`](src/app/root-store/meta/task-shared-meta-reducers/task-shared-helpers.ts) - Invariant enforcement
|
||||
|
||||
**When to Update This Pattern**:
|
||||
|
||||
- Adding new virtual tags
|
||||
- Modifying tag membership logic
|
||||
- Working with today's task list
|
||||
|
||||
---
|
||||
|
||||
## How to Use This Document
|
||||
|
||||
### When Making Architectural Changes
|
||||
|
||||
1. **Before implementing**: Check if your change affects any active pattern
|
||||
2. **During implementation**: Follow the documented patterns
|
||||
3. **After implementation**: Update this document if you've:
|
||||
- Changed an existing pattern
|
||||
- Added a new architectural pattern
|
||||
- Made a decision that affects future development
|
||||
|
||||
### When to Add a New Decision
|
||||
|
||||
Add a new decision record when:
|
||||
|
||||
- The decision affects multiple files/modules
|
||||
- Future developers need to understand "why" not just "what"
|
||||
- The pattern needs to be followed consistently across the codebase
|
||||
- The decision prevents a specific class of bugs
|
||||
|
||||
### Decision Record Template
|
||||
|
||||
```markdown
|
||||
### N. [Pattern/Decision Name]
|
||||
|
||||
**Status**: ✅ Active | 🚧 Draft | ⚠️ Deprecated | ❌ Superseded
|
||||
|
||||
**Decision**: [One-sentence summary of the decision]
|
||||
|
||||
**Rationale**:
|
||||
|
||||
- [Why was this decision made?]
|
||||
- [What problems does it solve?]
|
||||
|
||||
**Implementation**:
|
||||
|
||||
- [How is it implemented?]
|
||||
- [Key techniques or patterns used]
|
||||
|
||||
**Documentation**: [Link to detailed docs]
|
||||
|
||||
**Key Files**: [List of primary files implementing this pattern]
|
||||
|
||||
**When to Update This Pattern**: [Scenarios when someone should review/update this]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [`docs/ai/`](docs/ai/) - AI/Developer architecture docs (detailed patterns)
|
||||
- [`docs/sync-and-op-log/`](docs/sync-and-op-log/) - Operation log architecture
|
||||
- [`docs/long-term-plans/`](docs/long-term-plans/) - Future architectural plans
|
||||
|
||||
---
|
||||
|
||||
## Commit Reference
|
||||
|
||||
When committing changes related to these patterns, reference this document and the specific decision:
|
||||
|
||||
```
|
||||
feat(tasks): implement feature X
|
||||
|
||||
Uses dueDay/dueWithTime mutual exclusivity pattern (ARCHITECTURE-DECISIONS.md #1)
|
||||
See: docs/ai/dueDay-dueWithTime-mutual-exclusivity.md
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue