ARCHITECTURE-DECISIONS.md
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.
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:
Implementation:
dueDay when setting dueWithTime (in meta-reducers)dueWithTime first; only check dueDay if dueWithTime is not set (in selectors)Key Files:
task.model.ts - Field definitions with JSDoctask-shared-scheduling.reducer.ts - Write implementationwork-context.selectors.ts - Read patternplanner.selectors.ts - Read patterntask.selectors.ts - Read patternWhen to Update This 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:
Related: Uses the dueDay/dueWithTime mutual exclusivity pattern (Decision #1)
Key Files:
tag.const.ts - TODAY_TAG definitionwork-context.selectors.ts - Membership computationtask-shared-helpers.ts - Invariant enforcementWhen to Update This Pattern:
Status: ✅ Active (since May 2026)
Decision: Operation-log sync code is split by dependency direction:
src/app composes host-specific wiring, @sp/sync-providers owns bundled
provider implementations, and @sp/sync-core owns framework-agnostic reusable
sync primitives.
Rationale:
Implementation:
@sp/sync-core has no runtime dependencies and owns vector-clock algorithms
used by client/server compatibility pathspackages/shared-schema compatibility-re-exports generic vector-clock
algorithms from @sp/sync-core; @sp/sync-core must not import
@sp/shared-schema@sp/sync-providers depends on public @sp/sync-core plus provider runtime
helpers, while app factories inject credentials, platform bridges, validators,
OAuth routing, and configDocumentation: docs/sync-and-op-log/package-boundaries.md
Key Files:
packages/sync-core/src/index.ts - Core public APIpackages/sync-providers/src/index.ts - Provider public APIeslint.config.js - Package boundary enforcementsrc/app/op-log/sync-providers/sync-providers.factory.ts - App-side provider compositionWhen to Update This Pattern:
Status: ✅ Active (since May 2026)
Decision: SuperSync batch uploads derive conflict-safety from the shared
user_sync_state.lastSeq row write that reserves server sequence numbers, not
from PostgreSQL RepeatableRead snapshot isolation alone.
Rationale:
user_sync_state.lastSeq row forces
accepted writers for the same user to serialize on that row lockImplementation:
INSERT ... ON CONFLICT ... DO UPDATE SET last_seq = last_seq + deltaskipDuplicates; an unexpected unique conflict
aborts the transaction and lets the request retrylastSeq write requires replacing this safety
mechanism with an equivalent per-user serialization primitiveDocumentation: docs/sync-and-op-log/diagrams/02-server-sync.md
Key Files:
packages/super-sync-server/src/sync/sync.service.ts - Upload transaction and batch primitivepackages/super-sync-server/prisma/schema.prisma - user_sync_state.last_seqWhen to Update This Pattern:
Add a new decision record when:
### 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]
docs/sync-and-op-log/ - Operation log architecturedocs/long-term-plans/ - Future architectural plansWhen 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)