A production-style full-stack Todo app that uses most of the Cleverbrush framework — server, client, auth, DI, mapper, schema-driven forms, and OpenAPI.
The monorepo includes a complete backend + frontend demo with Docker Compose and PostgreSQL. It showcases the core workflow: define schemas once, share the contract, and get typed handlers, clients, and forms for free.
| Package | What it does in the demo |
|---|---|
@cleverbrush/server | REST API, exhaustive handler mapping, batching, health check |
@cleverbrush/schema | Shared schemas for request/response bodies, queries, headers |
@cleverbrush/auth | JWT auth, Google OAuth, role-based authorization |
@cleverbrush/di | Dependency injection with schema-as-key tokens |
@cleverbrush/env | Typed env config with schema validation |
@cleverbrush/knex-schema | Schema-aware Knex queries (.hasTableName(), .hasColumnName()) |
@cleverbrush/mapper | Object mapping between DB rows and API responses |
@cleverbrush/server-openapi | Auto-generated OpenAPI 3.1 + AsyncAPI specs |
@cleverbrush/schema-json | Discriminator support for OpenAPI |
| Package | What it does in the demo |
|---|---|
@cleverbrush/client | Typed REST client with retry, timeout, dedup, cache, batching |
@cleverbrush/react-form | Schema-driven form fields with auto-validation |
@cleverbrush/schema | Shared schemas (same ones used on the server) |
One contract file imported by both server and client — no codegen, no type duplication:
// contract.ts — shared between frontend and backend
export const api = defineApi({
todos: {
list: todosResource.get()
.query(TodoListQuerySchema)
.responses({ 200: array(TodoResponseSchema) }),
create: todosResource.post()
.body(CreateTodoBodySchema)
.responses({ 201: TodoResponseSchema }),
}
});import { createClient } from '@cleverbrush/client/react';
import { retry, timeout, dedupe, throttlingCache, batching } from '@cleverbrush/client';
export const client = createClient(api, {
baseUrl: BASE_URL,
getToken: () => loadToken(),
middlewares: [
retry({ limit: 2 }),
timeout({ timeout: 10_000 }),
dedupe(),
throttlingCache({ throttle: 2000 }),
batching({ maxSize: 10 })
]
});
// Usage: fully typed, autocompleted
const todos = await client.todos.list({ query: { page: 1 } });import { useSchemaForm, Field } from '@cleverbrush/react-form';
const form = useSchemaForm(CreateTodoBodySchema);
// Validation rules come from the schema — no manual rules needed
<Field forProperty={(t) => t.title} form={form} label="Title" />
<Field forProperty={(t) => t.description} form={form} label="Description" variant="textarea" />const server = createServer()
.use(corsMiddleware)
.services(svc => configureDI(svc, config))
.useAuthentication({
defaultScheme: 'jwt',
schemes: [jwtScheme({
secret: config.jwt.secret,
mapClaims: claims => ({ userId: claims.sub, role: claims.role })
})]
})
.useAuthorization()
.withHealthcheck()
.useBatching();
mapHandlers(server, api, handlers);
server.listen(config.port);import { env, parseEnv } from '@cleverbrush/env';
export const config = parseEnv({
db: {
host: env('DB_HOST', string().default('localhost')),
port: env('DB_PORT', number().coerce().default(5432))
},
jwt: {
secret: env('JWT_SECRET', string().minLength(32))
}
});import { any } from '@cleverbrush/schema';
// Schema builders serve as DI tokens — fully typed
export const KnexToken = any().hasType<Knex>();
export const BoundQueryToken = any().hasType<BoundQuery>();Clone the repo and spin up the demo with Docker Compose:
git clone https://github.com/nicklatkovich/framework.git
cd framework/demos
docker compose upThis starts the backend, frontend, and PostgreSQL. The frontend is available at http://localhost:8080 and the API at http://localhost:3000.
| Feature | What it demonstrates |
|---|---|
| CRUD endpoints | Pagination, conflict detection (If-Match), soft delete |
| Auth | JWT login/register, Google OAuth, RBAC (user/admin) |
| Export/Import | CSV file download, bulk import with 207 Multi-Status |
| Webhooks | OpenAPI 3.1 callbacks via .callbacks() |
| WebSocket/SSE | Live todo updates, chat, AsyncAPI spec |
| Resilience demo | Slow and flaky endpoints to test retry/timeout |
| Batching demo | Client request batching in action |
| Discriminated unions | Todo events (assigned/commented/completed) |
| Object mapping | DB rows → API responses via mapper |
| Schema-driven forms | Create/edit with auto-validation from schema |