Skip to Content
FeaturesTasksOverview

Tasks Feature Guide

Guide to the Tasks module — one-off and dated to-dos with due dates, scheduled dates, smart date filtering, subtasks, tags, reminders, and Eisenhower prioritization.

Overview

The Tasks module lets users create to-dos that are organized by three independent date fields — dueDateTime (a deadline), scheduledDateTime (do it on a specific day), and showInListFrom (when the task should start appearing in the list). The server performs smart filtering over these fields so a task surfaces in the right date range, including overdue scheduled tasks that are not yet done. Tasks support subtasks, tags, reminders, priority, and project association. Completion is a single boolean toggle (done) recorded with a doneDateTime, not a per-occurrence flag like Habits. The client uses a stale-while-revalidate cache and reacts to domain events so completing, rescheduling, or editing a task refreshes related screens automatically.

Architecture

TasksRepositoryImpl reads from the local Room cache first and revalidates from the server in the background, so the UI renders immediately and updates when fresh data arrives.

Data Models

The Task model also carries clearFields (a list of field names to explicitly null on PATCH) and subtasks (omitted/null = leave unchanged, empty list = clear all).

ReminderType Enum

ValueMeaning
NOTIFICATIONLocal/push notification (default)
EMAILEmail reminder
SMSSMS reminder

A task with no explicit Reminder row still gets a “task starting soon” push when its anchor (scheduledDateTime ?? dueDateTime) falls within UserSettings.defaultTaskReminderOffsetMinutes (default 15, 0 to disable). See Default reminder offsets.

SortOption (client TaskState)

ValueSorts by
EISENHOWEREisenhower matrix (urgency × importance) — default
DUE_DATEDue date
PRIORITYPriority value
NAMEName (alphabetical)
CREATEDCreated date

TaskFilters (date-range presets)

TODAY, THIS_WEEK, NEXT_WEEK, THIS_MONTH — each maps to a Pair<startDate, endDate> via getDateRangeByFilter().

API Endpoints

MethodPathDescription
GET/tasksList tasks (filter, limit/offset, date, withOverdue, tagSlug, projectId, sortOption, ignoreShowInListFrom, includeMeta)
GET/tasks/byDateRangeList tasks between startDate and endDate (no smart filtering)
GET/tasks/byDateRangeWithSmartFilteringSmart-filtered range list (withOverdue, currentDateTime, includeCompleted, includeUndated, returns virtual rows when includeMeta)
GET/tasks/noDueDateTasks with no dueDateTime; completions older than 7 days excluded
GET/tasks/{id}Get task detail
POST/tasksCreate task (CreateTaskDTO) — 201 Created
PATCH/tasks/{id}Update task (UpdateTaskDTO)
DELETE/tasks/{id}Delete task
PATCH/tasks/{id}/completeMark complete — datetime query param required and validated
PATCH/tasks/{id}/uncompleteUndo completion
PUT/tasks/{id}/tagsReplace all tags on a task (UpdateTaskTagsDTO)
POST/tasks/{id}/tags/{tagId}Attach a single tag
DELETE/tasks/{id}/tags/{tagId}Detach a single tag
POST/tasks/import/previewAI import preview (parse free text / tabular into tasks)
POST/tasks/importCommit AI-parsed task import
POST/tasks/tags/ai/previewAI tag-suggestion preview
POST/tasks/tags/ai/applyApply AI tag suggestions

All date/time parameters (date, startDate, endDate, datetime, currentDateTime) use the dd/MM/yyyy HH:mm format and are validated server-side (Validator.isValidDateTimeFormat). The X-Platform header (DESKTOP/MOBILE) gates feature flags used when building virtual task rows.

State Machine

Completion is a single done boolean (with a recorded doneDateTime) — unlike Habits, there is no per-occurrence completion. RescheduleTask moves whichever of showInListFrom, dueDateTime, and scheduledDateTime are set forward to tomorrow at the original time, leaving null fields null.

Client Behavior

TaskViewModel subscribes to the DomainEventBus and re-fetches on TaskCreated, TaskUpdated, TaskCompleted, TaskUncompleted, TaskDeleted, and TaskRescheduled. A fetch generation counter discards stale results when overlapping refreshes race.

