Skip to content
Docs

Command palette

Jump to a page or view, or find a todo by name.

Changelog

Client/server boundary

Keep server capabilities out of browser and native module graphs.

Markdown

Import a leaf

A server-capable module must not re-export a neighbor's convenience constant. A client that imports one enum from a Drizzle table module can pull the entire table graph into its bundle. That happened here and led to ADR-0002.

import { PRIORITIES } from "@doro/db/schema/todo.enums";
import type { AppRouterClient } from "@doro/api/client";

Domain enums live in dependency-free *.enums.ts modules. Public Zod contracts live in api/src/routers/*.schema.ts, importing only safe contracts where necessary. A LEAF MODULE header means no imports may be added to that module. The API client entry exports types only.

Enforcement

  1. Nested Oxlint configs reject value imports of server modules from web, mobile and UI. Type-only imports are allowed.
  2. Server package export maps enumerate supported subpaths. Add a specific entry deliberately; do not widen it to ./*.
  3. The web build scans emitted client assets for server-only markers with assert-client-bundle-clean.mjs.
pnpm exec oxlint
pnpm --filter web build

The Drizzle schema aggregate is the documented exception: the relations builder needs all tables, and clients cannot reach it. The existing web oRPC adapter also uses a framework-stripped server branch for SSR. Do not copy that exception into an ordinary component.

Extending a contract

Put the shared value in a leaf first. Make the table and schema import the leaf. Add its explicit package export, then import that address from consumers. Do not rely on tree-shaking to hide server side effects.

Documentation articles render on the server so examples of server-only names stay out of executable client assets too. The browser receives trusted, repository-authored HTML and small navigation metadata.

Key files

Edit on GitHubDocumentation is in English.