# Agent Guidelines for placebo.mk ## Project Overview News site in Macedonia with sarcastic tone. Minimalistic design using TanStack stack. ## Tech Stack - **Frontend**: TanStack (React 19, Query, Router) + Vite + Tailwind CSS + shadcn/ui - **Backend**: NestJS + TypeORM + SQLite - **CMS**: Strapi (in /cms) ## Build Commands ### Backend (NestJS) ```bash cd backend npm install npm run start:dev # Watch mode npm run build npm run start:prod npm run lint # Lint npm run lint:fix # Auto-fix npm run type-check # TypeScript check npm test # All tests npm test app.service.spec.ts # Single file npm test -t "should" # By test name npm run test:cov # Coverage npm run test:e2e # E2E tests ``` ### Frontend (TanStack) ```bash cd frontend npm install npm run dev # Vite dev server npm run build npm run preview npm run lint npm run lint:fix npm run type-check npm test # All tests npm test Header.test.tsx # Single file npm test -t "renders" # By name npm run test:ui # Vitest UI ``` ## Code Style ### Formatting & TypeScript - Use Prettier (2 spaces, single quotes, trailing commas, 100 char max) - Strict TypeScript - no implicit `any`, avoid `any`, use `unknown` - Explicit return types for public methods - Prefer interfaces over types for objects - Use `readonly` for immutable properties ### Naming Conventions - **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`) ### Import Order - External libraries first, then internal modules, then relative imports ### File Structure ``` backend/src/ modules/feature-name/ feature-name.module.ts feature-name.controller.ts feature-name.service.ts feature-name.entity.ts feature-name.dto.ts common/{decorators,filters,guards,interceptors,pipes} config/ frontend/src/ components/{ui,layout,features}/ hooks/ lib/ queries/ routes/ types/ utils/ ``` ### Error Handling - **Backend**: Use NestJS exceptions (`NotFoundException`, `BadRequestException`), custom exceptions, Logger - **Frontend**: Error boundaries, try-catch with user-friendly messages ### API Conventions - REST endpoints: `/api/v1/resources` - JSON fields: snake_case - Pagination: `page`, `limit` query params - Response format: ```typescript { data: T, meta: { total, page, limit }, error?: { code, message } } ``` ### Testing - Unit tests for services/hooks (AAA pattern: Arrange-Act-Assert) - Integration tests for API endpoints - E2E tests for critical user flows - Descriptive test names that explain what is tested - Mock external dependencies (use Jest for backend, Vitest for frontend) - Run `npm test` for all tests or target specific files/names ### Git Workflow - Conventional commits: `feat:`, `fix:`, `refactor:`, `test:`, `docs:`, `chore:` - Keep commits atomic and focused - Write clear commit messages in imperative mood ### Component Guidelines - Keep components small and focused (< 200 lines) - Use functional components with hooks - Prefer composition over inheritance - Extract complex logic into custom hooks - Use TanStack Query for server state management - Use TanStack Router for routing - Validate props with TypeScript ### Database - Use TypeORM for SQLite - Define entities with proper relationships - Use migrations for schema changes - Seed data with factory functions - Use TypeORM repositories for data access ### UI Components - Use shadcn/ui components from `components/ui/` - Use class-variance-authority (CVA) for component variants - Use clsx and tailwind-merge for class composition - Follow shadcn patterns for new component creation ## Environment Variables - Backend: `@nestjs/config` with `.env` files - Frontend: Vite env vars (`VITE_API_URL`) - Never commit secrets to the repository. - Example frontend env: `VITE_API_URL=http://localhost:3000` - Example backend env: `DATABASE_PATH=./data.db` - Store sensitive config in `.env` files - Use `DATABASE_PATH` for SQLite location