Skip to main content
All Docs
FeaturesPurple PepperUpdated April 7, 2026

Todos & Tasks

Todos & Tasks

The Todo & Task system lets you create, assign, and track tasks against tenancies and tenancy terms. Tasks can be scoped to a specific role (agent, tenant, or landlord), categorised by type, prioritised, and tracked through completion — with a portfolio-wide view for outstanding work.


Concepts

Task Types

Every todo has a taskType that categorises it:

ValueDescription
cost_breakdown_signTenant or landlord needs to sign a cost breakdown
holding_deposit_payTenant needs to pay the holding deposit
tenancy_agreement_signTenancy agreement needs to be signed
compliance_docA compliance document needs to be uploaded
customA freeform task not covered by the above types

The default task type is custom.

Role Assignment (assignedTo)

Each todo is assigned to a role:

  • agent — an internal team member (default)
  • tenant — the tenant party
  • landlord — the landlord party

Optionally, a specific user ID (assignedUserId) can be set to target an individual agent.

Status & Completion

Todos have a status field (pending | complete) and a boolean isComplete flag. When a todo is marked complete, the platform records:

  • completedAt — the timestamp
  • completedByUserId — the user who performed the action

Completion can be reversed using the reopenTodo procedure.

Priority

Four priority levels are supported: low, normal (default), high, urgent.

Scoping

A todo must be scoped to at least one of:

  • tenancyId — links the task to a tenancy
  • tenancyTermId — links the task to a specific tenancy term

Both can be provided simultaneously. The platform validates that the referenced tenancy or term belongs to your organisation before creating the todo.


tRPC Procedures

All procedures are accessed via the todo router and require an authenticated org session.

todo.createTodo

Create a new todo.

Input:

{
  tenancyId?: string;        // Required if tenancyTermId not provided
  tenancyTermId?: string;    // Required if tenancyId not provided
  title: string;             // 1–500 characters
  description?: string;      // Up to 2,000 characters
  taskType?: TaskType;       // Default: "custom"
  assignedTo?: Role;         // Default: "agent"
  assignedUserId?: string;   // Specific agent user ID (optional)
  priority?: Priority;       // Default: "normal"
  dueDate?: string;          // ISO 8601 datetime string
  propertyAddress?: string;  // Up to 500 characters
  tenantName?: string;       // Up to 200 characters
}

Returns: The created todo record.

Audit event: todo.created


todo.markTodoComplete

Mark a todo as complete. Throws if the todo is already complete.

Input:

{ todoId: string }

Returns: The updated todo record.

Audit event: todo.completed


todo.reopenTodo

Undo completion of a todo. Resets isComplete, completedAt, and completedByUserId. Throws if the todo is not complete.

Input:

{ todoId: string }

Returns: The updated todo record.

Audit event: todo.reopened


todo.getById

Fetch a single todo by ID.

Input:

{ todoId: string }

Returns: The todo record, or a NOT_FOUND error.


todo.listByTenancy

List todos scoped to a tenancy or tenancy term. Results are ordered: incomplete items first (ascending due date), then complete items.

Input:

{
  tenancyId?: string;
  tenancyTermId?: string;
  includeComplete?: boolean; // Default: false
}

Returns: Array of todo records.


todo.listOutstandingAcrossPortfolio

Paginated list of all incomplete todos across the entire portfolio, sorted by due date (most urgent first). Supports filtering by role, task type, and assigned user.

Input:

{
  // Pagination
  page?: number;
  limit?: number;
  // Filters
  assignedTo?: Role;       // "agent" | "tenant" | "landlord"
  taskType?: TaskType;
  assignedUserId?: string;
}

Returns: Paginated result with todo records.

Note: propertyAddress and tenantName are denormalised onto each todo record to support efficient display in this portfolio-wide view without joins.


todo.applyDefaultTemplates

Reads the company's default todo templates from companySettings.defaultTodoTemplates (JSONB) and bulk-creates todos for a given tenancy. Use this when creating a new tenancy term to bootstrap the standard task list.

Input:

{
  tenancyId: string;
  tenancyTermId?: string;
  propertyAddress?: string;
  tenantName?: string;
}

Returns: Array of created todo records.


todo.updateTodo

Update todo details. Only the fields you provide will be changed.

Updatable fields: title, description, priority, assignedTo, assignedUserId, dueDate, taskType

Input:

{
  todoId: string;
  title?: string;
  description?: string;
  priority?: Priority;
  assignedTo?: Role;
  assignedUserId?: string;
  dueDate?: string;
  taskType?: TaskType;
}

Returns: The updated todo record.


todo.deleteTodo

Permanently delete a todo. Only incomplete todos can be deleted.

Input:

{ todoId: string }

Returns: Confirmation of deletion.


Default Todo Templates

You can define a standard set of tasks to be created automatically when a new tenancy term is set up. Templates are stored in companySettings.defaultTodoTemplates as a JSONB array. Call todo.applyDefaultTemplates with the new tenancy's IDs to instantiate the template list.

This is useful for enforcing a consistent pre-tenancy pipeline (e.g. always creating tasks for cost breakdown sign-off, holding deposit payment, and compliance document upload).


Audit Logging

All state-changing operations are recorded in the audit trail:

ActionTrigger
todo.createdcreateTodo
todo.completedmarkTodoComplete
todo.reopenedreopenTodo

Each audit event captures the acting user, the todo ID, task type, and associated tenancy identifiers.


Type Reference

type TaskType =
  | "cost_breakdown_sign"
  | "holding_deposit_pay"
  | "tenancy_agreement_sign"
  | "compliance_doc"
  | "custom";

type Role = "agent" | "tenant" | "landlord";

type Priority = "low" | "normal" | "high" | "urgent";

type Status = "pending" | "complete";