mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-18 00:46:45 +00:00
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.
135 lines
4.6 KiB
Markdown
135 lines
4.6 KiB
Markdown
# 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)
|
|
|
|
**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)
|
|
|
|
**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/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)
|
|
```
|