Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.wellapp.ai/llms.txt

Use this file to discover all available pages before exploring further.

A Task represents a discrete unit of work within a workspace — it can be user-created, agent-created, or system-seeded as part of an onboarding or provider-scoring pipeline. Tasks belong to a single workspace, may be assigned to a Person, and may form a parent-child hierarchy (a task may have one parent task and many subtasks). They carry a rich status lifecycle, typed enums for executor and source, optional plan/step/scoring/subworkspace-candidate metadata in a JSONB field, and a polymorphic references array that links them to invoices, companies, people, documents, transactions, providers, or calendar months.
NamingValue
ObjectTask
Resource type (JSON:API type)task
Collection / records roottasks
REST base/v1/tasks
Entity classTask

API operations

OperationMethod & pathStatus
ListGET /v1/tasks✅ Implemented
RetrieveGET /v1/tasks/{id}✅ Implemented
CreatePOST /v1/tasks🟡 Planned
UpdatePATCH /v1/tasks/{id}🟡 Planned
DeleteDELETE /v1/tasks/{id}🟡 Planned

Data model

Attributes

FieldTypeRequiredConstraintsAllowed valuesDescription
task_idstring, UUID, system✅ Yesunique; generated by gen_random_uuid() on INSERTPublic stable identifier for the task. Never changes after creation.
titlestring✅ Yestext; no length limit enforced at DB levelShort human-readable label for the task, shown in the UI and chat cards.
descriptionstring⚪ Notext; nullableOptional longer prose explanation of what the task requires and why.
statusstring (enum)✅ Yesdefault = ‘open’; backed by native PG enum task_status_enum; partial unique index uniq_tasks_active_provider_company fires only on status IN (‘open’,‘ice_log’,‘blocked’)ice_log, open, in_progress, done, blocked, cancelled, archivedLifecycle state of the task. ice_log = surfaced but not yet actionable; archived = closed but kept for audit.
executor_typestring (enum)✅ YesNOT NULL; backed by native PG enum executor_type_enumhuman, systemWhether the task is intended for a human actor or executed entirely by the system/agent pipeline.
sourcestring (enum)✅ Yesdefault = ‘user’; backed by native PG enum task_source_enumuser, agentWhether the task was created by a human user or autonomously by an AI agent.
prioritystring (enum)⚪ Nonullable; default = ‘medium’; backed by native PG enum task_priority_enumlow, medium, high, criticalUrgency level of the task, used to sort and filter the task list in the UI.
confidence_scorenumber (decimal)⚪ Nonullable; columnType numeric(3,2); range 0.00-1.00Agent-assigned confidence that the task is relevant and actionable for this workspace. Higher means more certain.
token_rewardinteger⚪ Nonullable; integerGamification reward tokens awarded to the user upon completing this task. Sourced from the associated TaskTemplate or set by the pipeline.
due_datedatetime⚪ Nonullable; no DB-level CHECKOptional deadline after which the task is considered overdue. Displayed in the task card and used for sorting.
visible_datedatetime⚪ Nonullable; no DB-level CHECKDate before which the task should not be surfaced to the user (deferred visibility). Used by the scoring pipeline to schedule tasks for future monthly-close cycles.
referencesjsonb (array of TaskReference objects)✅ Yesdefaults to []; GIN index idx_tasks_references_gin (jsonb_path_ops) for fast dedup lookupsArray of { type: invoice|company|person|document|transaction|provider|month, id: string, label: string }Polymorphic reference list linking the task to one or more domain entities. Drives context in the chat card and CTA routing. The first provider-typed entry is denormalized into provider_ref_id; the first company-typed entry into company_ref_id.
provider_ref_idstring⚪ Nonullable; varchar(36); denormalized from references[0 where type=‘provider’].id; participates in partial unique index uniq_tasks_active_provider_company on (workspace_pk, provider_ref_id, company_ref_id) WHERE deleted_at IS NULL AND status IN (‘open’,‘ice_log’,‘blocked’) AND both ref_ids NOT NULL AND parent_task_pk IS NULLDenormalized first provider reference id extracted from the references array. Populated at task creation by TaskService.createTask. Enables O(1) dedup guard preventing duplicate root scoring tasks for the same workspace x provider x company triplet.
company_ref_idstring⚪ Nonullable; varchar(36); denormalized from references[0 where type=‘company’].id; co-participant in partial unique index uniq_tasks_active_provider_companyDenormalized first company reference id extracted from the references array. Populated at task creation by TaskService.createTask alongside provider_ref_id.
historyjsonb (array of TaskHistoryEntry objects)✅ Yesdefaults to []Array of { action: created|status_changed|assigned|comment, at: ISO8601, by?: string, by_type: human|system, from?: string, to?: string, detail?: string }Append-only audit log of state transitions and comments on this task. Each entry records who did what and when.
plan_metajsonb (discriminated union on ‘kind’)⚪ Nonullable. Partial unique index uq_tasks_subworkspace_candidate_dedup on (workspace_pk, plan_meta->>‘dedup_key’) WHERE deleted_at IS NULL AND plan_meta->>‘kind’ = ‘subworkspace-candidate’ AND plan_meta->>‘dedup_key’ IS NOT NULL.kind: plan | step | scoring | mail-connect | connect-extension | connect-tools-parent | subworkspace-candidateOptional metadata blob whose shape is discriminated by the ‘kind’ field. plan = agentic plan phases. step = individual step within a plan. scoring = provider-scoring signals and CTA route. mail-connect = connect-email fallback gate. connect-extension = Chrome extension install sub-task. connect-tools-parent = lazy parent for provider-connection subtasks. subworkspace-candidate = WAS-projection, detection signals, and dedup_key for child workspace discovery.
scorenumber (decimal)⚪ Nonullable; columnType numeric(8,2)Computed relevance or urgency score assigned by the scoring pipeline (0-1000+ scale). Used to order tasks in the UI surface.
done_atdatetime⚪ Nonullable; no DB trigger; set by service layerTimestamp when the task transitioned to status=done. Set by the service layer on completion.
conversation_thread_idstring, UUID⚪ Nonullable; UuidType; soft reference only (no FK constraint)UUID of the chat conversation thread associated with this task. Allows the AI to link back to the thread context. No FK cascade — deleting the conversation does not affect the task.
created_atdatetime, system✅ Yesset on INSERT via MikroORM onCreate lifecycle; not nullableTimestamp when the task row was created.
updated_atdatetime, system⚪ Noset on INSERT (onCreate) and updated on every UPDATE (onUpdate) via MikroORM lifecycleTimestamp of the last modification to this task row.
deleted_atdatetime, system⚪ Nonullable; soft-delete sentinel; all active queries filter deleted_at IS NULL; both partial unique indexes include deleted_at IS NULL in their WHERE clause so hard-deletes release dedup slotsSoft-delete timestamp. When set, the task is logically deleted and excluded from all active queries.

