6520e88d53
- architecture.md (2019 lines): 73/73 v1 features, RLS policies, CORS, auth rate limiting, v2 FKs removed - task_graph.json v2.1.0: 14 tasks (7 v1 + 7 v2), 143 features, 298 ACs, all dict test_specs - AGENTS.md: 14 tasks mapped, T07a/T07b split, v1/v2 phase plan - Quality gate reviews: Round 1, 2, 3 (all passed) - Security review: APPROVED_WITH_CONCERNS (0 critical, 7 major, 8 minor) - Architecture feasibility review: FEASIBLE_WITH_RISKS (3 critical fixed, 5 major fixed) - All 3 critical issues from feasibility review resolved - All pre-implementation security items addressed
24 KiB
24 KiB
LeoCRM — AGENTS.md
Projekt: leocrm Erstellt: 2026-06-28 Status: Draft — ready for implementation
1. Build & Test Commands
Backend (Python / FastAPI)
Setup
cd backend
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
Run Dev Server
cd backend
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
Database Migrations (Alembic)
cd backend
# Generate migration after model changes
alembic revision --autogenerate -m "description"
# Apply migrations
alembic upgrade head
# Rollback one migration
alembic downgrade -1
Run All Backend Tests
cd backend
python -m pytest -v --tb=short
Run Specific Test File
cd backend
python -m pytest tests/test_auth.py -v --tb=short
Run Tests with Coverage
cd backend
python -m pytest --cov=app --cov-report=term-missing --cov-report=html
Run Tests with Grep Filter
cd backend
python -m pytest -k 'tenant or auth' -v
Type Checking
cd backend
mypy app/ --ignore-missing-imports
Linting
cd backend
ruff check app/
ruff format app/
Frontend (React / Vite / TypeScript)
Setup
cd frontend
npm install
Run Dev Server
cd frontend
npm run dev
Build Production
cd frontend
npm run build
Run All Frontend Tests
cd frontend
npx vitest run --reporter=verbose
Run Tests with Coverage
cd frontend
npx vitest run --coverage
Run Tests in Watch Mode (dev)
cd frontend
npx vitest watch
Type Checking
cd frontend
npx tsc --noEmit
Linting
cd frontend
npx eslint src/ --ext .ts,.tsx
Docker Compose (Full Stack)
Build All Services
docker compose build
Start All Services
docker compose up -d
View Logs
docker compose logs -f backend
Stop All Services
docker compose down
Validate Compose Config
docker compose config --quiet
E2E Tests (Playwright)
cd e2e
npx playwright install
npx playwright test
2. Test Rules
TDD (Test-Driven Development)
- Red-Green-Refactor: Write failing test first → implement minimum code to pass → refactor.
- Every new endpoint gets a test BEFORE implementation.
- Every bug fix starts with a reproduction test.
Coverage Targets
| Layer | Coverage Target | Measured By |
|---|---|---|
| Backend Core (app/core/) | 85% | pytest-cov |
| Backend Models+Services | 85% | pytest-cov |
| Backend Routes | 85% | pytest-cov |
| Backend Plugins | 80% | pytest-cov |
| Frontend Components | 75% | vitest coverage |
| Frontend Plugin UI | 70% | vitest coverage |
| E2E (critical paths) | 100% of defined specs | Playwright |
Test File Structure
Backend
backend/tests/
├── conftest.py — Fixtures: test client, test DB, auth helpers, seed data
├── test_auth.py — Auth endpoints, RBAC, password reset
├── test_tenant.py — Tenant isolation, cross-tenant access
├── test_companies.py — Company CRUD, search, filter, pagination, soft-delete
├── test_contacts.py — Contact CRUD, N:M links, GDPR delete
├── test_import_export.py — CSV import/export, XLSX export, dry-run preview
├── test_plugins.py — Plugin lifecycle, event bus, migrations
├── test_dms.py — DMS folders, files, upload, shares, permissions
├── test_calendar.py — Entries, recurrence, kanban, ICS, resources
├── test_mail.py — Accounts, IMAP sync, send, threading, rules, PGP
├── test_tags.py — Tag CRUD, assignment, bulk
├── test_notifications.py — Notification CRUD, unread count
├── test_health.py — Health endpoint
├── test_ai_copilot.py — KI-Copilot API, RBAC enforcement, history
├── test_workflows.py — Workflow CRUD, instances, approval/rejection, event triggers
├── test_monitoring.py — Extended health, Prometheus metrics, alerting
└── test_performance.py — 200k seed, list <500ms, FTS <500ms, streaming export
Frontend
frontend/src/__tests__/
├── components/ — UI component unit tests (Button, Input, Modal, Table, etc.)
├── features/ — Feature integration tests (CompanyList, ContactForm, etc.)
├── hooks/ — Custom hook tests (useDebounce, usePagination, etc.)
├── plugins/ — Plugin UI tests (DMS, Calendar, Mail, Tags)
└── search/ — Global search tests
E2E
e2e/
├── auth.spec.ts — Login → logout flow
├── company-crud.spec.ts — Create → edit → delete company
├── contact-crud.spec.ts — Create → link to company → delete
├── search.spec.ts — Global search
└── plugin-toggle.spec.ts — Activate/deactivate plugin
Test Conventions
- Test names:
test_<action>_<condition>_<expected_result>(e.g.,test_login_with_invalid_credentials_returns_401) - Test structure: Arrange → Act → Assert (AAA pattern)
- Fixtures: Use
conftest.pyfor shared fixtures. No fixture duplication across files. - Test DB: Use in-memory or ephemeral PostgreSQL (via testcontainers or pytest-postgresql). NEVER test against production DB.
- Mocking: Mock external services (SMTP, IMAP, OnlyOffice) in tests. Use
unittest.mock.AsyncMockfor async mocks. - Assertions: Use pytest's native
assertfor backend,expect()from@testing-library/jest-domfor frontend. - No flaky tests: Tests must be deterministic. Use explicit waits, not sleeps.
- Test isolation: Each test must be independent. No test depends on another test's side effects.
Don't Modify Tests Rule
- NEVER modify existing tests to make them pass. If a test fails, fix the code, not the test.
- Exception: If the test itself is wrong (testing incorrect behavior), document why and get approval before changing.
- Test files are owned by the QA process, not the implementer.
3. Conventions
Backend Structure
backend/app/
├── main.py — FastAPI app entry point, lifespan, middleware registration
├── config.py — Pydantic Settings (reads from env vars)
├── deps.py — FastAPI dependency injection (auth, db, tenant, permissions)
├── core/ — Core infrastructure (cross-cutting concerns)
│ ├── db/ — SQLAlchemy engine, session factory, base model
│ ├── tenant.py — TenantMixin, ORM auto-filter, tenant context
│ ├── auth.py — Session auth, password hashing (bcrypt), RBAC
│ ├── event_bus.py — Async in-process event bus
│ ├── service_container.py — DI container
│ ├── storage.py — File storage (local/S3)
│ ├── cache.py — Redis cache wrapper
│ ├── jobs.py — ARQ job queue integration
│ ├── notifications.py — Notification service
│ └── audit.py — Audit log middleware
├── models/ — SQLAlchemy ORM models (one file per domain)
├── schemas/ — Pydantic schemas (request/response, one file per domain)
├── services/ — Business logic (one file per domain)
├── routes/ — FastAPI routers (one file per domain)
├── plugins/ — Plugin system
│ ├── registry.py — Plugin discovery, registration
│ ├── manifest.py — Plugin manifest Pydantic schema
│ ├── lifecycle.py — Install/activate/deactivate/uninstall
│ ├── migrations.py — Plugin DB migration runner
│ ├── ui_registry.py — Plugin UI component registration
│ └── builtins/ — Built-in plugins
│ ├── dms/ — DMS plugin
│ ├── calendar/ — Calendar plugin
│ ├── mail/ — Mail plugin
│ └── tags/ — Tags plugin
└── utils/ — Shared utilities (validation, export, import)
Backend Naming Conventions
- Files:
snake_case.py(e.g.,company_service.py) - Classes:
PascalCase(e.g.,CompanyService,CompanyModel) - Functions/Methods:
snake_case(e.g.,get_company_by_id) - Constants:
UPPER_SNAKE_CASE(e.g.,SESSION_TIMEOUT_HOURS) - Models:
<Entity>Modelsuffix or just<Entity>(e.g.,Company,Contact) - Schemas:
<Entity>Create,<Entity>Update,<Entity>Read,<Entity>List(Pydantic) - Services:
<Entity>Service(e.g.,CompanyService) - Routers:
<entity>_routervariable, file name<entity>_router.py - Tests:
test_<domain>.py(e.g.,test_companies.py)
Backend Code Conventions
- Async first: All route handlers and service methods are
async def. - Type hints: All function signatures have type hints (Python 3.12+ syntax).
- Docstrings: All public functions/classes have docstrings (Google style).
- Error handling: Use FastAPI
HTTPExceptionwith proper status codes. Never raise genericException. - Validation: Pydantic schemas validate input. Never validate in routes directly.
- Tenant scoping: Never query without tenant filter (ORM auto-filter handles this, but be aware).
- UUID: All IDs are UUID. Never use integer auto-increment.
- Timestamps: All datetime fields are
TIMESTAMPTZ. Never use naive datetime. - Soft-delete: Use
deleted_at IS NULLfilter. Never hard-delete without explicitgdpr=trueflag. - Audit: All mutations must create audit log entries. Use the audit middleware/decorator.
Frontend Structure
frontend/src/
├── main.tsx — React entry point
├── App.tsx — Root component, router, providers
├── api/ — API client (axios), interceptors, endpoint definitions
├── components/ — Shared UI components
│ ├── layout/ — Shell, Sidebar, TopBar, ContentArea
│ ├── ui/ — Button, Input, Select, Modal, Toast, Table, Card, Badge, Avatar
│ └── shared/ — EmptyState, LoadingState, ConfirmDialog, Pagination, Skeleton
├── features/ — Feature modules (one folder per feature)
│ ├── auth/ — Login, PasswordReset
│ ├── companies/ — CompanyList, CompanyDetail, CompanyForm
│ ├── contacts/ — ContactList, ContactDetail, ContactForm
│ ├── settings/ — SettingsTree, ProfileSettings, RoleEditor
│ ├── audit/ — AuditLog
│ ├── dashboard/ — Dashboard
│ └── search/ — GlobalSearch
├── plugins/ — Plugin UI loading framework
│ ├── PluginRegistry.tsx — Fetch manifests, register components
│ └── PluginLoader.tsx — Dynamic lazy-loading of plugin components
├── hooks/ — Custom React hooks (useDebounce, usePagination, useAuth, etc.)
├── store/ — Zustand stores (useAuthStore, useUIStore, useTenantStore)
├── i18n/ — react-i18next setup + locale files (de.json, en.json)
├── styles/ — Global CSS, design tokens (Tailwind config), accessibility
└── utils/ — Utilities (format, validation, export, constants)
Frontend Naming Conventions
- Files:
PascalCase.tsxfor components (e.g.,CompanyList.tsx),camelCase.tsfor utilities (e.g.,apiClient.ts) - Components:
PascalCase(e.g.,CompanyList,ContactForm) - Hooks:
use<Feature>(e.g.,useDebounce,useAuth) - Stores:
use<Domain>Store(e.g.,useAuthStore,useUIStore) - Types/Interfaces:
PascalCase(e.g.,CompanyData,ContactFormValues) - API functions:
camelCase(e.g.,getCompanies,createContact) - Test files:
<Component>.test.tsxnext to component or in__tests__/mirror
Frontend Code Conventions
- TypeScript strict:
strict: truein tsconfig.json. Noanytypes. - Functional components: Only function components, no class components.
- Hooks: Custom hooks for reusable logic. No inline hooks in JSX.
- TanStack Query: Server state via
useQuery/useMutation. No manual fetch in components. - Zustand: Client state only (UI toggles, theme, active tenant). No server data in Zustand.
- React Hook Form + Zod: All forms use
react-hook-formwithzodResolver. - Tailwind CSS: No custom CSS files (except global + accessibility). Use Tailwind utility classes.
- i18n: All user-visible strings go through
t()fromreact-i18next. No hardcoded strings. - Accessibility: ARIA attributes on all interactive elements. 44px touch targets. Keyboard navigation.
- Lazy loading: Plugin components use
React.lazy()withSuspenseboundaries.
Git Conventions
- Branch naming:
feature/T01-core-infrastructure,fix/auth-tenant-isolation,hotfix/critical-bug - Commit messages: Conventional Commits format:
feat(core): implement auth system with session-based loginfix(dms): resolve folder permission bypass on movetest(mail): add IMAP sync integration testsrefactor(calendar): extract recurrence engine to separate moduledocs(architecture): update ADR-03 with plugin lifecycle details
- PR titles:
[T01] Core Infrastructure + Multi-Tenant + Auth System - Branch from:
main(or feature branch for sub-features) - Merge strategy: Squash merge to
mainafter review + CI passes
4. Task-Zuweisung (Subagenten pro Task)
Phasen-Plan
v1 Core Phases (Phase 3 — Implementation)
| Phase | Tasks | Parallel | Subagent Profile | Description |
|---|---|---|---|---|
| 1 | T01 | No | implementation_engineer | Foundation: Core, Auth, Multi-Tenant, RLS, Rate Limiting |
| 2 | T02, T03 | Yes (2 agents) | implementation_engineer ×2 | Core entities + Plugin framework parallel |
| 3 | T07a, T09 | Yes (2 agents) | implementation_engineer ×2 | Frontend Shell+Auth+UI Library + KI-Copilot/Workflow parallel |
| 4 | T07b | No | implementation_engineer | Frontend Feature Pages (Companies, Contacts, Settings, Dashboard, Search) |
| 5 | T10 | No | implementation_engineer | Monitoring, Performance, Doku, Environment Config |
v2 Plugin Phases (nach v1 Deployment)
| Phase | Tasks | Parallel | Subagent Profile | Description |
|---|---|---|---|---|
| 6 | T04, T05, T06, T11 | Yes (4 agents) | implementation_engineer ×4 | DMS, Calendar, Mail, Tags+Permissions backends parallel |
| 7 | T08a, T08b, T08c | Yes (3 agents) | implementation_engineer ×3 | Frontend DMS+Tags, Calendar, Mail+Search parallel |
Task-to-Subagent Mapping
| Task ID | Title | Subagent | Dependencies | Phase | Scope |
|---|---|---|---|---|---|
| T01 | Core Infrastructure + Multi-Tenant + Auth | implementation_engineer | — | 1 | v1 |
| T02 | Company + Contact + Import/Export | implementation_engineer | T01 | 2 | v1 |
| T03 | Plugin System Framework | implementation_engineer | T01 | 2 | v1 |
| T07a | Frontend SPA — Shell, Auth, Routing, i18n, UI Library | implementation_engineer | T01 | 3 | v1 |
| T07b | Frontend SPA — Companies, Contacts, Settings, Dashboard, Search | implementation_engineer | T01, T02, T07a | 4 | v1 |
| T09 | KI-Copilot + Workflow Engine | implementation_engineer | T01, T02 | 3 | v1 |
| T10 | Monitoring + Performance + Doku + Env Config | implementation_engineer | T01, T02 | 5 | v1 |
| T04 | DMS Plugin Backend | implementation_engineer | T01, T03 | 6 | v2 |
| T05 | Calendar Plugin Backend | implementation_engineer | T01, T03 | 6 | v2 |
| T06 | Mail Plugin Backend | implementation_engineer | T01, T03 | 6 | v2 |
| T11 | Tags + Permissions + Entity Links Backend | implementation_engineer | T01, T03 | 6 | v2 |
| T08a | Frontend DMS + Tags + Permissions UI | implementation_engineer | T04, T07b | 7 | v2 |
| T08b | Frontend Calendar UI | implementation_engineer | T05, T07b | 7 | v2 |
| T08c | Frontend Mail + Global Search UI | implementation_engineer | T06, T07b | 7 | v2 |
Parallelization Notes
v1 Phases:
- Phase 2: T02 (Company/Contact) and T03 (Plugin Framework) are independent after T01 — safe to run in parallel.
- Phase 3: T07a (Frontend Shell+Auth+UI Library) depends only on T01. T09 (KI/Workflow) depends on T01+T02. Both can run in parallel if API contracts are frozen.
- Phase 4: T07b (Frontend Feature Pages) depends on T07a (UI library, routing, auth) + T02 (company/contact API). Must run after T07a.
- Phase 5: T10 (Monitoring+Doku) depends on T01+T02. Can run parallel with T07b.
v2 Phases (after v1 deployment):
- Phase 6: T04 (DMS), T05 (Calendar), T06 (Mail), T11 (Tags+Perm) all depend on T01+T03 — safe to run in parallel.
- Phase 7: T08a/T08b/T08c depend on T07b + respective backend (T04/T05/T06) — safe to run in parallel.
Block Rules
- Block = max 3 Tasks per implementation block.
- After each block: quality_reviewer review → block_compactor → context_compactor → User checkpoint.
- quality_reviewer and release_auditor do NOT count toward the 3-task limit.
- After 3 blocks (9 tasks): release_auditor runs full audit.
- Token budget: ~3000 tokens per task. If tool result >5000 tokens: context_compactor.
5. Forbidden Patterns
Backend Forbidden
- ❌ SQLite: No SQLite as database. PostgreSQL 16 only (ADR-01).
- ❌ Jinja2: No server-side HTML rendering. API-only backend (ADR-03).
- ❌ Cross-Tenant Data Access: No query without tenant_id filter. ORM auto-filter must not be bypassed.
- ❌ Plaintext Passwords: Passwords must be bcrypt-hashed (cost=12). Never store or log plaintext.
- ❌ JWT Tokens: No JWT auth in v1. Session-based auth with HttpOnly cookies only (ADR-05).
- ❌ Naive Datetime: All datetime fields must be timezone-aware (TIMESTAMPTZ). Never use
datetime.now()without tz. - ❌ Integer IDs: All primary keys are UUID. Never use auto-increment integer IDs.
- ❌ Hard-Delete without GDPR flag: Companies/Contacts use soft-delete. Hard-delete only with explicit
?gdpr=true. - ❌ Manual Tenant Filter: Never manually add
.filter(Tenant.id == x)in services. The ORM auto-filter handles this. - ❌ Sync I/O in Routes: All route handlers are
async def. Never use blocking I/O (useasyncpg,aiofiles, etc.). - ❌ Raw SQL without Tenant Check: Any raw SQL query must explicitly include
tenant_idfilter. - ❌ Secrets in Code: No hardcoded secrets. All secrets via environment variables.
- ❌ Unvalidated Input: All request bodies validated by Pydantic schemas. Never trust raw request data.
- ❌ Missing Audit Log: All create/update/delete operations must create audit log entries.
- ❌ Plugin Tables without tenant_id: All plugin-created tables must include
tenant_idcolumn. The migration validator enforces this.
Frontend Forbidden
- ❌ Class Components: No class components. Functional components with hooks only.
- ❌ Inline Styles: No
style={{}}props. Use Tailwind utility classes. - ❌ Hardcoded Strings: No user-visible hardcoded strings. Use
t()from i18n. - ❌ Manual Fetch in Components: No
fetch()oraxioscalls in components. Use TanStack Query hooks. - ❌ Server Data in Zustand: Zustand is for client state only. Server data goes in TanStack Query.
- ❌
anyTypes: Noanytype. Use proper TypeScript types. - ❌ Missing ARIA Attributes: All interactive elements must have ARIA labels.
- ❌ Touch Targets < 44px: All buttons/links must have minimum 44px touch target.
- ❌ Direct DOM Manipulation: No
document.getElementById()orquerySelector()in components. Use React refs. - ❌ Unsafe HTML Rendering: No
dangerouslySetInnerHTMLwithout sanitization. Mail bodies must be sanitized (DOMPurify equivalent).
Deployment Forbidden
- ❌ Running as Root in Container: Containers run as non-root user (app:app).
- ❌ Exposed DB Port in Production: PostgreSQL port (5432) must not be exposed externally in production.
- ❌ No Health Check: All services must have Docker health checks configured.
- ❌ No Volume for Storage: File storage must use a named volume, not ephemeral container storage.
- ❌ Secrets in docker-compose.yml: No secrets in compose file. Use
.envfile or Docker secrets.
6. Quality Gates
Per-Task Quality Gate
Before a task is marked complete:
- All test_spec commands must pass.
- Coverage target must be met (measured by pytest-cov / vitest coverage).
- TypeScript compiles without errors (
tsc --noEmit). - Linting passes (ruff for backend, eslint for frontend).
- Build succeeds (Vite build for frontend, no build step for backend).
- No forbidden patterns detected.
- All acceptance criteria verified as testable.
Phase Gate (after each phase)
- All tasks in the phase pass their quality gates.
- quality_reviewer subagent reviews the phase output.
- No critical issues from quality_reviewer.
- Block compactor saves progress.
- User checkpoint before next phase.
Release Gate (before v1 deployment)
- All 7 v1 tasks complete (T01, T02, T03, T07a, T07b, T09, T10).
- release_auditor runs full audit.
- Docker Compose builds and starts successfully.
- Health endpoint returns 200.
- E2E tests (Playwright) pass.
- All forbidden patterns checked.
v2 Release Gate (before v2 plugin deployment)
- All 7 v2 tasks complete (T04, T05, T06, T11, T08a, T08b, T08c).
- release_auditor runs full audit.
- All plugin backends + frontends pass quality gates.
- Plugin install/activate/deactivate lifecycle tested.
- All forbidden patterns checked.
7. Environment Setup
Development Environment
| Variable | Value | Purpose |
|---|---|---|
POSTGRES_HOST |
localhost (dev) / postgres (docker) |
Database host |
POSTGRES_PORT |
5432 |
Database port |
POSTGRES_DB |
leocrm |
Database name |
POSTGRES_USER |
leocrm |
Database user |
POSTGRES_PASSWORD |
(from .env) | Database password |
REDIS_URL |
redis://localhost:6379/0 |
Redis for cache + sessions + jobs |
LEOCRM_SECRET_KEY |
(min 32 chars) | Session signing secret |
SESSION_TIMEOUT_HOURS |
8 |
Session expiry |
MAIL_ENCRYPTION_KEY |
(32-byte hex) | AES-256 key for mail credentials |
STORAGE_BACKEND |
local (dev) / s3 (prod) |
File storage backend |
STORAGE_PATH |
/data/leocrm/storage |
Local storage path |
ONLYOFFICE_URL |
http://onlyoffice:80 |
OnlyOffice document server |
LOG_LEVEL |
INFO |
Logging level |
Test Environment
- Test DB: Ephemeral PostgreSQL (pytest-postgresql or testcontainers).
- Test Redis: Ephemeral or fakeredis.
- External services (IMAP, SMTP, OnlyOffice): Mocked via
unittest.mock.AsyncMock. - Test fixtures in
conftest.pyprovide: test client, authenticated client (per role), seeded data.
8. Architecture Reference
Full architecture details: architecture.md
Full task graph with test specs: task_graph.json
Key ADRs:
- ADR-01: PostgreSQL 16 (not SQLite)
- ADR-02: ARQ (not Celery)
- ADR-03: Built-in plugins with manifest (not dynamic pip-install)
- ADR-04: TanStack Query (not Redux)
- ADR-05: Session-based auth (not JWT)
- ADR-06: Soft-delete with
deleted_atcolumn
Handoff
- AGENTS.md status: COMPLETE
- task_graph.json status: COMPLETE (14 tasks: 7 v1 + 7 v2, all with test_spec, 143 features covered, v1/v2 separated, v2.1.0)
- architecture.md status: COMPLETE (73/73 v1 features referenced, v2 sections marked)
- Ready for v1 implementation: YES (pending quality_reviewer review + plan_mode transition to implementation_allowed)
- v2 implementation: After v1 deployment, separate phase