README.md93 lines · main
1# todo-app
2
3the canonical briven hello-world. one table, four mutations, one reactive query, and a tiny react client. demonstrates:
4
5- schema with default values + nullable columns
6- input validation throwing `brivenError`
7- ULID generation via `@briven/shared`
8- a reactive `listTodos` query that the react client subscribes to
9
10## what's in here
11
12```
13todo-app/
14├─ briven.json project descriptor (filled by `briven link`)
15├─ briven/
16│ ├─ schema.ts one table: todos
17│ └─ functions/
18│ ├─ listTodos.ts reactive query · accepts {filter: 'open'|'done'|'all'}
19│ ├─ createTodo.ts mutation · validates body, returns the new row
20│ ├─ toggleTodo.ts mutation · flips done, sets/clears completedAt
21│ └─ deleteTodo.ts mutation · deletes by id
22└─ README.md you are here
23```
24
25## try it in 60 seconds
26
27```sh
28# 1. authenticate (skip if you already have credentials stored)
29briven login --project p_<id> --key brk_<...>
30
31# 2. copy the example, link it, deploy
32cp -r examples/todo-app my-todo-app
33cd my-todo-app
34briven link
35briven deploy
36
37# 3. exercise the api
38briven invoke createTodo --body '{"body":"buy milk"}'
39briven invoke listTodos
40briven invoke toggleTodo --body '{"id":"td_<paste-id>"}'
41```
42
43## react client
44
45```tsx
46import { BrivenProvider, useQuery, useMutation } from '@briven/react';
47
48function App() {
49 return (
50 <BrivenProvider config={{ projectId: 'p_<id>', apiKey: 'brk_<...>' }}>
51 <TodoList />
52 </BrivenProvider>
53 );
54}
55
56function TodoList() {
57 const { data, isLoading } = useQuery('listTodos', { filter: 'open' });
58 const create = useMutation('createTodo');
59 const toggle = useMutation('toggleTodo');
60
61 if (isLoading) return <p>loading…</p>;
62
63 return (
64 <div>
65 <button onClick={() => create({ body: prompt('what?') ?? '' })}>+ add</button>
66 <ul>
67 {data.map((t) => (
68 <li key={t.id}>
69 <input
70 type="checkbox"
71 checked={t.done}
72 onChange={() => toggle({ id: t.id })}
73 />
74 {t.body}
75 </li>
76 ))}
77 </ul>
78 </div>
79 );
80}
81```
82
83`useQuery('listTodos')` subscribes to the underlying `todos` table — when any
84mutation commits, the query re-runs and the component re-renders. no manual
85invalidation, no cache keys.
86
87## next steps
88
89- swap `@briven/react` for `@briven/svelte` or `@briven/vue` — same surface
90- add multi-user todos: extend the schema with `ownerId text().notNull()` and
91 read `ctx.auth.userId` inside `createTodo`
92- add a search query: `ctx.db('todos').where(..).orderBy(..)` is just a query
93 builder, anything postgres can do you can do here
Preview

todo-app

the canonical briven hello-world. one table, four mutations, one reactive query, and a tiny react client. demonstrates:

  • schema with default values + nullable columns
  • input validation throwing brivenError
  • ULID generation via @briven/shared
  • a reactive listTodos query that the react client subscribes to

what's in here

todo-app/
├─ briven.json              project descriptor (filled by `briven link`)
├─ briven/
│  ├─ schema.ts             one table: todos
│  └─ functions/
│     ├─ listTodos.ts       reactive query · accepts {filter: 'open'|'done'|'all'}
│     ├─ createTodo.ts      mutation · validates body, returns the new row
│     ├─ toggleTodo.ts      mutation · flips done, sets/clears completedAt
│     └─ deleteTodo.ts      mutation · deletes by id
└─ README.md                you are here

try it in 60 seconds

# 1. authenticate (skip if you already have credentials stored)
briven login --project p_<id> --key brk_<...>

# 2. copy the example, link it, deploy
cp -r examples/todo-app my-todo-app
cd my-todo-app
briven link
briven deploy

# 3. exercise the api
briven invoke createTodo --body '{"body":"buy milk"}'
briven invoke listTodos
briven invoke toggleTodo --body '{"id":"td_<paste-id>"}'

react client

import { BrivenProvider, useQuery, useMutation } from '@briven/react';

function App() {
  return (
    <BrivenProvider config={{ projectId: 'p_<id>', apiKey: 'brk_<...>' }}>
      <TodoList />
    </BrivenProvider>
  );
}

function TodoList() {
  const { data, isLoading } = useQuery('listTodos', { filter: 'open' });
  const create = useMutation('createTodo');
  const toggle = useMutation('toggleTodo');

  if (isLoading) return <p>loading…</p>;

  return (
    <div>
      <button onClick={() => create({ body: prompt('what?') ?? '' })}>+ add</button>
      <ul>
        {data.map((t) => (
          <li key={t.id}>
            <input
              type="checkbox"
              checked={t.done}
              onChange={() => toggle({ id: t.id })}
            />
            {t.body}
          </li>
        ))}
      </ul>
    </div>
  );
}

useQuery('listTodos') subscribes to the underlying todos table — when any mutation commits, the query re-runs and the component re-renders. no manual invalidation, no cache keys.

next steps

  • swap @briven/react for @briven/svelte or @briven/vue — same surface
  • add multi-user todos: extend the schema with ownerId text().notNull() and read ctx.auth.userId inside createTodo
  • add a search query: ctx.db('todos').where(..).orderBy(..) is just a query builder, anything postgres can do you can do here