# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. See also the monorepo-level `../CLAUDE.md` for full architecture overview and backend docs. ## Commands ```bash bun dev # Dev server (localhost:3000) bun run build # Production build bun run lint # ESLint + Prettier (concurrent) bunx tsc --noEmit # Type-check without emitting bun run gc # Generate FSD component (e.g. bun run gc shared Button) bun run gicons # Convert raw SVGs → React icon components bun run gen:api-types # Regenerate API types from OpenAPI schema (backend must be running) ``` ## Architecture Next.js 16 App Router with Feature-Sliced Design. Strict unidirectional imports: `pages → widgets → features → entities → shared`. - **App directory** is at `app/` (project root), not `src/app/`. The `src/app/` layer holds global styles and providers. - **`app/template.tsx`** wraps all routes with Header (conditionally hidden on auth routes). - **All components are `"use client"`** unless explicitly marked otherwise. ## API & Data Layer - **`fetchClient`** (`openapi-fetch`) — typed HTTP client with JWT middleware that reads `access_token` from cookies. Defined in `src/shared/api/index.ts`. - **`api`** (`openapi-react-query`) — wraps `fetchClient` for use with TanStack Query hooks in components. Import as `import api from "@shared/api"`. - **Generated types** live in `src/shared/api/__generated__/openapi.types.ts` — never edit manually. - **Server actions** in `src/shared/api/server.ts` — used for server-side API calls (ping, token verification). ## Styling - **SCSS Modules** (`.module.scss`) for all component styles. - **SCSS partials auto-injected** via `next.config.mjs` using `@use`: `_variables.scss`, `_breakpoints.scss`, `_typography.scss`, `_mixins.scss`. No need to import them manually in `.module.scss` files. - **Radix UI Themes** wraps the app (`accentColor="iris"`, `grayColor="slate"`). Some components use Radix primitives directly (e.g., Dropdown uses `@radix-ui/react-dropdown-menu`, not Radix Themes). - **Class composition**: `import cs from "classnames"`. - **Design tokens** defined as CSS custom properties in `src/shared/styles/global.scss`, mirrored as SCSS vars in `_variables.scss`. ## State Management - **Server state**: TanStack React Query (primary for all API data). - **Client state**: Redux Toolkit with two slices: `appState` and `user` (in `src/shared/store/`). - **Provider hierarchy** (in `src/shared/context/AppProviders.tsx`): Redux → QueryClient → UserSync → Radix Theme. ## Component Convention Generate new components with `bun run gc ` — never create component files manually. Each component folder contains: - `index.ts` — public re-export only - `ComponentName.tsx` — implementation - `ComponentName.module.scss` — scoped styles - `ComponentName.d.ts` — props interface (`IComponentNameProps`) ## Code Style - **Prettier**: tabs (width 2), no semicolons, double quotes, sorted imports. - **Imports**: use path aliases (`@shared/*`, `@entities/*`, etc.), never relative paths across layers. - **Forms**: `react-hook-form` for form state management. - **Icons**: Lucide React for standard icons. Custom icons: place SVG in `src/shared/assets/raw-icons/`, run `bun run gicons`, import from `@shared/ui/Icons/IconName`. ## Features Layer — Module-Aware Structure Features are **grouped by domain module**, not placed flat at the top level. Each module folder has a barrel `index.ts`: ``` src/features/ ├── profile/ # Profile domain │ ├── index.ts # Barrel: re-exports all features in module │ ├── AvatarUpload/ │ ├── EditProfileForm/ │ └── LogoutButton/ └── project/ # Project domain ├── index.ts ├── CreateProjectModal/ ├── DeleteProjectModal/ ├── EditProjectModal/ └── RenameProjectModal/ ``` Import via module barrel: `import { AvatarUpload, EditProfileForm } from "@features/profile"`. When adding a new feature, place it inside the relevant domain module folder (create one if needed). ## File Uploads Use the shared `uploadFile` utility for any file upload — do not inline FormData logic in components: ```ts import { uploadFile } from "@shared/api/uploadFile" const result = await uploadFile(file, "avatars") // result.file_url, result.file_path ``` The utility handles FormData construction, Content-Type override, and auth middleware automatically. ## Date Formatting Use `date-fns` with Russian locale for all date formatting — never use `moment.js` or inline `Date` logic: ```ts import { formatDate, formatRelativeTime } from "@shared/lib/dates" formatDate(user.date_joined) // "21.02.2026" formatDate(date, "dd MMM yyyy") // "21 февр. 2026" formatRelativeTime(project.updated_at) // "2 дня назад" ``` Utilities live in `src/shared/lib/dates.ts`. Add new date helpers there, not in components. ## Localization All user-facing UI text **must be in Russian** — labels, headings, buttons, placeholders, tooltips, aria-labels, error messages, breadcrumbs. The brand name "Coffee Project" / "Cofee Project" stays in English. ## Gotchas - The `pages/` directory in the project root must exist (even if empty) — removing it causes Next.js build errors. - Dropdown component's `asChild` trigger applies both the Dropdown's trigger class AND the child's class. Avoid `all: unset` on Dropdown triggers — it strips child flex/display styles. - SCSS auto-import uses `@use` (not `@import`), so variables/mixins are namespaced (e.g., `variables.$color`). The files are injected as `additionalData` in `next.config.mjs`. - **openapi-fetch + multipart**: `fetchClient` defaults to `Content-Type: application/json`. For file uploads, you must override the header and body serializer. Use the shared `uploadFile()` utility instead of doing this manually. - **StaticLoader** is exported from `@shared/ui/Loader` (file is `Loader.tsx`), not from `@shared/ui/Loader/StaticLoader` — there is no subdirectory. - **`lint:es` / `lint:prettier` scripts** are referenced by `bun run lint` but not defined in `package.json`. Linting is currently broken — use `bunx tsc --noEmit` for type checking. - **`next/image` remote hosts**: External image hostnames must be listed in `next.config.mjs` `images.remotePatterns`. MinIO (`localhost:9000`) is already configured. If you add another storage backend, add its hostname there too. - **Stale OpenAPI types**: Always run `bun run gen:api-types` before implementing against the API if the backend has changed. Stale types cause silent 404s at runtime. - **Never use raw `fetch`/`useEffect` for API calls** — always use `api.useQuery()`/`api.useMutation()` from `@shared/api` (TanStack Query + openapi-fetch wrapper). For polling, use the `refetchInterval` option. Raw `fetch` bypasses typed routes, auth middleware, and query caching. Always use Context7 MCP when I need library/API documentation, code generation, setup or configuration steps without me having to explicitly ask. ## Testing Standards - All E2E tests use Playwright with TypeScript - Test files live in tests/e2e/ - Use `getByRole` as primary locator strategy - Every PR must include error-state tests, not just happy paths