> ## 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.

# Custom Column

> A Custom Column is a per-workspace, per-root virtual column a user adds to a records table (e.g

A Custom Column is a per-workspace, per-root virtual column a user adds to a records table (e.g. a 'Risk level' column on companies). It holds the column definition only — name, type, position, and the AI/formula/format config — while the computed cell values live in custom\_column\_values. Custom columns are workspace-scoped and namespaced by records root; they are NOT Hasura columns and NOT governed DATA\_VIEW\_ROOTS, so they sit behind the records table as an overlay rather than as a queryable entity of their own.

| Naming                          | Value                             |
| ------------------------------- | --------------------------------- |
| Object                          | Custom Column                     |
| Resource type (JSON:API `type`) | `custom_column`                   |
| Collection / records root       | — <sub>(not a records root)</sub> |
| REST base                       | `/v1/custom-columns`              |
| Entity class                    | `CustomColumn`                    |

<Note>
  **Internal object.** Not currently exposed on the public REST API. The operations below describe the intended contract.
</Note>

## API operations

| Operation | Method & path                    | Status     |
| --------- | -------------------------------- | ---------- |
| List      | `GET /v1/custom-columns`         | 🟡 Planned |
| Retrieve  | `GET /v1/custom-columns/{id}`    | 🟡 Planned |
| Create    | `POST /v1/custom-columns`        | 🟡 Planned |
| Update    | `PATCH /v1/custom-columns/{id}`  | 🟡 Planned |
| Delete    | `DELETE /v1/custom-columns/{id}` | 🟡 Planned |

## Data model

### Attributes

| Field              | Type                          | Required | Constraints                                                    | Allowed values                                          | Description                                                                                                            |
| ------------------ | ----------------------------- | -------- | -------------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| custom\_column\_id | string, UUID, 🔒 system       | ✅ Yes    | unique; gen\_random\_uuid()                                    | —                                                       | Public identifier of the column definition. Internal pk is never exposed.                                              |
| root               | string                        | ✅ Yes    | max 50 chars; part of partial-unique key                       | A records root (companies, invoices, transactions, …)   | The data-view root this column is attached to. Scopes the column to one records table.                                 |
| name               | string                        | ✅ Yes    | max 255 chars                                                  | —                                                       | Human-readable column header shown in the records table.                                                               |
| field\_key         | string                        | ✅ Yes    | max 100 chars; part of partial-unique key; slugified from name | —                                                       | Stable machine key for the column, slugified from name at creation. Unique per (workspace, root).                      |
| type               | string (CustomColumnTypeEnum) | ✅ Yes    | native enum custom\_column\_type\_enum; default 'text'         | text, number, amount, single\_select, multi\_select, ai | Column data type. 'ai' (and rules\_config-bearing columns) are auto-computed; others may be manually entered.          |
| position           | number (int)                  | ⚪ No     | default 0                                                      | —                                                       | Display order of the column within the records table.                                                                  |
| icon               | string                        | ⚪ No     | max 100 chars; nullable                                        | —                                                       | Optional icon identifier rendered in the column header.                                                                |
| rules\_config      | jsonb                         | ⚪ No     | nullable                                                       | —                                                       | AI compute rules. When set, the column is auto-computed by the enrichment pipeline (Anthropic Haiku) for every record. |
| formula\_config    | jsonb                         | ⚪ No     | nullable                                                       | —                                                       | Formula configuration for computed (non-AI) columns.                                                                   |
| format\_config     | jsonb                         | ⚪ No     | nullable                                                       | —                                                       | Display/format configuration (e.g. select options, number format).                                                     |
| created\_at        | ISO 8601, 🔒 system           | —        | onCreate hook                                                  | —                                                       | Creation timestamp.                                                                                                    |
| updated\_at        | ISO 8601, 🔒 system           | —        | onCreate + onUpdate hooks                                      | —                                                       | Last-update timestamp.                                                                                                 |
| deleted\_at        | ISO 8601, 🔒 system           | —        | nullable; soft delete                                          | —                                                       | Soft-delete tombstone; null when active.                                                                               |

### Relationships

| Name      | Type                            | Required | Description                                                                                     |
| --------- | ------------------------------- | -------- | ----------------------------------------------------------------------------------------------- |
| workspace | to-one (workspace)              | ✅ Yes    | Owning workspace — the per-workspace scope of the column.                                       |
| values    | to-many (custom\_column\_value) | ⚪ No     | Computed/entered cell values for this column, one per record (cascade-deleted with the column). |

### System-computed

* custom\_column\_id generated by gen\_random\_uuid()
* field\_key slugified from name at creation (slugifyFieldKey)
* Partial unique index on (workspace\_pk, root, field\_key) WHERE deleted\_at IS NULL — managed in a raw-SQL migration, not @Index (MikroORM cannot express partial indexes)
* type defaults to 'text'; position defaults to 0
* created\_at via onCreate; updated\_at via onCreate + onUpdate hooks
* Soft-delete via deleted\_at
* On create: autoProvisionPresets(workspace, root) may seed preset AI columns; fire-and-forget recompute over existing records
* On rules\_config / formula\_config / format\_config change: enqueueRecompute → recompute all records for the column
* AI columns (type='ai' or rules\_config present) compute via EnrichmentTask (CUSTOM\_COLUMN) → Cloud Task → Anthropic Haiku, with anti-prompt-injection guards

## Example

```json theme={null}
{
  "data": {
    "type": "custom_column",
    "id": "7c1f9a02-4d3b-4e21-9a77-2f0c11aa33bc",
    "attributes": {
      "custom_column_id": "7c1f9a02-4d3b-4e21-9a77-2f0c11aa33bc",
      "root": "companies",
      "name": "Risk level",
      "field_key": "risk_level",
      "type": "single_select",
      "position": 3,
      "icon": "shield-alert",
      "rules_config": "{\"prompt\":\"Classify the company risk as low, medium, or high based on its industry and country.\"}",
      "formula_config": null,
      "format_config": "{\"options\":[\"low\",\"medium\",\"high\"]}",
      "created_at": "2026-05-20T09:14:00.000Z",
      "updated_at": "2026-05-28T11:02:00.000Z",
      "deleted_at": null
    }
  },
  "relationships": {
    "workspace": {
      "data": {
        "type": "workspace",
        "id": "a1b2c3d4-0000-4000-8000-000000000001"
      }
    }
  }
}
```

<sub>Source: `apps/api/src/database/entities/CustomColumn.ts` · domain: records / data-views · tier: Infrastructure</sub>
