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 FieldRule stores a workspace-scoped AI grounding configuration for a single column (field_key) within a record root (e.g. invoices, companies). It carries three optional JSONB payloads — rules_config, formula_config, and format_config — each represented as a rich-text document tree (Tiptap/ProseMirror) or a plain-text prompt string. The entity is owned by the user: it is created or replaced via PUT /v1/field-rules/:root/:fieldKey and soft-deleted via DELETE on the same path. A partial unique index on (workspace_pk, root, field_key) WHERE deleted_at IS NULL enforces one active rule per field per workspace.
| Naming | Value |
|---|
| Object | FieldRule |
Resource type (JSON:API type) | field_rule |
| Collection / records root | — (not a records root) |
| REST base | /v1/field-rules |
| Entity class | FieldRule |
Internal object. Not currently exposed on the public REST API. The operations below describe the intended contract.
API operations
| Operation | Method & path | Status |
|---|
| List | GET /v1/field-rules | 🟡 Planned |
| Retrieve | GET /v1/field-rules/{id} | 🟡 Planned |
| Create | POST /v1/field-rules | 🟡 Planned |
| Update | PATCH /v1/field-rules/{id} | 🟡 Planned |
| Delete | DELETE /v1/field-rules/{id} | 🟡 Planned |
Data model
Attributes
| Field | Type | Required | Constraints | Allowed values | Description |
|---|
| field_rule_id | string (UUID) — 🔒 system | ✅ Yes | unique; default gen_random_uuid() | — | Public stable identifier for the field rule. Generated by the database on creation. |
| root | string | ✅ Yes | max length 50; part of partial-unique index (workspace_pk, root, field_key) WHERE deleted_at IS NULL | — | The record root this rule applies to (e.g. ‘invoices’, ‘companies’, ‘transactions’). Matches the root values accepted by /v1/records/query. |
| field_key | string | ✅ Yes | max length 255; part of partial-unique index (workspace_pk, root, field_key) WHERE deleted_at IS NULL | — | Dot-notation path identifying the target column within the root (e.g. ‘invoices.issuer.name’). Together with root and workspace, uniquely identifies one active rule. |
| column_name | string | ✅ Yes | max length 255 | — | Human-readable display label for the column this rule targets, used for context in AI grounding prompts. |
| column_type | string | ✅ Yes | max length 50 | — | Data type of the target column (e.g. ‘text’, ‘number’, ‘date’). Used to guide the AI extraction format. |
| rules_config | jsonb (FieldRuleConfig — RichTextNode | string | null) | ⚪ No | nullable | — | AI grounding instructions for extraction rules. Stored as a Tiptap/ProseMirror rich-text document tree (RichTextNode) or a plain-text prompt string. Supports @-mention nodes in the document tree. |
| formula_config | jsonb (FieldRuleConfig — RichTextNode | string | null) | ⚪ No | nullable | — | AI grounding configuration for formula-based computation of the field value. Same shape as rules_config — rich-text or plain string. |
| format_config | jsonb (FieldRuleConfig — RichTextNode | string | null) | ⚪ No | nullable | — | AI grounding configuration for output formatting instructions (e.g. currency symbol placement, date format). Same shape as rules_config. |
| created_at | datetime — 🔒 system | ✅ Yes | set on insert via onCreate hook; not null | — | Timestamp of row creation. Set automatically by the MikroORM onCreate lifecycle hook. |
| updated_at | datetime — 🔒 system | ✅ Yes | set on insert and update via onCreate/onUpdate hooks; not null | — | Timestamp of last modification. Set automatically on every write. |
| deleted_at | datetime | null — 🔒 system | ⚪ No | nullable; soft-delete sentinel; included in the partial-unique index condition (WHERE deleted_at IS NULL) | — | Soft-delete timestamp. When set, the rule is logically deleted and excluded from the active partial-unique index, allowing a new rule for the same (workspace, root, field_key) to be created. |
Relationships
| Name | Type | Required | Description |
|---|
| workspace | to-one (ManyToOne) | ✅ Yes | The workspace this field rule belongs to. FK: field_rules.workspace_pk → workspaces.pk. Enforces multi-tenant isolation — all queries are scoped to req.workspace. ON UPDATE CASCADE. |
System-computed
- field_rule_id: generated by gen_random_uuid() on insert; never client-provided
- created_at: set by MikroORM onCreate hook to new Date() at insert time
- updated_at: set by MikroORM onCreate and onUpdate hooks; reflects last write timestamp
- deleted_at: written by FieldRuleService.deleteRule() for soft deletion; not a client-settable field
- Partial unique index idx_field_rules_workspace_root_field_key enforces exactly one active rule per (workspace, root, field_key) when deleted_at IS NULL; soft-deleting a rule releases the slot for re-creation
- Upsert semantics in FieldRuleService.upsertRule(): finds existing active rule by (root, field_key, workspace); updates in-place if found, creates a new row otherwise
- On upsert, FieldRuleService.fireAndForgetRecompute() is triggered automatically to re-run AI extraction for affected records — this is a side effect not visible in the API response
Example
{
"data": {
"id": "a3f1b2c4-8e12-4d5a-9b3f-1c2e3d4f5a6b",
"type": "field_rule",
"attributes": {
"field_rule_id": "a3f1b2c4-8e12-4d5a-9b3f-1c2e3d4f5a6b",
"root": "invoices",
"field_key": "invoices.issuer.name",
"column_name": "Issuer",
"column_type": "text",
"rules_config": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "Extract the legal company name from the document header." }
]
}
]
},
"formula_config": null,
"format_config": null,
"created_at": "2026-04-01T10:30:00.000Z",
"updated_at": "2026-05-15T14:22:00.000Z",
"deleted_at": null
},
"relationships": {
"workspace": {
"data": { "id": "7e4c9a12-3b5d-4e6f-8a1b-2c3d4e5f6a7b", "type": "workspace" }
}
}
}
}
Source: apps/api/src/database/entities/FieldRule.ts · domain: workspace · tier: Infrastructure