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.

EnrichmentTask is the durable work-item record for Well’s asynchronous enrichment pipeline. Each row represents one unit of background AI or data-processing work — logo resolution, AI company/people/invoice extraction, OCR, bank-sync reconciliation, provider scoring, custom column compute, field rule evaluation, or monthly invoice closure — targeted at an arbitrary entity identified by the polymorphic (entity_type, entity_id) pair. Tasks are scoped to a Workspace, can be grouped into a batch_id (one Magic-button press), and support parent/subtask nesting via a self-referencing parent_task relationship. The enrichment pipeline writes and advances all lifecycle states; users and operators observe tasks read-only.
NamingValue
ObjectEnrichmentTask
Resource type (JSON:API type)enrichment_task
Collection / records root(not a records root)
REST base/v1/enrichment-tasks
Entity classEnrichmentTask
Internal object. Not currently exposed on the public REST API. The operations below describe the intended contract.

API operations

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

Data model

Attributes

FieldTypeRequiredConstraintsAllowed valuesDescription
enrichment_task_idUUID (🔒 system)✅ YesUNIQUEPublic stable identifier. Auto-generated by gen_random_uuid() at insert. This is the id exposed in JSON:API responses; the internal pk is never surfaced.
entity_typestring (varchar 100)✅ Yesmax 100 chars; NOT NULL; composite index with entity_id (enrichment_tasks_entity_idx)Polymorphic discriminator identifying the kind of entity this task targets (e.g. company, person, invoice, document, transaction). Pairs with entity_id to form the generic entity reference introduced in Migration20260323100000 to replace per-type FK columns.
entity_idstring (varchar 255)✅ Yesmax 255 chars; NOT NULL; composite index with entity_type; partial unique index on (entity_type, entity_id, enrichment_type) WHERE status = 'pending' AND deleted_at IS NULL AND enrichment_type = 'monthly_close' enforces one active monthly_close task per target monthPublic UUID of the target entity (the *_id column of the referenced row, e.g. company_id, person_id, invoice_id). Stored as a string to support multiple entity types without per-type FK constraints. Composite index with entity_type.
statusenum (🔒 system) — native Postgres type enrichment_task_status_enum✅ YesDEFAULT ‘pending’; NOT NULLpending | processing | completed | awaiting_approval | failed | rejectedLifecycle state of the enrichment task. Default pending. Transitions are driven exclusively by the enrichment pipeline workers; users cannot write this field.
enrichment_typestring (text) — backed by Postgres type enrichment_type_enum historically but stored as text on the column✅ YesNOT NULLlogo | ai_company | ai_people | ai_invoice | ocr_extract | reconcile | provider_score | document_reconciliation_backfill | monthly_close | monthly_close_backfill | custom_column | field_ruleIdentifies the enrichment worker that should process this task. Determines which Cloud Tasks handler is dispatched. See EnrichmentTypeEnum for the full controlled vocabulary.
inputjsonb⚪ NonullableWorker input payload. Shape is worker-specific. For monthly_close the dedup key is input->>'record_id' (month label); a JSONB expression partial index (idx_enrichment_tasks_input_record_id) covers lookups on that path within a workspace + status window.
outputjsonb⚪ NonullableWorker output payload written on task completion. Shape is worker-specific. For monthly_close_backfill, holds aggregate fan-out counts and request parameters.
target_fieldsjsonb (string[])⚪ NonullableOptional list of field names the enrichment worker should populate or re-evaluate. Used by custom_column and field_rule workers to scope work to a subset of columns.
errortext⚪ NonullableError message or stack trace written by the worker when the task transitions to failed. Null on success.
source_channelenum — native Postgres type source_channel_enum⚪ Nonullablecompany_create | person_create | document_upload | ocr_completion | bank_sync | email_import | mcp_hub | cell_edit | manualRecords which product surface triggered the task. Used for attribution and observability. Added in Migration20260319120000.
input_hashtext⚪ Nonullable; index enrichment_tasks_input_hash_idxDeduplication fingerprint of the input payload. Allows workers to detect duplicate enqueues with identical inputs and skip redundant work. Added in Migration20260319120000.
descriptiontext⚪ NonullableHuman-readable markdown summary of the enrichment task, populated by the worker or the pipeline orchestrator for display in the UI. Added in Migration20260327100000.
batch_idUUID⚪ Nonullable; index enrichment_tasks_batch_id_idx; composite index idx_enrichment_tasks_batch_status on (batch_id, status)Groups tasks triggered by a single user action (Magic button press). All tasks sharing a batch_id were enqueued together and can be tracked collectively. Index idx_enrichment_tasks_batch_status covers hot-path batch completion detection. Added in Migration20260327100000.
created_attimestamptz (🔒 system)✅ YesNOT NULL; set once on insertRow creation timestamp set by MikroORM onCreate hook. Not writable after insert.
updated_attimestamptz (🔒 system)⚪ Nonullable; updated on every writeLast modification timestamp, maintained automatically by MikroORM onUpdate hook on every flush.
deleted_attimestamptz⚪ NonullableSoft-delete timestamp. When set the row is logically deleted and filtered out of standard queries. The partial unique index on monthly_close tasks is scoped to deleted_at IS NULL.
completed_attimestamptz⚪ NonullableTimestamp written by the worker when the task reaches completed, failed, or rejected. Distinct from updated_at to allow precise pipeline latency measurement.

