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

# FieldRule

> A `FieldRule` stores a workspace-scoped AI grounding configuration for a single column (field_key) within a record root (e.g

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       | — <sub>(not a records root)</sub> |
| REST base                       | `/v1/field-rules`                 |
| Entity class                    | `FieldRule`                       |

<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/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

```json theme={null}
{
  "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" }
      }
    }
  }
}
```

<sub>Source: `apps/api/src/database/entities/FieldRule.ts` · domain: workspace · tier: Infrastructure</sub>
