# 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 { // 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