| task_id | string, UUID, system | ✅ Yes | unique; generated by gen_random_uuid() on INSERT | — | Public stable identifier for the task. Never changes after creation. |
| title | string | ✅ Yes | text; no length limit enforced at DB level | — | Short human-readable label for the task, shown in the UI and chat cards. |
| description | string | ⚪ No | text; nullable | — | Optional longer prose explanation of what the task requires and why. |
| status | string (enum) | ✅ Yes | default = ‘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, archived | Lifecycle state of the task. ice_log = surfaced but not yet actionable; archived = closed but kept for audit. |
| executor_type | string (enum) | ✅ Yes | NOT NULL; backed by native PG enum executor_type_enum | human, system | Whether the task is intended for a human actor or executed entirely by the system/agent pipeline. |
| source | string (enum) | ✅ Yes | default = ‘user’; backed by native PG enum task_source_enum | user, agent | Whether the task was created by a human user or autonomously by an AI agent. |
| priority | string (enum) | ⚪ No | nullable; default = ‘medium’; backed by native PG enum task_priority_enum | low, medium, high, critical | Urgency level of the task, used to sort and filter the task list in the UI. |
| confidence_score | number (decimal) | ⚪ No | nullable; columnType numeric(3,2); range 0.00-1.00 | — | Agent-assigned confidence that the task is relevant and actionable for this workspace. Higher means more certain. |
| token_reward | integer | ⚪ No | nullable; integer | — | Gamification reward tokens awarded to the user upon completing this task. Sourced from the associated TaskTemplate or set by the pipeline. |
| due_date | datetime | ⚪ No | nullable; no DB-level CHECK | — | Optional deadline after which the task is considered overdue. Displayed in the task card and used for sorting. |
| visible_date | datetime | ⚪ No | nullable; no DB-level CHECK | — | Date 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. |
| references | jsonb (array of TaskReference objects) | ✅ Yes | defaults to []; GIN index idx_tasks_references_gin (jsonb_path_ops) for fast dedup lookups | Array 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_id | string | ⚪ No | nullable; 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 NULL | — | Denormalized 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_id | string | ⚪ No | nullable; varchar(36); denormalized from references[0 where type=‘company’].id; co-participant in partial unique index uniq_tasks_active_provider_company | — | Denormalized first company reference id extracted from the references array. Populated at task creation by TaskService.createTask alongside provider_ref_id. |
| history | jsonb (array of TaskHistoryEntry objects) | ✅ Yes | defaults 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_meta | jsonb (discriminated union on ‘kind’) | ⚪ No | nullable. 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-candidate | Optional 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. |
| score | number (decimal) | ⚪ No | nullable; 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_at | datetime | ⚪ No | nullable; no DB trigger; set by service layer | — | Timestamp when the task transitioned to status=done. Set by the service layer on completion. |
| conversation_thread_id | string, UUID | ⚪ No | nullable; 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_at | datetime, system | ✅ Yes | set on INSERT via MikroORM onCreate lifecycle; not nullable | — | Timestamp when the task row was created. |
| updated_at | datetime, system | ⚪ No | set on INSERT (onCreate) and updated on every UPDATE (onUpdate) via MikroORM lifecycle | — | Timestamp of the last modification to this task row. |
| deleted_at | datetime, system | ⚪ No | nullable; 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 slots | — | Soft-delete timestamp. When set, the task is logically deleted and excluded from all active queries. |