This commit is contained in:
echo 2026-02-22 00:44:46 +01:00
parent f20842b3ab
commit 83c60ce40d

277
AGENTS.md
View File

@ -1,218 +1,169 @@
# Agent Guidelines for placebo.mk # Agent Guidelines for placebo.mk
## Project Overview ## Project Overview
News site in Macedonia with sarcastic tone. Minimalistic design using TanStack stack. Macedonian satirical news site using TanStack stack + NestJS backend.
## Tech Stack ## Tech Stack
- **Frontend**: TanStack (React 19, Query, Router) + Vite + Tailwind CSS + shadcn/ui - **Frontend**: React 19 + TanStack (Query, Router) + Vite + Tailwind CSS + shadcn/ui
- **Backend**: NestJS + TypeORM + SQLite - **Backend**: NestJS + TypeORM + SQLite
- **CMS**: Strapi (in /cms) - **CMS**: Strapi (in /cms)
## Root-Level Commands ## Commands
### Root Level
```bash ```bash
# Docker development
npm run docker:up # Start all services
npm run docker:down # Stop all services
npm run docker:build # Rebuild containers
npm run docker:logs # View logs
npm run dev:docker # Start docker dev (alias)
# Local development
npm run dev:local # Start backend & frontend locally npm run dev:local # Start backend & frontend locally
npm run dev:backend:local # Backend only (local env) npm run dev:docker # Start via docker-compose
npm run dev:frontend:local # Frontend only (local env)
# Code quality
npm run lint # Lint both projects npm run lint # Lint both projects
npm run lint:fix # Auto-fix lint issues npm run lint:fix # Auto-fix lint issues
npm run type-check # Type check both projects npm run type-check # Type check both projects
# Database operations
npm run db:backup # Backup database
npm run db:restore # Restore database
npm run db:reset # Reset database
# Environment
npm run reset:env # Reset to docker environment
``` ```
## Build Commands ### Backend (cd backend)
### Backend (NestJS)
```bash ```bash
cd backend
npm install
npm run start:dev # Watch mode npm run start:dev # Watch mode
npm run start:debug # Debug mode npm run lint / lint:fix # ESLint
npm run build
npm run start:prod
npm run lint # Lint
npm run lint:fix # Auto-fix
npm run type-check # TypeScript check npm run type-check # TypeScript check
npm test # All tests npm test # All tests
npm test:watch # Watch mode tests npm test app.service.spec # Single file (omit .ts)
npm test -t "should return" # By pattern
npm test:cov # Coverage npm test:cov # Coverage
npm test:e2e # E2E tests npm test:e2e # E2E tests
npm test app.service.spec.ts # Single file
npm test -t "should return" # By test name pattern
npm run format # Format with Prettier
npm run dev:local # Local env with .env.local
npm run dev:docker # Docker env with .env.docker
``` ```
### Frontend (TanStack) ### Frontend (cd frontend)
```bash ```bash
cd frontend
npm install
npm run dev # Vite dev server npm run dev # Vite dev server
npm run build npm run lint / lint:fix # ESLint
npm run preview
npm run lint # Lint
npm run lint:fix # Auto-fix
npm run type-check # TypeScript check npm run type-check # TypeScript check
npm test # All tests (Vitest) 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:ui # Vitest UI
npm test:coverage # Test coverage npm test:coverage # Coverage
npm test Header.test.tsx # Single file
npm test -t "renders" # By test name pattern
npm run dev:local # Local env with .env.local
npm run dev:docker # Docker env with .env.docker
``` ```
## Code Style ## Code Style
### Formatting & TypeScript ### TypeScript
- Use Prettier (2 spaces, single quotes, trailing commas, 100 char max) - Strict mode: `noImplicitAny`, `strictNullChecks`, `noFallthroughCasesInSwitch`
- Strict TypeScript - no implicit `any`, avoid `any`, use `unknown` - No implicit `any` - use `unknown` when type uncertain
- Explicit return types for public methods - Explicit return types for public methods
- Prefer interfaces over types for objects - Prefer `interface` over `type` for objects
- Use `readonly` for immutable properties - Use `readonly` for immutable properties
- Backend: `noImplicitAny: true`, `strictNullChecks: true`
- Frontend: Path alias `@/*` maps to `./src/*`
### Naming Conventions ### Formatting (Prettier)
- **Files**: kebab-case (`user-profile.ts`, `auth.service.ts`) - Single quotes, trailing commas, 2-space indent
- **Classes**: PascalCase (`UserService`, `AuthGuard`) - No semicolons in comments
- **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 ### Naming
- External libraries first, then internal modules, then relative imports | Element | Convention | Example |
- Group imports with blank lines between groups |---------|------------|---------|
- Example: | Files | kebab-case | `user-profile.ts`, `auth.service.ts` |
```typescript | Classes | PascalCase | `UserService`, `AuthGuard` |
// External | Functions/Variables | camelCase | `getUser`, `isLoading` |
import { Module } from '@nestjs/common'; | Constants | UPPER_SNAKE_CASE | `MAX_RETRIES` |
import { TypeOrmModule } from '@nestjs/typeorm'; | Private members | underscore prefix | `_cache`, `_validate()` |
| Interfaces | PascalCase (no I prefix) | `User`, `ApiResponse` |
// Internal modules
import { AuthModule } from '../auth/auth.module';
// Relative imports
import { UserService } from './user.service';
import { UserController } from './user.controller';
```
### 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 ### File Structure
``` ```
backend/src/ backend/src/
modules/feature-name/ modules/{feature}/
feature-name.module.ts {feature}.module.ts
feature-name.controller.ts {feature}.controller.ts
feature-name.service.ts {feature}.service.ts
feature-name.entity.ts {feature}.dto.ts
feature-name.dto.ts
common/{decorators,filters,guards,interceptors,pipes} common/{decorators,filters,guards,interceptors,pipes}
config/ entities.ts # All TypeORM entities
frontend/src/ frontend/src/
components/{ui,layout,features}/ components/{ui,layout,features,admin,routes}/
hooks/ hooks/ # Custom React hooks
lib/ queries/ # TanStack Query hooks
queries/ lib/ # Utilities, API client
routes/ routes/ # TanStack Router routes
types/ types/ # TypeScript types
utils/ ```
### 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 ### Error Handling
- **Backend**: Use NestJS exceptions (`NotFoundException`, `BadRequestException`), custom exceptions, Logger - **Backend**: NestJS exceptions (`NotFoundException`, `BadRequestException`)
- **Frontend**: Error boundaries, try-catch with user-friendly messages - **Frontend**: Error boundaries, try-catch with user-friendly messages
### API Conventions ### API Response Format
- REST endpoints: `/api/v1/resources` ```typescript
- JSON fields: snake_case { data: T, meta: { total, page, limit }, error?: { code, message } }
- Pagination: `page`, `limit` query params ```
- Response format:
```typescript
{
data: T,
meta: { total, page, limit },
error?: { code, message }
}
```
### Testing ## Testing
- **Backend**: Jest with ts-jest transformer - **Backend**: Jest (`*.spec.ts`), AAA pattern, mock dependencies
- **Frontend**: Vitest with React Testing Library patterns - **Frontend**: Vitest + React Testing Library (`*.test.tsx`)
- Unit tests for services/hooks (AAA pattern: Arrange-Act-Assert) - Descriptive names: `should return user data when valid ID provided`
- Integration tests for API endpoints
- E2E tests for critical user flows
- Descriptive test names that explain what is tested (e.g., `should return user data when valid ID provided`)
- Mock external dependencies (use Jest for backend, Vitest for frontend)
- Run `npm test` for all tests or target specific files/names
- Test files: `*.spec.ts` (backend), `*.test.tsx` (frontend)
- Coverage reports: `npm test:cov` (backend), `npm test:coverage` (frontend)
### Git Workflow ## Git Commits
- Conventional commits: `feat:`, `fix:`, `refactor:`, `test:`, `docs:`, `chore:` - Conventional: `feat:`, `fix:`, `refactor:`, `test:`, `docs:`, `chore:`
- Keep commits atomic and focused - Atomic, imperative mood
- Write clear commit messages in imperative mood
### Component Guidelines ## UI Components
- Keep components small and focused (< 200 lines) - Use shadcn/ui from `components/ui/`
- Use functional components with hooks - CVA for variants, clsx + tailwind-merge for classes
- 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 ## Agent Instructions
- Use TypeORM for SQLite - **ALWAYS** run `npm run lint` and `npm run type-check` after changes
- Define entities with proper relationships - **NEVER** commit without explicit request
- 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
- Use `@nestjs/config` for backend environment management
- Frontend env vars must be prefixed with `VITE_`
## Agent-Specific Instructions
- **ALWAYS** run `npm run lint` and `npm run type-check` after making changes
- **NEVER** commit changes without explicit user request
- **ALWAYS** follow existing code patterns and conventions
- **PREFER** editing existing files over creating new ones - **PREFER** editing existing files over creating new ones
- **VERIFY** tests pass before considering work complete - **VERIFY** tests pass before considering work complete
- **USE** the root-level commands for common operations - **CHECK** both backend/frontend when making API changes
- **CHECK** both backend and frontend when making API changes