Relationships

NameTypeRequiredDescription
workspaceto-one (ManyToOne)✅ YesThe workspace that owns this enrichment task. All task queries are tenant-scoped via this relationship. deleteRule: cascade — deleting a workspace removes all its tasks. FK column workspace_pk.
parent_taskto-one (ManyToOne, self-referencing)⚪ NoOptional reference to a parent EnrichmentTask. Used by the Monthly Invoice Closure pipeline to link per-counterparty sub-tasks to their macro parent task. FK column parent_task_pk. deleteRule: set null — deleting a parent task nullifies the FK on children without cascading deletion. Added in Migration20260327100000.
subtasksto-many (OneToMany, self-referencing)Inverse collection of child EnrichmentTask rows that reference this task as their parent_task. Populated for macro tasks in the Monthly Invoice Closure pipeline. Mapped by parent_task on the child side.

System-computed

  • enrichment_task_id — auto-generated by gen_random_uuid() Postgres default at INSERT; never set by application code
  • created_at — set by MikroORM onCreate hook; never writable after insert
  • updated_at — set and maintained by MikroORM onUpdate hook on every flush
  • deleted_at — soft-delete; set by the pipeline or admin tooling, never by user PATCH
  • status — default ‘pending’ at creation; all state transitions (pending → processing → completed / failed / rejected / awaiting_approval) are driven exclusively by enrichment pipeline workers via Cloud Tasks handlers
  • input_hash — computed by the enqueuing service as a fingerprint of the input payload for dedup detection; not computed by the database
  • batch_id — assigned at enqueue time by the orchestrator when multiple tasks are triggered together (Magic button); not user-assignable
  • completed_at — written by the worker on task terminal state; not set by application business logic outside the worker
  • entity_type / entity_id — set at enqueue time from the triggering entity’s public UUID; the generic polymorphic reference replaced per-type FK columns (company_pk, person_pk, document_pk, invoice_pk, transaction_pk) in Migration20260323100000
  • subtasks collection — populated by ORM from the OneToMany inverse of parent_task; not a stored column

Example

{
  "data": {
    "type": "enrichment_task",
    "id": "c3a1f9e2-4b7d-4e2a-8f1c-9a0b3d5e7f21",
    "attributes": {
      "enrichment_task_id": "c3a1f9e2-4b7d-4e2a-8f1c-9a0b3d5e7f21",
      "entity_type": "company",
      "entity_id": "a1b2c3d4-0000-0000-0000-000000000001",
      "status": "completed",
      "enrichment_type": "ai_company",
      "input": { "company_id": "a1b2c3d4-0000-0000-0000-000000000001" },
      "output": { "domain": "acme.com", "registered_name": "Acme Corp" },
      "target_fields": ["domain", "registered_name"],
      "error": null,
      "source_channel": "company_create",
      "input_hash": "sha256:abc123",
      "description": null,
      "batch_id": "f7e6d5c4-3b2a-1908-7654-321098fedcba",
      "created_at": "2026-05-15T10:30:00.000Z",
      "updated_at": "2026-05-15T10:31:05.000Z",
      "deleted_at": null,
      "completed_at": "2026-05-15T10:31:05.000Z"
    },
    "relationships": {
      "workspace": {
        "data": { "type": "workspace", "id": "ws-uuid-0001" }
      },
      "parent_task": {
        "data": null
      }
    }
  }
}
Source: apps/api/src/database/entities/EnrichmentTask.ts · domain: ingestion · tier: Infrastructure