Files
main_frontend/AGENTS.md
T
2026-02-27 23:34:17 +03:00

334 lines
11 KiB
Markdown

# AGENTS.md — Coffee Project Frontend
## Project Overview
Next.js 16 application using **Feature-Sliced Design (FSD)** architecture, powered by **Bun** runtime and package manager.
---
## Tech Stack
| Category | Technology |
| ------------- | ------------------------------------------ |
| Runtime | Bun 1.3.5 |
| Framework | Next.js 16.1.1 (App Router) |
| Language | TypeScript 5.9 |
| UI Library | React 19 |
| Styling | SCSS Modules, normalize.css |
| State/Fetch | TanStack React Query 5, Axios, Xior |
| Animation | Framer Motion |
| Utilities | Lodash, date-fns, classnames, usehooks-ts |
| Icons | Lucide React, SVGR (custom icons) |
| Notifications | React Toastify |
| File Upload | React Dropzone |
| Linting | ESLint 9, Prettier, Stylelint |
| Testing | Jest, Testing Library |
---
## Commands
```bash
bun dev # Start dev server
bun run build # Production build
bun run start # Start production server
bun run lint # Run ESLint + Prettier
bun run gc <layer> <ComponentName> # Generate FSD component
bun run gicons # Convert SVGs to React components
```
---
## Project Structure (FSD)
```
app/ # Next.js App Router entry
pages/ # Keep empty (Next.js requires it)
public/ # Static assets
src/
├── app/ # App layer: global styles, providers
├── pages/ # Page compositions
├── widgets/ # Large UI blocks (header, sidebar)
├── features/ # User interactions (auth, search)
├── entities/ # Business entities (user, product)
└── shared/ # Reusable: UI kit, utils, API, assets
├── ui/ # Button, Input, Icons...
├── api/ # API clients
├── lib/ # Utilities
└── assets/ # Images, raw-icons
```
### Path Aliases
```ts
@app/* ./src/app/*
@pages/* ./src/pages/*
@widgets/* ./src/widgets/*
@features/* ./src/features/*
@entities/* ./src/entities/*
@shared/* ./src/shared/*
@/* ./src/*
```
---
## Component Structure
Each component follows **flat FSD structure** (simplified for MVP):
```
ComponentName/
├── index.ts # Public API (re-export)
├── ComponentName.tsx # Component + imports
├── ComponentName.module.scss # Styles
├── ComponentName.d.ts # Props interface
└── useComponentApi.ts # Optional: hooks/API if needed
```
> **Note:** Old nested structure (`ui/`, `model/`, `api/` folders) has been deprecated.
> The backup of the old generator is at `.scripts/create-fsd-component.ts.bak`
### Component Template
```tsx
import type { IComponentNameProps } from "./ComponentName.d"
import type { JSX } from "react"
import { FunctionComponent } from "react"
import styles from "./ComponentName.module.scss"
export const ComponentName: FunctionComponent<
IComponentNameProps
> = (): JSX.Element => {
return (
<div className={styles.root} data-testid="ComponentName">
ComponentName
</div>
)
}
```
### Props Interface Template (ComponentName.d.ts)
```typescript
export interface IComponentNameProps {
className?: string
}
```
### Generate Component
Use one of these commands to generate new project-wide standardized component, don't create new component file by file by yourself
```bash
bun run gc <layer> <ComponentName>
# Examples:
bun run gc shared Button
bun run gc feature AuthForm
bun run gc entity UserCard
bun run gc page HomePage
bun run gc widget Sidebar
```
---
## Best Practices
### Code Style
1. **Small Functions** — max 20-30 lines; extract helpers
2. **Single Responsibility** — one function = one purpose
3. **Descriptive Names**`getUserById` not `getData`
4. **Early Returns** — reduce nesting with guard clauses
5. **No Magic Values** — use constants: `const MAX_ITEMS = 10`
### TypeScript
```ts
// ✅ Use interfaces for props
interface IButtonProps {
variant: "primary" | "secondary"
disabled?: boolean
onClick: () => void
}
// ✅ Prefer explicit types over `any`
// ✅ Use `type` for unions/intersections, `interface` for objects
```
### React Patterns
```tsx
// ✅ Functional components with explicit return type
export const Button: FC<IButtonProps> = ({ variant, onClick }): JSX.Element => { ... }
// ✅ Destructure props
// ✅ Use data-testid for testing
// ✅ Colocate styles with components (CSS Modules)
```
### FSD Rules
1. **Import Direction** — only downward: `features → entities → shared`
2. **Public API** — export only through `index.ts`
3. **No Cross-Slice Imports** — features cannot import from other features
4. **Shared is Agnostic** — no business logic in shared layer
5. **Features are module-aware** — group features by domain inside module folders (see below)
### When to Split Files
Split into separate files **only when**:
- Hook/API is reused by multiple components
- File exceeds ~200 lines
- Props interface is shared across 3+ components
### File Naming
| Type | Convention | Example |
| --------- | ----------------- | ---------------------- |
| Component | PascalCase | `UserCard.tsx` |
| Module | PascalCase.module | `UserCard.module.scss` |
| Types | PascalCase.d | `UserCard.d.ts` |
| Hook | camelCase (use-) | `useAuth.ts` |
| Utility | camelCase | `formatDate.ts` |
| Constant | UPPER_SNAKE_CASE | `API_ENDPOINTS.ts` |
### Performance
1. Use `React.memo` for expensive renders
2. Use `useMemo` / `useCallback` for derived data and callbacks
3. Lazy load pages/heavy components with `next/dynamic`
4. Prefer server components where possible (Next.js App Router)
### Testing
- Place tests next to components: `ComponentName.test.tsx`
- Use `data-testid` attributes for queries
- Test behavior, not implementation
---
## Features Layer — Module-Aware Structure
Features **must be grouped by domain module**. Never place feature folders flat at the top of `src/features/`.
```
src/features/
├── profile/ # Profile domain module
│ ├── index.ts # Barrel export for all features in this module
│ ├── AvatarUpload/
│ ├── EditProfileForm/
│ └── LogoutButton/
└── project/ # Project domain module
├── index.ts
├── CreateProjectModal/
└── ...
```
**Rules:**
- Each module folder has an `index.ts` barrel that re-exports all its features
- Import via the module barrel: `import { AvatarUpload } from "@features/profile"`
- When creating a new feature, place it inside the relevant domain folder
- After running `bun run gc feature <Name>`, move the generated folder into the correct module
- Create a new module folder + barrel if the domain doesn't exist yet
---
## Shared Utilities
Reusable operations should live in `src/shared/`**do not inline shared logic inside feature components**.
### File Upload
Use `uploadFile()` from `@shared/api/uploadFile` for any file upload:
```ts
import { uploadFile } from "@shared/api/uploadFile"
const result = await uploadFile(file, "avatars")
// result.file_url — URL of the uploaded file
// result.file_path — storage path
```
This handles FormData construction, Content-Type header override, and JWT auth automatically.
### Date Formatting
Use `date-fns` with Russian locale via shared utilities in `src/shared/lib/dates.ts`. **Never use `moment.js` or inline `Date` formatting in components.**
```ts
import { formatDate, formatRelativeTime } from "@shared/lib/dates"
formatDate(user.date_joined) // "21.02.2026" (default: "dd.MM.yyyy")
formatDate(date, "dd MMM yyyy") // "21 февр. 2026"
formatRelativeTime(project.updated_at) // "2 дня назад"
```
Add new date helpers to `src/shared/lib/dates.ts`, not to individual components.
### API Client
- **In React components**: use `api.useQuery()` / `api.useMutation()` from `@shared/api`
- **Outside React** (utilities, event handlers): use `fetchClient` from `@shared/api`
- **File uploads**: use `uploadFile()` from `@shared/api/uploadFile`
---
## Icons Workflow
1. Place raw SVG in `src/shared/assets/raw-icons/`
2. Run `bun run gicons`
3. Import from `@shared/ui/Icons/IconName`
---
## Notes
- **Keep `pages/` folder** in root — removing causes Next.js build errors
- **Bun only** — use `bun` commands, not npm/yarn
- **SCSS Modules** — all styles are scoped via `.module.scss`
- **Strict TypeScript** — `strict: true` in tsconfig
---
## Quick Reference
| Task | Command / Location |
| ------------------ | ------------------------------- |
| Add dependency | `bun add <package>` |
| Add dev dependency | `bun add -d <package>` |
| Create component | `bun run gc <layer> <Name>` |
| Global styles | `src/app/styles/global.scss` |
| API client | Use Axios/Xior with React Query |
| State management | TanStack Query (server state) |
## Localization
All user-facing UI text **must be in Russian**. This includes: labels, headings, buttons, placeholders, tooltips, aria-labels, error messages, breadcrumbs, and any other text visible to the user. The only exception is the brand name "Coffee Project" / "Cofee Project" — it stays in English.
## Implementation sentiments
Write less complicated code, simple but readable code
Less overhead - better
Write all components with html semantics in mind
To import classNames lib use
`import cs from 'classnames'`
Always install packages using
`bun install <package>`
To test is project have no errors use
`bunx tsc --noEmit`
---
## Common Mistakes to Avoid
1. **Flat features folder** — never place feature component folders directly in `src/features/`. Always group them inside a domain module folder (`profile/`, `project/`, etc.).
2. **Inlining reusable logic** — if an operation (file upload, date formatting, etc.) could be used by multiple features, extract it to `src/shared/`. Features should be thin wrappers around shared utilities.
3. **Wrong StaticLoader import** — it lives at `@shared/ui/Loader`, not `@shared/ui/Loader/StaticLoader`. There is no subdirectory.
4. **multipart/form-data with fetchClient** — the default `fetchClient` sets `Content-Type: application/json`. For file uploads you must override headers and body serializer. Use the shared `uploadFile()` utility instead.
5. **Broken lint scripts**`bun run lint` calls `lint:es` and `lint:prettier` which are not defined in `package.json`. Use `bunx tsc --noEmit` for type checking until lint is fixed.
6. **Generator output needs moving**`bun run gc feature <Name>` creates the folder flat in `src/features/`. You must manually move it into the correct domain module folder afterward.
7. **Raw `fetch` / `useEffect` for API calls** — never use plain `fetch` or `useEffect`-based polling for API requests. Always use `api.useQuery()` / `api.useMutation()` from `@shared/api` which wraps TanStack Query + openapi-fetch. For polling, use `refetchInterval`. Raw `fetch` bypasses typed routes, auth middleware, and query caching.