Key Files

FilePurpose
shared/.../models/Task.ktTask, TaskSubtask, Reminder, ReminderType models
shared/.../models/Tag.ktTag / tag request models
shared/.../models/TaskFilters.ktDate-range filter presets (TODAY, THIS_WEEK, …)
shared/.../services/tasks/TaskService.ktKtor HTTP client for task endpoints
tasks/tasks_domain/.../repository/TasksRepository.ktRepository interface
tasks/tasks_domain/.../use_cases/TaskUseCases.ktAggregated use cases (get/add/complete/reschedule/…)
tasks/tasks_domain/.../use_cases/RescheduleTask.ktReschedule-to-tomorrow logic
tasks/tasks_data/.../repository/TasksRepositoryImpl.ktSWR repository (local Room + remote)
tasks/tasks_presentation/.../viewmodel/TaskViewModel.ktMVI ViewModel + event-bus refresh
tasks/tasks_presentation/.../viewmodel/state/TaskState.ktTaskState + SortOption
server/.../routing/TasksRouting.ktREST endpoints + date validation
server/.../service/TaskService.ktServer-side task logic / smart filtering

Testing

  • Unit: RescheduleTask — verify only non-null date fields shift to tomorrow at the original time; SortOption ordering (Eisenhower vs due date).
  • Server smart filtering: TaskSmartFilteringTest, TaskPendingVisibilityTestdueDate >= startDate inclusion, overdue scheduled tasks with withOverdue, and showInListFrom vs currentDateTime visibility window.
  • Import: TaskTextImportParserTest, TaskTabularImportParserTest, TaskImportDefaultDueTest, TaskReminderImportParseTest — AI/import parsing edge cases.
  • Integration: complete/uncomplete toggling; /tasks/noDueDate excluding completions older than 7 days.

Troubleshooting

Task not appearing for today

  • A dueDateTime task shows only if dueDateTime >= startDate; check the requested range.
  • If showInListFrom is set, the task stays hidden until showInListFrom <= min(currentDateTime, endDate 23:59) — send currentDateTime so same-day windows behave correctly.
  • A scheduledDateTime task only shows on that date unless it is overdue, not done, and withOverdue=true.

Overdue scheduled task missing

  • Overdue scheduled tasks require withOverdue=true (the default). If “hide overdue” is on, they are suppressed.

Complete request returns 400

  • The datetime query param is required on PATCH /tasks/{id}/complete and must match dd/MM/yyyy HH:mm; an invalid or missing value returns 400.

Edited task field not clearing

  • On PATCH, a null/omitted field is left unchanged. To explicitly null a field, include its name in clearFields. For subtasks, send an empty list to clear all.

Stale list after completing/editing

  • Refresh is driven by DomainEventBus events; if a screen does not update, confirm it subscribes to the relevant DomainEvent.Task* event. The SWR cache may briefly show local data before the server revalidation completes.

API Endpoints

All endpoints require JWT authentication and are prefixed with /api/v1. See server/README.md for full reference.

MethodPathDescription
GET/tasksList tasks (filterable by date, tagSlug, projectId, sortOption)
GET/tasks/byDateRangeList tasks in a date range
GET/tasks/noDueDateList tasks with no due date
POST/tasksCreate a task
POST/tasks/import/previewPreview AI-powered task import from text
POST/tasks/importImport tasks via AI from natural language
POST/tasks/tags/ai/previewPreview AI-suggested tags
POST/tasks/tags/ai/applyApply AI-suggested tags
GET/tasks/{id}Get task by ID
PATCH/tasks/{id}Update task
DELETE/tasks/{id}Delete task
PATCH/tasks/{id}/completeMark task as complete
PATCH/tasks/{id}/uncompleteMark task as incomplete
PUT/tasks/{id}/tagsReplace all tags on a task
  • Task logic — server-side smart filtering algorithm (dueDate, scheduledDate, showInListFrom, withOverdue)
  • Habits — recurrence and per-occurrence completion (contrast with Tasks)
  • Calendar — how task dates map onto calendar days
  • Domain & models — shared domain model reference
  • UI & UX — task screen layouts and interactions
  • Testing & QA — testing strategy