--- applyTo: "src/api/**/*.ts,src/mocks/**/*.ts,src/routes/_auth/**/*.tsx,e2e/**/*.spec.ts" description: "Use when adding a new CRUD resource (orders, roles, tenants, etc.). Keywords: add resource, new resource, scaffold, CRUD page." --- # Add Resource Recipe Add a list CRUD flow in `apps/with-lingui` that mirrors **Users** (TanStack Router + Query + MSW + Lingui). There is **no** codegen script: **copy and adapt by hand** using the steps below, or have an Agent follow this checklist. Primary references: `src/routes/_auth/users/`, the sample `src/routes/_auth/orders/`, and the matching `e2e/*.spec.ts` files. ## 0. Verification commands (after your changes) ```bash cd apps/with-lingui pnpm run build # refresh TanStack routeTree when routes change pnpm exec vp check --no-fmt pnpm run test:e2e -- e2e/.spec.ts ``` ## 1. Zod and types (`src/api/schemas.ts`) - Define `Schema`, `CreateRequestSchema`, `UpdateRequestSchema` (`Update` = `Create.partial()`). - Reuse `PaginatedResponseSchema(Schema)` for list responses. - Export `type = z.infer`. ## 2. Endpoint constants (`src/api/.ts`) - Export `_ENDPOINTS`: `list` / `create` / `update(id)` / `delete(id)` with paths like `/api/`. ## 3. Mock data (`src/mocks/data.ts`) - Append a `MOCK_` array. For **admin** users, `permissions` must include `:view` (and create/edit/delete if you add writes), aligned with `GET /api/auth/permissions`. ## 4. MSW (`src/mocks/handlers/.ts` + `handlers/index.ts`) - Follow `handlers/user.ts` / `handlers/orders.ts`: paginated `GET` + optional `keyword`, `POST` / `PUT` / `DELETE`; use `successWithSchema` / `paginatedWithSchema` / `successWithNullBody` for success and `errorResponse` for errors. - Register `...Handlers` in `handlers/index.ts`. ## 5. Route page (`src/routes/_auth//`) - `createFileRoute("/_auth//")`, wiring `useResourceCRUD` (recommended: `optimistic: { update: true, delete: true }`), `useCrudToasts`, `useUrlSearchState`, `useTableFitHeight` (see `users/` for splitting `-Toolbar` / `-FormModal`). - **Lingui**: run `pnpm run i18n:extract && pnpm run i18n:compile` for new copy (or `vp exec lingui …`). ## 6. Menu and permissions (`src/utils/appMenu.ts`) - Add a menu entry to `APP_MENU_TREE`: `path: "/"`, `permissions: [":view"]`, `icon` using a Sidebar-registered key such as `IconLucidePackage` (see existing `IconLucide*` entries in `Sidebar`). - Keep behavior consistent with `canAccessPath` / 403. ## 6b. Sidebar labels and icons (`src/components/Layout/Sidebar/index.tsx`) - In `MENU_LABELS`, add a Lingui `msg` entry for the menu item `name` (must match the `name` string from `appMenu`). - In `MENU_ICON_MAP`, map the new `icon` key to a `lucide-react` icon and add the matching `import`. - Then run `pnpm run i18n:extract && pnpm run i18n:compile` and fill in `zh` (and other locale) translations. > In this template repo, the `orders` sample is already aligned with the Sidebar next to `appMenu`. When adding a resource from scratch, double-check this section. ## 7. E2E (`e2e/.spec.ts`) - Copy structure from `users.spec.ts` / `orders.spec.ts`: `loginAsAdmin` → `goto /`, assert headers / search placeholder, etc. ## 8. Verification - `pnpm exec vp check --no-fmt` - `pnpm run test:e2e:core` (if you add the new spec to core) or `pnpm exec playwright test e2e/.spec.ts` - `pnpm run build` and watch chunk sizes in the log ## Notes - Before adding or renaming files, confirm nothing already exists at that path so you do not overwrite hand-written code. - After manual schema edits, treat the diff as source of truth; there is no automatic merge.