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

4.9 KiB

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

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)

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)

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

// 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)

@Injectable()
export class AuthService {
  constructor(
    private userService: UserService,
    private jwtService: JwtService,
  ) {}

  async login(dto: LoginUserDto): Promise<AuthResponse> {
    // Implementation
  }
}

Frontend Hooks (TanStack Query)

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

{ 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