Imported from nocobase/nocobase3 (
packages/templates/app-template-examples/client/AGENTS.md). Install upstream withnpx skills add nocobase/nocobase3 --skill client. Copyright stays with the author.
Client Instructions
This directory is the application's browser client. Read the application's root AGENTS.md first; skills/nocobase-app-development/references/ holds the detail behind it.
What lives where
routes.tsdeclares your page routes.pages/holds the components they load.components/holds your components;components/ui/holds shadcn/ui primitives added withpnpm exec shadcn add.locales/holds every user-visible string.runtime.tsis the composition root.service-provider.tsholds startup logic and Refine resources for CRUD integration.react-providers.tsholds your React context providers, andplugins.tslists the plugins the browser loads. Sidebar entries come from routenavigationdeclarations.routing/,layouts/,shell/, andtheme/are the framework structure: route rendering and access checks, the settings and dev shells, the authenticated chrome, and the theme provider. The template evolves these, so an edit here is what a future upgrade has to reconcile — prefer the built-in mechanism, and when you do change them, comment why. Do not declare product routes in any of them.extensions/*/extension.tsare application-owned copies of plugin-published UI, discovered automatically.
Rules
- Keep every page behind a lazy
componentLoader(), default-exporting its component. Route metadata stays synchronous. - All three route surfaces define sidebar entries with
navigationon routes. Refine resources serve CRUD, not menus. Recursive groups organize navigation; page children require a manually placedOutlet. Readskills/nocobase-app-development/references/client-child-routes.mdfrom the application root. - Never write the deployment base path such as
/maininto a route path. The runtime restores it. authon a route controls browser navigation only. The endpoint it calls enforces its own authentication.- Pages declared with
defineDevRoutes()mount under/devand are absent from a production build. That is a build boundary, not a permission boundary. - Register plugins with
pnpm plugin:registerandpnpm plugin:unregister. Editplugins.tsby hand only to reorder entries or pass a plugin its options; array order is contribution order and presence enables the plugin. - To customize a plugin's page, use a plugin option, an
extensions/*/extension.tssource extension, orroute-overrides.ts. Do not declare a duplicate path such as/login. An override replaces onlycomponentLoader, keeps it lazy, includes acomponentEntry, and default-exports the component. One route takes one override across all three mechanisms. - Authentication UI belongs in
extensions/nocobase-auth-ui/. UseAuthLinkfrom@nocobase/app-plugin-authentication/client/uiand the plugin'sclient/actionshooks. Do not call auth endpoints directly from a page or create a second session store. - Style with semantic Tailwind tokens —
bg-background,text-foreground,border-border— so pages follow both themes. Never hard-code colors, and never restyle one page in isolation; change the tokens intheme/themes/*.cssif the look must change. - Every user-visible string goes through a translation key.
- React provider layers are outer-to-inner:
root,application,extension. Applications use the first two; plugins own the extension layer.beforeandafterorder only within one layer.
Before finishing, run pnpm typecheck, pnpm test, pnpm lint, and pnpm build. Use pnpm client:inspect when a contribution does not appear where you expect — it reports composition, not correctness.
For UI styling, use the shared color, font, size, spacing, radius and shadow contract in skills/nocobase-app-development/references/theme-tokens.md (from the application root). Prefer its Tailwind utilities so components respond to theme changes; keep deliberate fixed-size exceptions explicit.