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