# uip pm apps data-model, uip pm apps model

> Syntax and options for editing a Process Mining app's structural data model and semantic model — tables, fields, dashboards, and metrics — with `uip pm apps data-model` and `uip pm apps model`.

Part of the [`uip pm`](./uip-pm.md) tool. This page covers the two model-editing surfaces on a process app:

- **`apps data-model`** — the structural table graph: which tables exist, their primary/foreign keys, and how they join to `Cases`.
- **`apps model`** — the semantic model: fields and their data kinds, calculated fields, dashboards, and metrics. Includes `fields`, `dashboards`, and `metrics` sub-groups for targeted edits, plus `get`/`update` for the whole document.
- **`apps data-mapping`** — the app's *input* data mapping: which source table/column feeds which target field. Distinct from the data model above (that's the queryable table graph *after* mapping).

Every write here is ETag-guarded — see [Concepts](./uip-pm.md#concepts) on the parent page.

## Synopsis

```text
uip pm apps data-model get <app-id> [--stage dev|published] [--destination <file>]
uip pm apps data-model add-table <app-id> --file <json-file> [--stage dev|published]

uip pm apps model get <app-id> [--stage dev|published] [--destination <file>]
uip pm apps model update <app-id> --file <json-file> --etag <etag>

uip pm apps model fields list <app-id> [--stage dev|published]
uip pm apps model fields set <app-id> <field-id> [--kind <kind>] [--display-name <text>] [--expression <json>] [--table ]
uip pm apps model fields remove <app-id> <field-id>

uip pm apps model dashboards list <app-id> [--stage dev|published]
uip pm apps model dashboards get <app-id> [--dashboard <id-or-name>] [--stage dev|published] [--destination <file>]
uip pm apps model dashboards update <app-id> [--file <json-file>] [--metrics <json-file>] --etag <etag> [--dashboard <id-or-name>]

uip pm apps model metrics list <app-id> [--stage dev|published]

uip pm apps data-mapping get <app-id> [--stage dev] [--destination <file>]
uip pm apps data-mapping update <app-id> --file <json-file> --etag <etag> [--stage dev]
```

## uip pm apps data-model get

Get the app's structural data model (tables with primary/foreign keys and column roles). Returns the model's ETag for reference; `add-table` itself takes no `--etag` because it re-reads and merges its own change.

### Arguments

| Name | Required | Purpose |
|---|---|---|
| `<app-id>` | yes | Process app ID. |

### Options

| Long | Value | Default | Description |
|---|---|---|---|
| `--stage <stage>` | `dev` \| `published` | `dev` | App stage. |
| `--destination <local-file>` | path | — | Write the model JSON to this file instead of the output envelope. |

### Data shape (--output json)

```json
{ "Code": "PmAppsDataModelGet", "Data": { "AppId": "9c46289e", "ETag": "W/\"3\"", "Model": {} } }
```

`Destination` replaces `Model` when `--destination` is passed.

## uip pm apps data-model add-table

Register a custom dbt model as a queryable data-model table. Process Mining is case-centric: a queryable table must be the `Cases` root or link to it — give the table a (nullable) `Case_ID` column with a foreign key to `Cases` to loosely link a standalone analytical table. Re-ingest afterward to materialize it. Takes no `--etag`: it reads the current data model itself and merges into exactly that document, so a write landing in between still conflicts and the command simply re-runs.

### Arguments

| Name | Required | Purpose |
|---|---|---|
| `<app-id>` | yes | Process app ID. |

### Options

| Long | Value | Required | Description |
|---|---|---|---|
| `--file <json-file>` | path | **yes** | JSON with the table(s) to add — a single data-model table, an array, or a `{ tables }` object. Each: `{ name, primaryKey, foreignKeys: [{ table: "Cases", column: "Case_ID" }] }` (`type` defaults to `"Object"`). |
| `--stage <stage>` | `dev` \| `published` | no | Default `dev`. |

A table is matched by `name`: an existing entry is replaced, a new one appended.

### Example

```bash
uip pm apps data-model add-table 9c46289e --file ./Workload_weekly.table.json
```

### Data shape (--output json)

```json
{
  "Code": "PmAppsDataModelAddTable",
  "Data": {
    "AppId": "9c46289e",
    "AddedTables": ["Workload_weekly"],
    "IngestionNeeded": true,
    "Instructions": "Re-ingest to materialize the table(s): uip pm ingestions create 9c46289e --wait — then query them. Run 'uip pm apps publish 9c46289e' to push to dashboards."
  }
}
```

Fails with `UserError_TableIsDeleted`-style rejection at the query layer if the table has no path to `Cases`. A nameless table entry, or a file with no usable table, fails client-side before any write.

## uip pm apps model get

Get the app's semantic model (fields with data kinds, calculated fields, metrics, and the dashboards view) — the shape `update` takes. Returns the model's ETag, which `model update` requires as `--etag`.

### Arguments

| Name | Required | Purpose |
|---|---|---|
| `<app-id>` | yes | Process app ID. |

### Options

| Long | Value | Default | Description |
|---|---|---|---|
| `--stage <stage>` | `dev` \| `published` | `dev` | App stage. |
| `--destination <local-file>` | path | — | Write the model JSON to this file instead of the output envelope. |

### Data shape (--output json)

```json
{ "Code": "PmAppsModelGet", "Data": { "AppId": "9c46289e", "ETag": "W/\"3\"", "Model": {} } }
```

## uip pm apps model update

Replace the whole app model from a local JSON file. Applies on dev only. For a single field prefer `apps model fields set`, which edits in place; a full replace has to carry the ETag of the `model get` it was written from — fetching a fresh ETag here would defeat the concurrency check.

### Arguments

| Name | Required | Purpose |
|---|---|---|
| `<app-id>` | yes | Process app ID. |

### Options

| Long | Value | Required | Description |
|---|---|---|---|
| `--file <json-file>` | path | **yes** | Local JSON file with the full model (as returned by `model get`). |
| `--etag <etag>` | string | **yes** | ETag of the model this edit is based on. |

### Data shape (--output json)

```json
{ "Code": "PmAppsModelUpdate", "Data": { "AppId": "9c46289e", "Versions": [4], "Instructions": "Model saved on dev. Run 'uip pm apps publish 9c46289e' to push it to the dashboards; if a field's data kind changed, re-ingest so the data matches: uip pm ingestions create 9c46289e --wait." } }
```

A stale `--etag` fails with a conflict — re-read via `model get`, redo the edit, and retry. A `UnsupportedOperatorArgumentDataKind` error means a dashboard filter, calculated field, or metric threshold still compares a field to a constant of its old data kind — fix or remove that comparison before changing the kind.

## uip pm apps model fields list

List every field across the app's tables with its data kind and whether it's a mapped column or a calculated field.

### Arguments

| Name | Required | Purpose |
|---|---|---|
| `<app-id>` | yes | Process app ID. |

### Options

| Long | Value | Default | Description |
|---|---|---|---|
| `--stage <stage>` | `dev` \| `published` | `dev` | App stage. |

### Data shape (--output json)

```json
{ "Code": "PmAppsFieldsList", "Data": [{ "Table": "Cases", "Id": "Case_status", "Display": "Status", "Kind": "nominal", "Type": "column" }] }
```

`Type` is `"column"` (mapped) or `"calculated"`.

## uip pm apps model fields set

Create or edit a field (ETag-safe internally — reads and merges its own base). Change its data kind, rename it, or turn it into a calculated field.

### Arguments

| Name | Required | Purpose |
|---|---|---|
| `<app-id>` | yes | Process app ID. |
| `<field-id>` | yes | Field ID. |

### Options

| Long | Value | Description |
|---|---|---|
| `--kind <kind>` | `ordinal`\|`nominal`\|`numeric`\|`datetime`\|`boolean`\|`percentage`\|`currency`\|`duration` | Data kind. (`id`/`ref` are structural and not settable.) |
| `--display-name <text>` | string | Display name. |
| `--expression <json>` | JSON (inline or `@file.json`) | Calculated-field expression node. Providing it turns the field into a calculated field. |
| `--table ` | string | Target table — required only when creating a new field. |

At least one of `--kind`/`--display-name`/`--expression` is required. Creating a field requires `--table`, `--expression`, and `--kind`; mapped columns can't be created this way (they come from ingested data). Setting `--expression` on an existing mapped column is rejected — create a new calculated field with a different ID instead. A create whose ID collides with a field in a *different* table is rejected rather than silently editing that field.

### Example

```bash
uip pm apps model fields set 9c46289e Case_status --kind ordinal
```

### Data shape (--output json)

```json
{ "Code": "PmAppsFieldsSet", "Data": { "AppId": "9c46289e", "Field": "Case_status", "Action": "updated", "Table": "Cases", "Versions": [4], "Instructions": "Model saved on dev. Run 'uip pm apps publish 9c46289e' to push it to the dashboards; if a field's data kind changed, re-ingest so the data matches: uip pm ingestions create 9c46289e --wait." } }
```

`Action` is `"created"` or `"updated"`.

## uip pm apps model fields remove

Remove a field from the model.

### Arguments

| Name | Required | Purpose |
|---|---|---|
| `<app-id>` | yes | Process app ID. |
| `<field-id>` | yes | Field ID. |

### Data shape (--output json)

```json
{ "Code": "PmAppsFieldsRemove", "Data": { "AppId": "9c46289e", "Field": "Case_status", "Table": "Cases", "Versions": [4], "Instructions": "..." } }
```

## uip pm apps model dashboards

The dashboard-shaped view of the same model document `model get`/`update` round-trip — `list`/`get`/`update` work on `view.dashboards`.

### uip pm apps model dashboards list

List the dashboards of a process app.

| Name/Option | Required | Purpose |
|---|---|---|
| `<app-id>` | yes | Process app ID. |
| `--stage <stage>` | no | `dev` \| `published`, default `dev`. |

```json
{ "Code": "PmAppsDashboardsList", "Data": [{ "Id": "overview", "Name": "Overview", "Layout": "three-left-one-right", "Charts": 4, "Metrics": 5, "IsVisible": true }] }
```

`Charts` is the flattened count of the dashboard's chart-id matrix.

### uip pm apps model dashboards get

Get the dashboards of a process app, with the ETag `update` needs.

| Long | Value | Description |
|---|---|---|
| `--stage <stage>` | `dev`\|`published` | Default `dev`. |
| `--dashboard <id-or-name>` | string | Return only this dashboard instead of the whole `view` section. Matched by ID first, then by exact name — an ambiguous name (more than one dashboard sharing it) fails, asking you to select by ID. |
| `--destination <local-file>` | path | Write JSON to this file instead of the envelope. |

```bash
uip pm apps model dashboards get 9c46289e --dashboard 'Overview' --destination ./dashboard.json
```

```json
{ "Code": "PmAppsDashboardsGet", "Data": { "Dashboard": "Overview", "ETag": "W/\"3\"", "Destination": "./dashboard.json" } }
```

### uip pm apps model dashboards update

Update the dashboards of a process app from a local JSON file. Dev stage only.

| Long | Value | Required | Description |
|---|---|---|---|
| `--file <local-file>` | path | no* | One dashboard when `--dashboard` is given, otherwise the whole `view` section. |
| `--metrics <local-file>` | path | no* | JSON array of metric definitions to add or replace by ID — written in the **same request** as `--file`, so a chart it introduces can reference a metric added in the same write. |
| `--etag <etag>` | string | **yes** | ETag of the model this edit is based on. |
| `--dashboard <id-or-name>` | string | no | Which dashboard `--file` replaces — requires `--file`; passing it without `--file` is rejected. |

\* At least one of `--file`/`--metrics` is required.

```bash
uip pm apps model dashboards update 9c46289e --dashboard 'Overview' --file ./dashboard.json --etag 'W/"3"'
```

```json
{ "Code": "PmAppsDashboardsUpdate", "Data": { "Dashboard": "Overview", "Versions": [4], "Instructions": "Saved on dev. Run 'uip pm apps publish 9c46289e' to push the change to the dashboards; if the publish reports IngestionNeeded, re-ingest with 'uip pm ingestions create 9c46289e --wait'." } }
```

## uip pm apps model metrics list

List the metrics a chart can reference, from the app's data model. Add or replace one with `dashboards update --metrics`.

| Name/Option | Required | Purpose |
|---|---|---|
| `<app-id>` | yes | Process app ID. |
| `--stage <stage>` | no | `dev`\|`published`, default `dev`. |

```json
{ "Code": "PmAppsMetricsList", "Data": [{ "Id": "avg_throughput", "Display": "Avg. throughput", "Aggregation": "AVERAGE", "Argument": "Case_throughput_time" }] }
```

## uip pm apps data-mapping get

Get the app's input data mapping — the same shape `apps create --data-mapping` takes, so it can be edited and pushed back with `data-mapping update`. Returns the mapping's ETag, which that update requires as `--etag`.

| Long | Value | Default | Description |
|---|---|---|---|
| `--stage <stage>` | `dev` \| `published` | `dev` | App stage to read. |
| `--destination <local-file>` | path | — | Write the mapping JSON to this file instead of the output envelope. |

```bash
uip pm apps data-mapping get 9c46289e --destination ./mapping.json
```

```json
{ "Code": "PmAppsDataMappingGet", "Data": { "AppId": "9c46289e", "ETag": "W/\"639204059477096903\"", "Destination": "./mapping.json" } }
```

## uip pm apps data-mapping update

Replace the app's input data mapping from a local JSON file (ETag-safe) — fix a wrong mapping in place instead of recreating the app. Applies on the next ingestion; unlike a transformation fix, a mapping change governs how the raw file is *parsed*, so `transformations apply` cannot apply it retroactively.

### Options

| Long | Value | Required | Description |
|---|---|---|---|
| `--file <json-file>` | path | **yes** | Full input data mapping (`{ "Tables": [...] }`) — replaces the stored mapping outright. Same per-field defaulting as `apps create --data-mapping`. |
| `--etag <etag>` | string | **yes** | ETag of the mapping this edit is based on. |
| `--stage <stage>` | `dev` | no | Only `dev` is writable — the backend serves GET on both stages but only accepts the write on dev. |

```bash
uip pm apps data-mapping update 9c46289e --file ./mapping.json --etag 'W/"639204059477096903"'
```

```json
{ "Code": "PmAppsDataMappingUpdate", "Data": { "AppId": "9c46289e", "Tables": ["Event_log"], "IngestionNeeded": true, "Instructions": "Re-ingest for the new mapping to take effect: uip pm ingestions create 9c46289e --wait. Re-upload first (uip pm files upload) only if the source columns changed." } }
```

A stale `--etag` fails with a conflict — re-read via `data-mapping get`, redo the edit, and retry. A mapping file with no tables in it fails client-side rather than wiping the app's mapping.

## Related

- [`uip pm`](./uip-pm.md) — overview and `apps` CRUD.
- [`ingestions` & `transformations`](./uip-pm-ingestion.md) — materialize a data-model or field change.
- [`conformance`, `deviations` & `query`](./uip-pm-analysis.md) — analyze the resulting data.

## See also

- [Global options](./global-options.md)
- [Exit codes](./exit-codes.md)
