Dashboard Feature Template
Section titled “Dashboard Feature Template”Use this when adding a new dashboard feature or standardizing a small existing feature.
Not every feature needs every file. Add only what the feature uses.
Canonical shape
Section titled “Canonical shape”apps/dashboard/src/features/{feature}/ api.ts query-keys.ts queries.ts mutations.ts model/ search-params.ts components/ {Feature}Panel.tsx pages/ {Feature}Page.tsx hooks/ use{Feature}.ts types.ts index.tsResponsibilities
Section titled “Responsibilities”api.ts: dynamicimport()+call()transport wrappers onlyquery-keys.ts: serializable, feature-owned query key factoriesqueries.ts:queryOptions(...)factories and invalidation helpersmutations.ts:useMutation(...)wrappers and cache invalidationmodel/: pure feature logic, mappers, filters, search defaults, validatorscomponents/: reusable feature-owned UI onlypages/: route-level page entry rendered by thin route fileshooks/: feature-specific hooks that do not fitqueries.tsormutations.tstypes.ts: feature-local types
Starter example
Section titled “Starter example”// apps/dashboard/src/features/{feature}/api.tsimport { call } from "@/shared/transport/server-fn-client";
export async function list{Feature}Items() { const { list{Feature}Items } = await import("@/server/functions/{feature}"); return call(() => list{Feature}Items());}// apps/dashboard/src/features/{feature}/query-keys.tsexport const {feature}QueryKeys = { all: ["{feature}"] as const, list: (search: {Feature}Search) => ["{feature}", search] as const, detail: (id: string) => ["{feature}-detail", id] as const,} as const;// apps/dashboard/src/features/{feature}/queries.tsimport { queryOptions } from "@tanstack/react-query";import { list{Feature}Items } from "./api";import { {feature}QueryKeys } from "./query-keys";
export const {feature}ListQueryOptions = (search: {Feature}Search) => queryOptions({ queryKey: {feature}QueryKeys.list(search), queryFn: async () => list{Feature}Items(), placeholderData: (previous) => previous, });// apps/dashboard/src/features/{feature}/pages/{Feature}Page.tsxexport function {Feature}Page() { return <div>{Feature} page</div>;}Do not do this
Section titled “Do not do this”- Do not put route loaders, route declarations, or search validation here.
- Do not put low-level shared primitives here if the component is generic.
- Do not add
helpers.tsorutils.tsif the logic belongs inmodel/.