
# System Sources

Data components normally bind to a table. Some do not: a runs grid, an audit log, or a global-search result list reads from a platform endpoint that is not one of your tables.

You can bind such a component inline with `dataSource: { system: { endpoint: … } }`. The moment two components read the same endpoint, that raw path is duplicated in your config. `app.systemSources` declares each endpoint once, under a name:

```yaml
systemSources:
  - name: runs
    endpoint: /api/admin/automations/runs
  - name: failed-runs
    endpoint: /api/admin/automations/runs
    query:
      status: failed
```

Components then reference the name:

```yaml
- type: data-table
  dataSource:
    systemSource: runs
```

## Entry Properties

| Property   | Description                                                                                         |
| ---------- | --------------------------------------------------------------------------------------------------- |
| `name`     | Reference name used by `{ systemSource: <name> }`. Lowercase kebab-case, unique within the catalog. |
| `endpoint` | The read endpoint to fetch rows from (e.g. `/api/admin/automations/runs`).                          |
| `rowsKey`  | Key of the rows array in the response envelope. Defaults to `items`.                                |
| `idKey`    | Key of each row's unique id. Defaults to `id`.                                                      |
| `totalKey` | Key of the total count in the envelope. Falls back to the number of rows returned when absent.      |
| `query`    | Static query parameters merged into every request to the endpoint.                                  |

A catalog entry is a drop-in for the inline `system` form — a referencing component reads exactly the same fields it would have read inline, so switching between the two never changes the component.

## Two Sources, One Endpoint

`query` is what makes named sources worth declaring. The same endpoint with different static parameters becomes two distinct, self-describing sources:

```yaml
systemSources:
  - name: open-tickets
    endpoint: /api/admin/tickets
    query:
      status: open
  - name: closed-tickets
    endpoint: /api/admin/tickets
    query:
      status: closed
```

Each is then one word at the binding site, and the filter lives in one place rather than being restated in every component.

## Which Components Accept One

Any data-bound component: `data-table`, `list`, `gallery`, `kanban`, `calendar`, `chart`, `kpi` and `data-timeline`. See [Data Components](/en/docs/data-components) for what each renders.

## Validation

- The catalog must declare at least one source when present.
- Every `name` must be unique — a duplicate would make a reference ambiguous.
- Every `{ systemSource: <name> }` reference must point at a declared entry.

All three are checked when the config is decoded, so `sovrium validate` catches a typo'd reference offline, before the app boots.

:::callout
**System sources are read-only.** They fetch rows for display. Writes go through the records API or an automation — see [CRUD & Upsert](/en/docs/records-crud).
:::

## Related Pages

- [Data Components](/en/docs/data-components) — the components that consume a source.
- [Pages Overview](/en/docs/pages-overview) — `dataSource` and table binding.
- [API Reference](/en/docs/api-reference) — the endpoints a system source can read.
- [Admin Dashboard](/en/docs/admin-dashboard) — the operator console built from these bindings.
