# Data flow

Recommended patterns for new Concorde apps (Lit + TypeScript). Under the hood, data lives in a **DataProvider** store.

## Quick map

| Need | Use |
|------|-----|
| Read/write in code | `get` / `set` / `dp` + `DataProviderKey` (static paths only) |
| Reactive Lit template | `sub(key)` or `@subscribe` |
| Read component state from store | `@subscribe` + `DataProviderKey<T, U>` + `@state` |
| Inherit ancestor attributes | `@ancestorAttribute` |
| Write from component state | `@publish` |
| React to assignments | `@handle` |
| HTTP GET | `@get` + `Endpoint`, or `sonic-list` / `sonic-queue` with `fetch` |
| HTTP POST (body from store) | `@post` + `Endpoint` + body `DataProviderKey` |
| HTTP PUT / PATCH (body from store) | `@put` / `@patch` — same model as `@post` |
| Forms | `formDataProvider` + `name` on fields (no Subscriber on form elements) |
| Derived / aggregate (JSONata) | `derive()` or `sonic-jsonata` — [Jsonata](/core/components/functional/jsonata) |
| Offline doc demos | `serviceURL="/docs-mock-api"` — [Local API demos](/docs/misc/docs-mock-api) |

Agent skill: `concorde` (`rules/data.md`), see [AI agents](/docs/getting-started/ai-agents).

## DataProviderKey

<sonic-code language="typescript">
  <template>
import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
import { dp, get, set } from "@supersoniks/concorde/utils";

const cartKey = new DataProviderKey&lt;{ items: string[] }&gt;("cart");

set(cartKey, { items: [] });
dp(cartKey.items).set(["a", "b"]);
get(cartKey);
  </template>
</sonic-code>

Dynamic paths (`users.${userId}`) → decorators or `sub()` — not `get("users.${id}")` in imperative code. Resolution rules: [Dynamic path placeholders](/docs/misc/dynamic-path).

[DataProviderKey](/docs/misc/dataProviderKey)

## Decorators

| Decorator | Role |
|-----------|------|
| `@subscribe` | Read-only property from store — [data configuration](/docs/getting-started/my-first-component) (type + key + scope) |
| `@publish` | Push property writes to store |
| `@handle` | Method called on assignment |
| `@ancestorAttribute` | Copy ancestor HTML attribute onto property |
| `@get` | HTTP GET into `ApiResult&lt;T&gt;` |
| `@post` | HTTP POST into `ApiResult&lt;T&gt;` (body from a publisher) |
| `@put` / `@patch` | HTTP PUT / PATCH into `ApiResult&lt;T&gt;` |

Walkthrough: [My first component](/docs/getting-started/my-first-component)

## HTTP and lists

- [@get](/docs/decorators/get) — single GET on a component
- [@post](/docs/decorators/post) — POST with body read from a `DataProviderKey`
- [@put](/docs/decorators/put) · [@patch](/docs/decorators/patch) — PUT / PATCH (same options as `@post`)
- [List](/core/components/functional/list) — `fetch` + `key="data"` + `/docs-mock-api/api/users`
- [Queue](/core/components/functional/queue) — lazy `offset=$offset&per_page=$limit` + optional `dataFilterProvider` (form → query)

## Starter kit

```bash
npx @supersoniks/create-concorde-ts-starter my-app
```

Interactive routes mirror these patterns (`/concepts/*`, `/demo/*`).

## Derived data (`derive` / `sonic-jsonata`)

Use when you need **client-side aggregations** (groupby, top N, chart shapes) from existing DataProviders — without inline app JS in SDUI.

- Primitive: `derive({ inputs, compute, output, variables? })` from `@supersoniks/concorde/utils` (read-only output, debounce, generation, cycle detection, `{output}/_state_`).
- SDUI adapter: [`sonic-jsonata`](/core/components/functional/jsonata) (`inputProvider` → `expression` → `outputProvider`, optional `formDataProvider`).
- vs [`sonic-mix`](/core/components/functional/mix): mix composes bidirectionally; jsonata **computes** unidirectionally.

## Legacy integration

| Topic | Page |
|-------|------|
| `data-bind` HTML (plain HTML hosts) | [HTML integration](/docs/misc/html-integration) — doc demos use Lit in `src/docs/example/` |
| `@onAssign` | [@onAssign](/docs/decorators/on-assign) (prefer `@handle`) |
| `sonic-fetch` alone | [Fetch](/core/components/functional/fetch) |
