Key tables
Tasks: task definitions (relativeCost, duration, body/mind weights, timing fields, essential flag, and default details copy).
TaskOccurrences: canonical per-instance schedule and state rows (dueDatetime, completion/cancellation/deferral, per-instance edits). For recurring tasks, due slots are generated at runtime from the task rule and matched against persisted rows.
CheckIns: daily body/mind/mood ratings, check-in tier, day-type classification.
Events: append-only audit log; source of truth for rebuilding derived state.
manaCost is not stored as source-of-truth. It is computed at read time from task properties and today’s axis factor.
Key fields
| Table | Field | Type | Notes |
|---|
| Task | details | string? | default details/instructions for this task |
| Task | relativeCost | double | effort relative to baseline |
| Task | isEssential | bool | user-controlled |
| Task | timingType | enum | none, deadline, scheduled |
| Task | recurrenceRule | string? | RFC 5545 RRule |
| TaskOccurrence | id | int | auto-increment local surrogate ID |
| TaskOccurrence | taskId | string | FK to task definition (Tasks.id) |
| TaskOccurrence | dueDatetime | datetime | canonical due timestamp for this instance |
| TaskOccurrence | details | string? | per-instance override; if null, UI can use Task.details |
| CheckIn | checkInDate | datetime | local calendar day identity, normalized to local midnight |
| CheckIn | checkInTier | enum | full, quick, momentum, none with confidence weights 1.0, 0.7, 0.4, 0.1 |
| CheckIn | dayType | enum | normal, packed, blocked, unusual; carries opportunity weights 1.0, 0.25, 0.0, 0.0 |
| UserProfile | lastCheckInDate | datetime | absence detection |
| UserProfile | returnRecoveryDaysRemaining | int | 3-step return recovery |
| PemEvent | attributionConfidence | double | 0.4-1.0 window-based |
| PemEvent | userAttributedTrigger | string? | optional user attribution |
| PersonalTaskEntry | observedHRResponse | JSON? | reserved for wearable integration |
Storage model
- Encrypted local SQLite via Drift + SQLCipher
- No remote DB, no cloud sync
- Offline-first behavior
- Encryption key in platform keystore (not cloud backed up)
Settings and feature flags are in shared_preferences and persist across health-data reset.
Runtime recurrence query
dueSlots = generateFromRRule(task.recurrenceRule, queryStart, queryEnd)
occurrences = merge(dueSlots, TaskOccurrences.persistedRows)
activeOccurrence = nearest unresolved future dueDatetime
Recurrence parsing contract
- Stored recurrence input may be either:
- a full content line (
RRULE:FREQ=...)
- or a bare rule value (
FREQ=...)
- If
DTSTART exists in the stored string, it is used as the recurrence anchor.
- If
DTSTART is absent, the anchor defaults to Task.createdAt.
- Line parsing splits on both Unix and Windows line endings (
\\n, \\r\\n).
- Implementation detail: the parser uses regex pattern
[\\r\\n]+ to split lines.
\\r matches carriage return, \\n matches newline, + collapses one-or-more line break chars into one separator.
- Example:
DTSTART:...\\r\\nRRULE:... and DTSTART:...\\n\\nRRULE:... both split into the same two logical lines.
- Invalid recurrence strings fail soft:
- no generated slots are returned
- a typed warning is emitted by the recurrence service
Example:
DTSTART:20260310T090000
RRULE:FREQ=DAILY;COUNT=2
Generates:
2026-03-10 09:00
2026-03-11 09:00
Derived status contract
missed is derived at read time in domain scheduling logic.
missed is not persisted in TaskOccurrences.
deferredUntil shifts an occurrence’s effective due time used by scheduling.
Read next