# Todo Example

This capsule shows the smallest useful Lakebed app pattern: authenticated per-user data with server-owned mutations.

## What It Shows

- A `todos` table with `text`, `done`, and `ownerId`.
- A `todos` query filtered by `ctx.auth.userId`.
- An `addTodo` mutation that cleans input before insert.
- A `setTodoDone` mutation that checks row ownership before update.
- A `clearDone` mutation that deletes only the current user's completed rows.
- A Preact UI using `useAuth`, `useQuery`, `useMutation`, and `<SignInWithGoogle />`.
- A pure shared helper for todo text normalization.

## Server Pattern

```ts
queries: {
  todos: query((ctx) =>
    ctx.db.todos
      .where("ownerId", ctx.auth.userId)
      .orderBy("createdAt", "desc")
      .all()
  )
}
```

Use this pattern whenever rows belong to a single user. The client should not receive rows it does not own.

For mutations, fetch the row and check ownership before changing it:

```ts
const todo = ctx.db.todos.get(id);
if (!todo || todo.ownerId !== ctx.auth.userId) {
  return;
}

ctx.db.todos.update(id, { done });
```

## Run It

Run the checked-in example:

```sh
npx lakebed auth as alice
npx lakebed dev examples/todo
```

Open:

```txt
http://localhost:3000
```

To compare two users, open:

```txt
http://localhost:3000/?lakebed_guest=alice
http://localhost:3000/?lakebed_guest=bob
```

Then inspect state:

```sh
npx lakebed db dump --port 3000
npx lakebed logs --port 3000
```