Relationships

NameTypeRequiredDescription
workspaceto-one (workspace)✅ YesThe workspace this task belongs to. deleteRule = ‘cascade’ — deleting the workspace hard-deletes all its tasks. Every query must scope to this relationship. Composite index idx_tasks_workspace_status covers (workspace_pk, status) for efficient status-filtered list queries.
templateto-one (task_template)⚪ NoOptional reference to the TaskTemplate that spawned or defines this task (title, markdown content, action type, token reward). deleteRule = ‘set null’ — deleting a template leaves tasks intact but unlinked. Template-less tasks are common for agent-generated or platform-seeded rows.
parent_taskto-one (task)⚪ NoSelf-referential parent for hierarchical task trees. A root task has parent_task = null. deleteRule = ‘set null’ — deleting a parent orphans its children rather than cascade-deleting them. The partial unique index uniq_tasks_active_provider_company only applies to root tasks (parent_task_pk IS NULL).
subtasksto-many (task)Inverse of parent_task. Collection of child tasks nested under this task. The composite composite_subtasks_list (display_type: relation_list, sort_proxy: subtasks_aggregate.min.created_at) in composites.yml surfaces subtask task_id, title, status, and due_date as a relation_list cell in the records table.
assigned_toto-one (people)⚪ NoThe Person to whom the task is assigned for action. deleteRule = ‘set null’. The composite assigned_to.composite_avatar_fullname (display_type: people_avatar_name) in composites.yml surfaces person_id, avatar URL, and full_name as a composite cell in the records table.
created_byto-one (people)⚪ NoThe Person who created the task, when created by a human. Null for agent-created or system-seeded tasks. deleteRule = ‘set null’.

