placebo.mk/AGENTS.md
2026-02-22 00:44:46 +01:00

170 lines
4.9 KiB
Markdown

# Agent Guidelines for placebo.mk
## Project Overview
Macedonian satirical news site using TanStack stack + NestJS backend.
## Tech Stack
- **Frontend**: React 19 + TanStack (Query, Router) + Vite + Tailwind CSS + shadcn/ui
- **Backend**: NestJS + TypeORM + SQLite
- **CMS**: Strapi (in /cms)
## Commands
### Root Level
```bash
npm run dev:local # Start backend & frontend locally
npm run dev:docker # Start via docker-compose
npm run lint # Lint both projects
npm run lint:fix # Auto-fix lint issues
npm run type-check # Type check both projects
```
### Backend (cd backend)
```bash
npm run start:dev # Watch mode
npm run lint / lint:fix # ESLint
npm run type-check # TypeScript check
npm test # All tests
npm test app.service.spec # Single file (omit .ts)
npm test -t "should return" # By pattern
npm test:cov # Coverage
npm test:e2e # E2E tests
```
### Frontend (cd frontend)
```bash
npm run dev # Vite dev server
npm run lint / lint:fix # ESLint
npm run type-check # TypeScript check
npm test # All tests (Vitest)
npm test Header.test # Single file (omit .tsx)
npm test -t "renders" # By pattern
npm test:ui # Vitest UI
npm test:coverage # Coverage
```
## Code Style
### TypeScript
- Strict mode: `noImplicitAny`, `strictNullChecks`, `noFallthroughCasesInSwitch`
- No implicit `any` - use `unknown` when type uncertain
- Explicit return types for public methods
- Prefer `interface` over `type` for objects
- Use `readonly` for immutable properties
### Formatting (Prettier)
- Single quotes, trailing commas, 2-space indent
- No semicolons in comments
### Naming
| Element | Convention | Example |
|---------|------------|---------|
| Files | kebab-case | `user-profile.ts`, `auth.service.ts` |
| Classes | PascalCase | `UserService`, `AuthGuard` |
| Functions/Variables | camelCase | `getUser`, `isLoading` |
| Constants | UPPER_SNAKE_CASE | `MAX_RETRIES` |
| Private members | underscore prefix | `_cache`, `_validate()` |
| Interfaces | PascalCase (no I prefix) | `User`, `ApiResponse` |
### Imports
Group with blank lines: External → Internal → Relative
```typescript
// External
import { Injectable } from '@nestjs/common';
import { useQuery } from '@tanstack/react-query';
// Internal modules
import { UserService } from '../users/user.service';
// Relative
import { AuthResponse } from './types';
```
### File Structure
```
backend/src/
modules/{feature}/
{feature}.module.ts
{feature}.controller.ts
{feature}.service.ts
{feature}.dto.ts
common/{decorators,filters,guards,interceptors,pipes}
entities.ts # All TypeORM entities
frontend/src/
components/{ui,layout,features,admin,routes}/
hooks/ # Custom React hooks
queries/ # TanStack Query hooks
lib/ # Utilities, API client
routes/ # TanStack Router routes
types/ # TypeScript types
```
### Path Aliases
- Frontend: `@/*` maps to `./src/*`
- Import UI components: `import { Button } from '@/components/ui/button'`
## Patterns
### Backend Services (NestJS)
```typescript
@Injectable()
export class AuthService {
constructor(
private userService: UserService,
private jwtService: JwtService,
) {}
async login(dto: LoginUserDto): Promise<AuthResponse> {
// Implementation
}
}
```
### Frontend Hooks (TanStack Query)
```typescript
export function useArticles(params: FindArticlesParams = {}) {
return useQuery({
queryKey: ['articles', params],
queryFn: () => api.fetchArticles(params),
});
}
export function useCreateArticle() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: api.createArticle,
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['articles'] }),
});
}
```
### Error Handling
- **Backend**: NestJS exceptions (`NotFoundException`, `BadRequestException`)
- **Frontend**: Error boundaries, try-catch with user-friendly messages
### API Response Format
```typescript
{ data: T, meta: { total, page, limit }, error?: { code, message } }
```
## Testing
- **Backend**: Jest (`*.spec.ts`), AAA pattern, mock dependencies
- **Frontend**: Vitest + React Testing Library (`*.test.tsx`)
- Descriptive names: `should return user data when valid ID provided`
## Git Commits
- Conventional: `feat:`, `fix:`, `refactor:`, `test:`, `docs:`, `chore:`
- Atomic, imperative mood
## UI Components
- Use shadcn/ui from `components/ui/`
- CVA for variants, clsx + tailwind-merge for classes
## Agent Instructions
- **ALWAYS** run `npm run lint` and `npm run type-check` after changes
- **NEVER** commit without explicit request
- **PREFER** editing existing files over creating new ones
- **VERIFY** tests pass before considering work complete
- **CHECK** both backend/frontend when making API changes