From 51c9b467b27e3fbb9d9464b9e0ae0c1e0426f559 Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Tue, 4 Aug 2026 11:41:18 +0200 Subject: [PATCH] Fix: verify_ws_origin async + await callers - auth.py: verify_ws_origin is now async def - kommunikation/routes.py: await verify_ws_origin - ai_ui_control/routes.py: await verify_ws_origin --- .a0proj/mcp_servers.json | 3 + .a0proj/project.json | 16 + AGENTS.md | 604 +++---------------- AGENTS.md.bak | 571 ++++++++++++++++++ app/core/auth.py | 2 +- app/plugins/builtins/ai_ui_control/routes.py | 2 +- app/plugins/builtins/kommunikation/routes.py | 2 +- 7 files changed, 672 insertions(+), 528 deletions(-) create mode 100644 .a0proj/mcp_servers.json create mode 100644 .a0proj/project.json create mode 100644 AGENTS.md.bak diff --git a/.a0proj/mcp_servers.json b/.a0proj/mcp_servers.json new file mode 100644 index 0000000..3cad2de --- /dev/null +++ b/.a0proj/mcp_servers.json @@ -0,0 +1,3 @@ +{ + "mcpServers": {} +} diff --git a/.a0proj/project.json b/.a0proj/project.json new file mode 100644 index 0000000..013d488 --- /dev/null +++ b/.a0proj/project.json @@ -0,0 +1,16 @@ +{ + "title": "LeoCRM", + "description": "Mini-CRM mit Kontakten, Mail, DMS, Kalender, Tasks und Plugin-System. FastAPI Backend + React/TypeScript Frontend. Deployiert über Coolify auf Hetzner VPS.", + "instructions": "Du arbeitest am LeoCRM-Projekt.\n\n## Projekt-Übersicht\n- **Repo**: /a0/usr/workdir/leocrm-fix (Git: Forgejo Leopoldadmin/leocrm)\n- **Frontend**: React + TypeScript + Vite + Tailwind, in frontend/\n- **Backend**: FastAPI + SQLAlchemy + PostgreSQL (pgvector), in app/\n- **Tests**: frontend/src/__tests__/ (Vitest), tests/ (pytest)\n- **Migrations**: alembic/versions/\n- **Plugins**: app/plugins/builtins/ (Mail, DMS, Tasks, Calendar, etc.)\n- **Plugin-Manifest-Schema**: app/plugins/manifest.py\n\n## Deploy\n### Frontend-only (~20s)\n```bash\nbash /a0/usr/workdir/leocrm-fix/scripts/fast-deploy.sh frontend\n```\nBaut lokal, kopiert dist/ direkt in den laufenden Container. Kein Coolify-Rebuild.\n\n### Full Deploy (~2min, fuer Backend-Aenderungen)\n```bash\nbash /a0/usr/workdir/leocrm-fix/scripts/fast-deploy.sh full\n```\nTriggert Coolify-Rebuild ueber deploy.py.\n\n### Wann was?\n- Nur Frontend (TSX, CSS): frontend\n- Backend (Python, Dockerfile, requirements): full\n\n## Git Workflow\n1. Aenderungen in /a0/usr/workdir/leocrm-fix\n2. git add -A && git commit -m '...' && git push origin main\n3. Dann deploy\n\n## Server & Container\n- Host: 46.225.91.159 (root, SSH Key: /a0/usr/workdir/.ssh/coolify-01-root)\n- Coolify: https://server.media-on.de\n- App UUID: stvabl4vaqru7jclx4ittzr3\n- Container-Name aendert sich bei jedem Coolify-Deploy (Suffix)\n- Frontend-Pfad im Container: /app/frontend/dist\n- Worker-Container: leocrm-worker\n- DB: crm-postgres (pgvector/pgvector:pg16)\n- Redis: crm-redis (redis:7-alpine)\n\n## Zugaenge\n- Web-UI: https://crm.media-on.de/login\n- Forgejo: https://forgejo.media-on.de/Leopoldadmin/leocrm\n- Sensible Credentials siehe leocrm-deploy.promptinclude.md im workdir\n\n## Wichtige Dateien\n- FIX-PLAN-V2.md — Aktueller Fix-Plan\n- architecture.md — Architektur-Dokumentation\n- DEPLOY.md — Deployment-Anleitung\n- COOLIFY_SETUP.md — Coolify-Konfiguration\n- .a0/ — Projekt-Status (current_status.md, next_steps.md, risks.md, worklog.md)\n\n## Regeln\n- Frontend-Style an bestehenden Komponenten orientieren (Mail-Plugin als Referenz)\n- Bei UI-Aenderungen immer Mail-Plugin als Referenz pruefen\n- Tests nicht editieren ausser explizit verlangt\n- Minimal focused changes, bestehenden Style beibehalten\n- Bei destruktiven Aenderungen: User fragen", + "include_agents_md": true, + "color": "#3b82f6", + "git_url": "https://forgejo.media-on.de/Leopoldadmin/leocrm.git", + "file_structure": { + "enabled": true, + "max_depth": 5, + "max_files": 20, + "max_folders": 20, + "max_lines": 250, + "gitignore": "node_modules\n__pycache__\n*.pyc\n.env\n.git\n.venv\ndist\n" + } +} diff --git a/AGENTS.md b/AGENTS.md index 9ba1d82..cbb43be 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,571 +1,125 @@ # LeoCRM — AGENTS.md -**Projekt:** leocrm -**Erstellt:** 2026-06-28 -**Status:** Draft — ready for implementation +**Projekt:** leocrm | **Stack:** FastAPI + SQLAlchemy + PostgreSQL 16 (pgvector) + React/TypeScript/Vite/Tailwind --- ## 1. Build & Test Commands -### Backend (Python / FastAPI) - -#### Setup ```bash - -python -m venv .venv -source .venv/bin/activate -pip install -e ".[dev]" -``` - -#### Run Dev Server -```bash - +# Backend uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 -``` - -#### Database Migrations (Alembic) -```bash - -# 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 -```bash - python -m pytest -v --tb=short -``` - -#### Run Specific Test File -```bash - python -m pytest tests/test_auth.py -v --tb=short -``` +alembic upgrade head +alembic revision --autogenerate -m "description" -#### Run Tests with Coverage -```bash +# Frontend +cd frontend && npm run dev +cd frontend && npm run build +cd frontend && npx vitest run --reporter=verbose +cd frontend && npx tsc --noEmit -python -m pytest --cov=app --cov-report=term-missing --cov-report=html -``` - -#### Run Tests with Grep Filter -```bash - -python -m pytest -k 'tenant or auth' -v -``` - -#### Type Checking -```bash - -mypy app/ --ignore-missing-imports -``` - -#### Linting -```bash - -ruff check app/ -ruff format app/ -``` - -### Frontend (React / Vite / TypeScript) - -#### Setup -```bash -cd frontend -npm install -``` - -#### Run Dev Server -```bash -cd frontend -npm run dev -``` - -#### Build Production -```bash -cd frontend -npm run build -``` - -#### Run All Frontend Tests -```bash -cd frontend -npx vitest run --reporter=verbose -``` - -#### Run Tests with Coverage -```bash -cd frontend -npx vitest run --coverage -``` - -#### Run Tests in Watch Mode (dev) -```bash -cd frontend -npx vitest watch -``` - -#### Type Checking -```bash -cd frontend -npx tsc --noEmit -``` - -#### Linting -```bash -cd frontend -npx eslint src/ --ext .ts,.tsx -``` - -### Docker Compose (Full Stack) - -#### Build All Services -```bash -docker compose build -``` - -#### Start All Services -```bash +# Docker docker compose up -d -``` - -#### View Logs -```bash docker compose logs -f backend ``` -#### Stop All Services -```bash -docker compose down -``` - -#### Validate Compose Config -```bash -docker compose config --quiet -``` - -### E2E Tests (Playwright) - -```bash -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___` (e.g., `test_login_with_invalid_credentials_returns_401`) -- **Test structure:** Arrange → Act → Assert (AAA pattern) -- **Fixtures:** Use `conftest.py` for 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.AsyncMock` for async mocks. -- **Assertions:** Use pytest's native `assert` for backend, `expect()` from `@testing-library/jest-dom` for 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.** +- 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. Conventions +## 3. Code Conventions -### Backend Structure +### 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` -``` -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) -``` +### 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 -### 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:** `Model` suffix or just `` (e.g., `Company`, `Contact`) -- **Schemas:** `Create`, `Update`, `Read`, `List` (Pydantic) -- **Services:** `Service` (e.g., `CompanyService`) -- **Routers:** `_router` variable, file name `_router.py` -- **Tests:** `test_.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 `HTTPException` with proper status codes. Never raise generic `Exception`. -- **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 NULL` filter. Never hard-delete without explicit `gdpr=true` flag. -- **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.tsx` for components (e.g., `CompanyList.tsx`), `camelCase.ts` for utilities (e.g., `apiClient.ts`) -- **Components:** `PascalCase` (e.g., `CompanyList`, `ContactForm`) -- **Hooks:** `use` (e.g., `useDebounce`, `useAuth`) -- **Stores:** `useStore` (e.g., `useAuthStore`, `useUIStore`) -- **Types/Interfaces:** `PascalCase` (e.g., `CompanyData`, `ContactFormValues`) -- **API functions:** `camelCase` (e.g., `getCompanies`, `createContact`) -- **Test files:** `.test.tsx` next to component or in `__tests__/` mirror - -### Frontend Code Conventions - -- **TypeScript strict:** `strict: true` in tsconfig.json. No `any` types. -- **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-form` with `zodResolver`. -- **Tailwind CSS:** No custom CSS files (except global + accessibility). Use Tailwind utility classes. -- **i18n:** All user-visible strings go through `t()` from `react-i18next`. No hardcoded strings. -- **Accessibility:** ARIA attributes on all interactive elements. 44px touch targets. Keyboard navigation. -- **Lazy loading:** Plugin components use `React.lazy()` with `Suspense` boundaries. - -### 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 login` - - `fix(dms): resolve folder permission bypass on move` - - `test(mail): add IMAP sync integration tests` - - `refactor(calendar): extract recurrence engine to separate module` - - `docs(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 `main` after review + CI passes +### Git +- Conventional Commits: `feat(core): ...`, `fix(dms): ...` +- Squash merge to main after review --- -## 4. Task-Zuweisung (Subagenten pro Task) +## 4. Forbidden Patterns -### Phasen-Plan +### 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 -#### v1 Core Phases (Phase 3 — Implementation) +### 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 -| 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. +### 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. Forbidden Patterns +## 5. Quality Gates -### 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 (use `asyncpg`, `aiofiles`, etc.). -- ❌ **Raw SQL without Tenant Check:** Any raw SQL query must explicitly include `tenant_id` filter. -- ❌ **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_id` column. 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()` or `axios` calls in components. Use TanStack Query hooks. -- ❌ **Server Data in Zustand:** Zustand is for client state only. Server data goes in TanStack Query. -- ❌ **`any` Types:** No `any` type. 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()` or `querySelector()` in components. Use React refs. -- ❌ **Unsafe HTML Rendering:** No `dangerouslySetInnerHTML` without 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 `.env` file or Docker secrets. +- 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. Quality Gates +## 6. ADRs -### Per-Task Quality Gate - -Before a task is marked complete: -1. All test_spec commands must pass. -2. Coverage target must be met (measured by pytest-cov / vitest coverage). -3. TypeScript compiles without errors (`tsc --noEmit`). -4. Linting passes (ruff for backend, eslint for frontend). -5. Build succeeds (Vite build for frontend, no build step for backend). -6. No forbidden patterns detected. -7. All acceptance criteria verified as testable. - -### Phase Gate (after each phase) - -1. All tasks in the phase pass their quality gates. -2. quality_reviewer subagent reviews the phase output. -3. No critical issues from quality_reviewer. -4. Block compactor saves progress. -5. User checkpoint before next phase. - -### Release Gate (before v1 deployment) - -1. All 7 v1 tasks complete (T01, T02, T03, T07a, T07b, T09, T10). -2. release_auditor runs full audit. -3. Docker Compose builds and starts successfully. -4. Health endpoint returns 200. -5. E2E tests (Playwright) pass. -6. All forbidden patterns checked. - -### v2 Release Gate (before v2 plugin deployment) - -1. All 7 v2 tasks complete (T04, T05, T06, T11, T08a, T08b, T08c). -2. release_auditor runs full audit. -3. All plugin backends + frontends pass quality gates. -4. Plugin install/activate/deactivate lifecycle tested. -5. 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.py` provide: 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-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` column +- ADR-06: Soft-delete with `deleted_at` ---- - -## 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 +Full architecture: `architecture.md` | Full task graph: `task_graph.json` diff --git a/AGENTS.md.bak b/AGENTS.md.bak new file mode 100644 index 0000000..9ba1d82 --- /dev/null +++ b/AGENTS.md.bak @@ -0,0 +1,571 @@ +# LeoCRM — AGENTS.md + +**Projekt:** leocrm +**Erstellt:** 2026-06-28 +**Status:** Draft — ready for implementation + +--- + +## 1. Build & Test Commands + +### Backend (Python / FastAPI) + +#### Setup +```bash + +python -m venv .venv +source .venv/bin/activate +pip install -e ".[dev]" +``` + +#### Run Dev Server +```bash + +uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 +``` + +#### Database Migrations (Alembic) +```bash + +# 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 +```bash + +python -m pytest -v --tb=short +``` + +#### Run Specific Test File +```bash + +python -m pytest tests/test_auth.py -v --tb=short +``` + +#### Run Tests with Coverage +```bash + +python -m pytest --cov=app --cov-report=term-missing --cov-report=html +``` + +#### Run Tests with Grep Filter +```bash + +python -m pytest -k 'tenant or auth' -v +``` + +#### Type Checking +```bash + +mypy app/ --ignore-missing-imports +``` + +#### Linting +```bash + +ruff check app/ +ruff format app/ +``` + +### Frontend (React / Vite / TypeScript) + +#### Setup +```bash +cd frontend +npm install +``` + +#### Run Dev Server +```bash +cd frontend +npm run dev +``` + +#### Build Production +```bash +cd frontend +npm run build +``` + +#### Run All Frontend Tests +```bash +cd frontend +npx vitest run --reporter=verbose +``` + +#### Run Tests with Coverage +```bash +cd frontend +npx vitest run --coverage +``` + +#### Run Tests in Watch Mode (dev) +```bash +cd frontend +npx vitest watch +``` + +#### Type Checking +```bash +cd frontend +npx tsc --noEmit +``` + +#### Linting +```bash +cd frontend +npx eslint src/ --ext .ts,.tsx +``` + +### Docker Compose (Full Stack) + +#### Build All Services +```bash +docker compose build +``` + +#### Start All Services +```bash +docker compose up -d +``` + +#### View Logs +```bash +docker compose logs -f backend +``` + +#### Stop All Services +```bash +docker compose down +``` + +#### Validate Compose Config +```bash +docker compose config --quiet +``` + +### E2E Tests (Playwright) + +```bash +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___` (e.g., `test_login_with_invalid_credentials_returns_401`) +- **Test structure:** Arrange → Act → Assert (AAA pattern) +- **Fixtures:** Use `conftest.py` for 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.AsyncMock` for async mocks. +- **Assertions:** Use pytest's native `assert` for backend, `expect()` from `@testing-library/jest-dom` for 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:** `Model` suffix or just `` (e.g., `Company`, `Contact`) +- **Schemas:** `Create`, `Update`, `Read`, `List` (Pydantic) +- **Services:** `Service` (e.g., `CompanyService`) +- **Routers:** `_router` variable, file name `_router.py` +- **Tests:** `test_.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 `HTTPException` with proper status codes. Never raise generic `Exception`. +- **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 NULL` filter. Never hard-delete without explicit `gdpr=true` flag. +- **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.tsx` for components (e.g., `CompanyList.tsx`), `camelCase.ts` for utilities (e.g., `apiClient.ts`) +- **Components:** `PascalCase` (e.g., `CompanyList`, `ContactForm`) +- **Hooks:** `use` (e.g., `useDebounce`, `useAuth`) +- **Stores:** `useStore` (e.g., `useAuthStore`, `useUIStore`) +- **Types/Interfaces:** `PascalCase` (e.g., `CompanyData`, `ContactFormValues`) +- **API functions:** `camelCase` (e.g., `getCompanies`, `createContact`) +- **Test files:** `.test.tsx` next to component or in `__tests__/` mirror + +### Frontend Code Conventions + +- **TypeScript strict:** `strict: true` in tsconfig.json. No `any` types. +- **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-form` with `zodResolver`. +- **Tailwind CSS:** No custom CSS files (except global + accessibility). Use Tailwind utility classes. +- **i18n:** All user-visible strings go through `t()` from `react-i18next`. No hardcoded strings. +- **Accessibility:** ARIA attributes on all interactive elements. 44px touch targets. Keyboard navigation. +- **Lazy loading:** Plugin components use `React.lazy()` with `Suspense` boundaries. + +### 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 login` + - `fix(dms): resolve folder permission bypass on move` + - `test(mail): add IMAP sync integration tests` + - `refactor(calendar): extract recurrence engine to separate module` + - `docs(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 `main` after 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 (use `asyncpg`, `aiofiles`, etc.). +- ❌ **Raw SQL without Tenant Check:** Any raw SQL query must explicitly include `tenant_id` filter. +- ❌ **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_id` column. 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()` or `axios` calls in components. Use TanStack Query hooks. +- ❌ **Server Data in Zustand:** Zustand is for client state only. Server data goes in TanStack Query. +- ❌ **`any` Types:** No `any` type. 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()` or `querySelector()` in components. Use React refs. +- ❌ **Unsafe HTML Rendering:** No `dangerouslySetInnerHTML` without 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 `.env` file or Docker secrets. + +--- + +## 6. Quality Gates + +### Per-Task Quality Gate + +Before a task is marked complete: +1. All test_spec commands must pass. +2. Coverage target must be met (measured by pytest-cov / vitest coverage). +3. TypeScript compiles without errors (`tsc --noEmit`). +4. Linting passes (ruff for backend, eslint for frontend). +5. Build succeeds (Vite build for frontend, no build step for backend). +6. No forbidden patterns detected. +7. All acceptance criteria verified as testable. + +### Phase Gate (after each phase) + +1. All tasks in the phase pass their quality gates. +2. quality_reviewer subagent reviews the phase output. +3. No critical issues from quality_reviewer. +4. Block compactor saves progress. +5. User checkpoint before next phase. + +### Release Gate (before v1 deployment) + +1. All 7 v1 tasks complete (T01, T02, T03, T07a, T07b, T09, T10). +2. release_auditor runs full audit. +3. Docker Compose builds and starts successfully. +4. Health endpoint returns 200. +5. E2E tests (Playwright) pass. +6. All forbidden patterns checked. + +### v2 Release Gate (before v2 plugin deployment) + +1. All 7 v2 tasks complete (T04, T05, T06, T11, T08a, T08b, T08c). +2. release_auditor runs full audit. +3. All plugin backends + frontends pass quality gates. +4. Plugin install/activate/deactivate lifecycle tested. +5. 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.py` provide: 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_at` column + +--- + +## 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 diff --git a/app/core/auth.py b/app/core/auth.py index ad03f21..6c9e760 100644 --- a/app/core/auth.py +++ b/app/core/auth.py @@ -91,7 +91,7 @@ def hash_token(token: str) -> str: return hashlib.sha256(token.encode()).hexdigest() -def verify_ws_origin(websocket) -> bool: +async def verify_ws_origin(websocket) -> bool: """Verify that the WebSocket upgrade request comes from an allowed origin. Checks the Origin header against the configured CORS origins. diff --git a/app/plugins/builtins/ai_ui_control/routes.py b/app/plugins/builtins/ai_ui_control/routes.py index 0cd01b2..32dc92f 100644 --- a/app/plugins/builtins/ai_ui_control/routes.py +++ b/app/plugins/builtins/ai_ui_control/routes.py @@ -209,7 +209,7 @@ async def ai_ui_control_ws(websocket: WebSocket): from app.core.service_container import get_container settings = get_settings() - if not verify_ws_origin(websocket): + if not await verify_ws_origin(websocket): await websocket.close(code=4003, reason="Origin not allowed") return diff --git a/app/plugins/builtins/kommunikation/routes.py b/app/plugins/builtins/kommunikation/routes.py index abac79b..c3c1a3a 100644 --- a/app/plugins/builtins/kommunikation/routes.py +++ b/app/plugins/builtins/kommunikation/routes.py @@ -477,7 +477,7 @@ async def websocket_endpoint( from app.core.auth import get_session_data, get_redis, verify_ws_origin settings = get_settings() - if not verify_ws_origin(websocket): + if not await verify_ws_origin(websocket): await websocket.close(code=4003, reason="Origin not allowed") return