# LeoCRM — AGENTS.md **Projekt:** leocrm | **Stack:** FastAPI + SQLAlchemy + PostgreSQL 16 (pgvector) + React/TypeScript/Vite/Tailwind --- ## 1. Build & Test Commands ```bash # Backend uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 python -m pytest -v --tb=short python -m pytest tests/test_auth.py -v --tb=short alembic upgrade head alembic revision --autogenerate -m "description" # Frontend cd frontend && npm run dev cd frontend && npm run build cd frontend && npx vitest run --reporter=verbose cd frontend && npx tsc --noEmit # Docker docker compose up -d docker compose logs -f backend ``` --- ## 2. Test Rules - TDD: failing test first → implement → refactor - NEVER modify tests to make them pass — fix the code - Test DB: ephemeral PostgreSQL, NEVER production DB - Mock external services (SMTP, IMAP, OnlyOffice) with AsyncMock - Tests must be deterministic and isolated --- ## 3. Code Conventions ### Backend - Async first: all routes/services `async def` - UUID primary keys only, never integer auto-increment - TIMESTAMPTZ only, never naive datetime - Soft-delete via `deleted_at IS NULL`; hard-delete only with `?gdpr=true` - Pydantic schemas validate input, never validate in routes - All mutations create audit log entries - snake_case files/functions, PascalCase classes - Schemas: `Create`, `Update`, `Read` ### Frontend - TypeScript strict, no `any` - Functional components only, no class components - TanStack Query for server state, Zustand for client state only - React Hook Form + Zod for all forms - Tailwind utility classes, no inline styles - i18n via `t()` from react-i18next, no hardcoded strings - ARIA attributes on all interactive elements, 44px touch targets - PascalCase.tsx for components, camelCase.ts for utilities ### Git - Conventional Commits: `feat(core): ...`, `fix(dms): ...` - Squash merge to main after review --- ## 4. Forbidden Patterns ### Backend - ❌ SQLite — PostgreSQL 16 only - ❌ Jinja2/server-side HTML rendering — API-only backend - ❌ Cross-tenant data access — ORM auto-filter must not be bypassed - ❌ Plaintext passwords — bcrypt cost=12 - ❌ JWT auth — session-based with HttpOnly cookies only - ❌ Naive datetime — TIMESTAMPTZ only - ❌ Integer IDs — UUID only - ❌ Hard-delete without `?gdpr=true` - ❌ Manual tenant filter — ORM auto-filter handles it - ❌ Sync I/O in routes — use asyncpg, aiofiles - ❌ Raw SQL without tenant_id check - ❌ Secrets in code — env vars only - ❌ Unvalidated input — Pydantic schemas required - ❌ Missing audit log on mutations - ❌ Plugin tables without tenant_id ### Frontend - ❌ Class components - ❌ Inline styles — Tailwind only - ❌ Hardcoded strings — use `t()` - ❌ Manual fetch/axios in components — use TanStack Query - ❌ Server data in Zustand - ❌ `any` types - ❌ Missing ARIA attributes - ❌ Touch targets < 44px - ❌ Direct DOM manipulation — use React refs - ❌ `dangerouslySetInnerHTML` without sanitization ### Deployment - ❌ Running as root in container — use app:app - ❌ Exposed DB port in production - ❌ Missing Docker health checks - ❌ Ephemeral storage — use named volumes - ❌ Secrets in docker-compose.yml --- ## 5. Quality Gates - Per-Task: tests pass, coverage met, tsc/ruff clean, build succeeds, no forbidden patterns - Phase: all tasks pass → quality_reviewer review → user checkpoint - Release: all tasks complete → release_auditor audit → Docker builds → health 200 → E2E pass --- ## 6. ADRs - ADR-01: PostgreSQL 16 (not SQLite) - ADR-02: ARQ (not Celery) - ADR-03: Built-in plugins with manifest (not pip-install) - ADR-04: TanStack Query (not Redux) - ADR-05: Session-based auth (not JWT) - ADR-06: Soft-delete with `deleted_at` Full architecture: `architecture.md` | Full task graph: `task_graph.json`