> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chardb.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat app

> Follow the generated organization message app from session to live update.

This recipe uses the app from [Quickstart](/quickstart). Do not rebuild it by hand. The initializer already wires the server, browser, Miniflare test, migration journal, and deploy scripts.

## Establish the Better Auth session

```tsx theme={null}
const workerUrl = window.location.origin;
const db = createChardbReactClient({
  url: workerUrl,
  ownership: "organization",
  auth: ({ baseURL }) => createAuthClient({
    baseURL,
    plugins: [anonymousClient(), organizationClient(), jwtClient()],
  }),
});

<db.Provider>
  <Workspace />
</db.Provider>
```

The React client passes its normalized public Worker URL to the Better Auth factory, then uses that same origin for live WebSockets and file routes. The generated browser signs in anonymously through `db.auth`, creates an organization, and calls `db.auth.organization.setActive`. The provider fetches the signed JWT used by live queries and mutations.

## Read the active organization

```tsx theme={null}
const { data = [], state } = db.useQuery(listMessages, {
  limit: 50,
});
```

The configured client reads the active organization from the Better Auth session and adds it to the registered query arguments. Gateway still verifies current membership and the table policy before it registers the query.

## Upload, then write

```tsx theme={null}
const post = db.useMutation(postMessage);

const uploaded = selectedFile
  ? await attachment.upload({
      file: selectedFile,
      idempotencyKey: retryKey,
    })
  : null;

await post({
  id: uuidv7(),
  body,
  attachment: uploaded?.fileId ?? null,
  clientCreatedAt: Date.now(),
});
```

The SDK adds the active organization to the mutation and file upload. Reuse the same upload idempotency key when retrying the selected file. The row stores only the opaque file ID.

Open the same organization in two tabs and post a message. Both subscriptions should receive the replacement snapshot. Switch one tab to another organization and confirm it cannot read or download the first organization's data.

The generated Vitest covers the server write and read. The browser path adds live delivery and the authenticated file lifecycle.
