# frontend/AGENTS.md ## Scope These rules apply to work under `frontend/`. This is a Vite + React + TypeScript app using TanStack Query, Tailwind CSS, Framer Motion, Radix UI-style components, MDX, and Zustand. ## Commands Use only scripts that exist in `package.json`: ```sh npm run dev npm run build npm run lint npm run preview ``` `npm run build` runs `tsc -b && vite build`, and `postbuild` runs `node scripts/generate-sitemap.js`. There is currently no `test` script in `package.json`. Do not run or report `npm test` unless a test script is added. After frontend changes, run: ```sh npm run build npm run lint ``` If either command cannot be run or fails, report the exact command and failure. Do not create, modify, or run tests unless the user explicitly asks for test work. When the user asks for tests, keep working and rerun them until they pass or the remaining failure is clearly blocked. ## TypeScript - TypeScript is strict. `tsconfig.app.json` enables `strict`, `noUnusedLocals`, `noUnusedParameters`, `erasableSyntaxOnly`, `noFallthroughCasesInSwitch`, and `noUncheckedSideEffectImports`. - Keep types explicit at module boundaries, API helpers, and exported utilities. - Use `import type` for type-only imports. - Prefer existing shared types from `src/types.ts` before adding local duplicate types. - Preserve the repository's existing spacing style in TypeScript, including GNU-style spacing before call parentheses where it is already used. - Prefer single quotes for strings unless interpolation or escaping makes double quotes better. - Never write a TypeScript or TSX line longer than 99 characters. - Aim to keep TypeScript and TSX lines within 79 characters where practical. - Use 4-space logical indentation in TypeScript and TSX. - For arrays, never put whitespace or a line break immediately before `]`. - Keep the first element on the same line as `[` by default. - If an array would exceed the line limit, break after `[` and indent elements by 4 spaces. - In TypeScript and TSX only, replace every leading run of 8 spaces with a tab to reduce bytes. - Treat one leading tab as exactly equivalent to 8 leading spaces. - Use tabs only for leading indentation. Never replace spaces that occur after a non-space character on the same line. ## React - Use function components. - Existing page components commonly export an anonymous function satisfying `FC`; match nearby file style when editing. - React hooks must be called unconditionally and at the top level of components or custom hooks. - Gate editing and other privileged controls with shared permission helpers such as `canEditContent`, instead of showing controls and relying only on a later API failure. - Keep page-level components under `src/pages`. - Keep shared and feature components under `src/components`. - Use `react-router-dom` route params and navigation patterns already present in `src/App.tsx`. - Encode URL path-segment values with `encodeURIComponent`. ## TanStack Query - Use `@tanstack/react-query` for server state. - Query keys should come from `src/lib/queryKeys.ts`; add key builders there instead of using ad hoc arrays in components. - Fetch functions should live in domain helpers under `src/lib`, such as `posts.ts`, `tags.ts`, or `wiki.ts`. - Use `useQueryClient().invalidateQueries` with the shared root keys when mutations affect cached lists or detail views. - The app-wide `QueryClient` is configured in `src/main.tsx`; do not create additional clients in feature code. ## API calls - Use `src/lib/api.ts` for HTTP calls. - The API wrapper attaches `X-Transfer-Code` from `localStorage` and converts non-blob responses to camelCase. - Send Rails snake_case params and request body keys where the backend expects them. - Do not bypass the API wrapper unless there is a specific reason, such as a third-party request outside the Rails API. - For blob responses, pass `responseType: 'blob'` so the wrapper does not camelCase the body. ## Imports and aliases - The `@` alias points to `frontend/src`. - Prefer `@/...` imports for app code instead of long relative paths. - Keep type imports separate with `import type`. - Match existing import grouping: external packages, app modules, then type imports. ## Tailwind and UI - Tailwind scans `src/**/*.{html,js,ts,jsx,tsx,mdx}`. - Use `cn` from `src/lib/utils.ts` for conditional class names and class merging. - Reuse components from `src/components/common`, `src/components/layout`, and `src/components/ui` before adding new primitives. - Keep Tailwind classes consistent with nearby components. - Prefer restrained, content-first UI chrome: avoid adding card backgrounds, heavy borders, or nested panel decoration unless the surrounding screen already uses them. - Keep operational screens dense and direct; trim explanatory copy and use short Japanese labels that fit the control. - Preserve existing Japanese tone and orthography in nearby UI text, including old-kana wording where the file already uses it. - When adding dynamic tag color classes, update `tailwind.config.js` safelist if the class cannot be statically detected. - Do not introduce new UI libraries or production dependencies without approval. ## TSX formatting - Preserve compact TSX expression shapes such as inline ternary branches and closing `)` forms when nearby code uses them. - For long Tailwind `className` strings, wrap across lines only when needed. - Keep continuation indentation aligned with the 4-space logical indentation rule, using tabs only as leading 8-space compression. - Do not add braces around `if`, `else`, or `for` bodies when the body is a single physical line. - Always add braces around `if`, `else`, or `for` bodies when the body spans two or more physical lines, even if it is one statement. - Avoid reformatting unrelated JSX. ## Lint and build constraints - ESLint uses `@eslint/js`, `typescript-eslint`, `eslint-plugin-react-hooks`, and `eslint-plugin-react-refresh`. - The hooks rules are enforced; fix hook ordering instead of disabling the rule. - `react-refresh/only-export-components` is enabled as a warning with `allowConstantExport`. - Build failures from unused locals or unused parameters are TypeScript errors, not lint-only issues. ## Files to avoid in routine work - Do not edit `dist/` output directly. - Do not inspect or modify `node_modules/` unless explicitly needed. - Keep generated build artifacts out of source changes unless the user asks for them.