System-computed

  • task_id is generated by gen_random_uuid() at INSERT via MikroORM defaultRaw; unique constraint enforced at DB level.
  • created_at is set by MikroORM onCreate lifecycle hook to new Date(); never subsequently updated.
  • updated_at is set by MikroORM onCreate and refreshed on every UPDATE via onUpdate lifecycle hook.
  • deleted_at is the soft-delete sentinel. All active queries must filter deleted_at IS NULL. Both partial unique indexes (uniq_tasks_active_provider_company and uq_tasks_subworkspace_candidate_dedup) include deleted_at IS NULL so hard-deleting a row releases its dedup slot.
  • status defaults to ‘open’ (TaskStatusEnum.OPEN) at entity construction; the native PG enum task_status_enum enforces allowed values at the DB level.
  • source defaults to ‘user’ (TaskSourceEnum.USER); overridden to ‘agent’ by the scoring and onboarding pipelines.
  • priority defaults to ‘medium’ (TaskPriorityEnum.MEDIUM); nullable so it can be intentionally unset.
  • references defaults to [] (empty array). The first provider-typed entry is extracted to provider_ref_id and the first company-typed entry to company_ref_id by TaskService.createTask. These two denormalized columns must stay in sync with the references array via service-layer discipline (no DB trigger enforces this).
  • history defaults to [] (empty array). Entries are appended by the service layer on every state transition (status_changed, assigned, comment). No DB trigger; the service is the sole writer.
  • Partial unique index uniq_tasks_active_provider_company on (workspace_pk, provider_ref_id, company_ref_id) WHERE deleted_at IS NULL AND status IN (‘open’,‘ice_log’,‘blocked’) AND provider_ref_id IS NOT NULL AND company_ref_id IS NOT NULL AND parent_task_pk IS NULL. Closes the concurrent-worker dedup race for root scoring tasks. Sub-tasks (parent_task_pk IS NOT NULL) are excluded by design.
  • Partial unique index uq_tasks_subworkspace_candidate_dedup on (workspace_pk, (plan_meta->>‘dedup_key’)) WHERE deleted_at IS NULL AND plan_meta->>‘kind’ = ‘subworkspace-candidate’ AND plan_meta->>‘dedup_key’ IS NOT NULL. Prevents re-emission of duplicate subworkspace-candidate tasks for the same canonical identity. CANCELLED rows are still covered; only hard-deleted rows release the slot.
  • Composite index idx_tasks_workspace_status on (workspace_pk, status) for efficient status-filtered workspace list queries.
  • GIN index idx_tasks_references_gin on references JSONB column (jsonb_path_ops) for fast reference-type filter and dedup lookups.
  • plan_meta is a discriminated-union JSONB blob. The ‘kind’ discriminant determines the valid shape. The rendering layer narrows on plan_meta.kind to select the correct chat card or CTA component.
  • done_at is set by the service layer when transitioning status to ‘done’; it is not a DB-generated column.
  • conversation_thread_id is a soft UUID reference to a ChatConversation; there is no FK constraint so deleting the conversation does not affect the task.

Example

{
  "data": {
    "type": "task",
    "id": "d4f1c7b2-3a9e-4f08-91c3-8e20b5f6a012",
    "attributes": {
      "title": "Connect Stripe to import missing invoices",
      "description": "We detected 14 open transactions from Stripe that have no matching invoice. Connect the Stripe provider to auto-import them.",
      "status": "open",
      "executor_type": "human",
      "source": "agent",
      "priority": "high",
      "confidence_score": "0.88",
      "token_reward": "50",
      "due_date": "2026-06-15T00:00:00.000Z",
      "visible_date": "2026-06-01T00:00:00.000Z",
      "score": "940.00",
      "done_at": null,
      "conversation_thread_id": null,
      "provider_ref_id": "a3f8c1d2-1111-4b0c-9abc-000000000001",
      "company_ref_id": "b7e2a5c4-2222-4c1d-8def-000000000002",
      "references": [
        { "type": "provider", "id": "a3f8c1d2-1111-4b0c-9abc-000000000001", "label": "Stripe" },
        { "type": "company",  "id": "b7e2a5c4-2222-4c1d-8def-000000000002", "label": "Stripe Payments Europe Ltd" }
      ],
      "history": [
        { "action": "created", "at": "2026-06-02T08:30:00.000Z", "by": null, "by_type": "system" },
        { "action": "assigned", "at": "2026-06-02T09:00:00.000Z", "by": "usr_human_01", "by_type": "human", "to": "Alice Martin" }
      ],
      "plan_meta": {
        "kind": "scoring",
        "signals": { "open_transactions": 14, "total_amount_eur": 12800, "dominant_currency": "EUR" },
        "route": { "action_type": "connect_provider" }
      },
      "created_at": "2026-06-02T08:30:00.000Z",
      "updated_at": "2026-06-02T09:00:00.000Z",
      "deleted_at": null
    },
    "relationships": {
      "workspace": { "data": { "type": "workspace", "id": "9f3a4b7c-0001-4e2a-b000-aabbccddeeff" } },
      "template": { "data": null },
      "parent_task": { "data": null },
      "subtasks": { "data": [] },
      "assigned_to": { "data": { "type": "people", "id": "c8d1f9e0-3333-4d2e-9e00-000000000003" } },
      "created_by": { "data": null }
    }
  }
}
Source: apps/api/src/database/entities/Task.ts · domain: workspace · tier: Activity