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
1067 lines
55 KiB
JSON
1067 lines
55 KiB
JSON
{
|
|
"project": "leocrm",
|
|
"version": "2.1.0",
|
|
"created": "2026-06-28",
|
|
"total_tasks": 14,
|
|
"tasks": [
|
|
{
|
|
"id": "T01",
|
|
"title": "Core Infrastructure + Multi-Tenant + Auth System",
|
|
"description": "Komplette Kern-Infrastruktur: SQLAlchemy Engine/Session/Base, TenantMixin mit ORM Auto-Filter, Session-based Auth (Login/Logout/Password-Reset), RBAC mit Rollen/Permissions, CSRF-Schutz, Event Bus, Service Container (DI), Redis Cache, ARQ Job Queue, Notification Service, Audit Log Middleware, Health Endpoint. Models: tenants, users, user_tenants, roles, sessions, audit_log, deletion_log, notifications, password_reset_tokens. Schemas, Services, Routes fuer Auth/User/Role/Tenant. Alembic Initial Migration. conftest.py mit Test-DB Fixtures.",
|
|
"requirement_ids": [
|
|
"F-CORE-01",
|
|
"F-CORE-02",
|
|
"F-CORE-05",
|
|
"F-CORE-07",
|
|
"F-CORE-08",
|
|
"F-CORE-09",
|
|
"F-CORE-10",
|
|
"F-CORE-12",
|
|
"F-CORE-13",
|
|
"F-AUTH-01",
|
|
"F-AUTH-02",
|
|
"F-AUTH-03",
|
|
"F-AUTH-04",
|
|
"F-AUTH-05",
|
|
"F-AUTH-06",
|
|
"F-AUTH-07",
|
|
"F-AUTH-08",
|
|
"F-SEC-01",
|
|
"F-SEC-02",
|
|
"F-SEC-03",
|
|
"F-INFRA-01",
|
|
"F-INFRA-03",
|
|
"F-INT-02",
|
|
"F-SCHED-01",
|
|
"F-TEST-01"
|
|
],
|
|
"acceptance_criteria": [
|
|
"POST /api/v1/auth/login mit valid credentials → 200 + Set-Cookie leocrm_session",
|
|
"POST /api/v1/auth/login mit invalid credentials → 401",
|
|
"GET /api/v1/auth/me ohne session cookie → 401",
|
|
"GET /api/v1/auth/me mit valid session → 200 + user+tenant JSON",
|
|
"POST /api/v1/auth/logout → 200, session invalidated",
|
|
"POST /api/v1/auth/password-reset/request → immer 200 (kein user enumeration)",
|
|
"POST /api/v1/auth/password-reset/confirm mit valid token → 200, password geaendert",
|
|
"POST /api/v1/auth/password-reset/confirm mit expired token → 400",
|
|
"POST /api/v1/auth/switch-tenant → 200, session tenant_id aktualisiert",
|
|
"GET /api/v1/users als admin → 200 + paginated list",
|
|
"GET /api/v1/users als viewer → 403",
|
|
"POST /api/v1/users mit valid data → 201",
|
|
"PATCH /api/v1/users/{id} → 200",
|
|
"DELETE /api/v1/users/{id} → 204",
|
|
"GET /api/v1/roles → 200 + list mit permissions",
|
|
"POST /api/v1/roles mit custom permissions → 201",
|
|
"Cross-tenant access auf company → 404 (not 403)",
|
|
"GET /api/v1/health → 200 ohne auth",
|
|
"Audit log entry created on company.create/update/delete",
|
|
"Notification erstellt beim user assign",
|
|
"RBAC: viewer kann company lesen aber nicht erstellen (POST → 403)",
|
|
"Field-level permissions: hidden field nicht in response",
|
|
"CSRF: POST ohne Origin header → 403",
|
|
"GET /api/v1/notifications → 200 + unread first",
|
|
"PATCH /api/v1/notifications/{id}/read → 200",
|
|
"GET /api/v1/notifications/unread-count → 200 + integer count"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/backend && python -m pytest tests/test_auth.py tests/test_tenant.py tests/test_health.py tests/test_notifications.py -v --tb=short",
|
|
"cd /app/backend && python -m pytest tests/test_auth.py tests/test_tenant.py --cov=app/core --cov=app/routes/auth --cov-report=term-missing",
|
|
"cd /app/backend && python -m pytest -k 'tenant' -v"
|
|
],
|
|
"expected_results": "All auth tests pass, tenant isolation verified (cross-tenant → 404), RBAC enforced (viewer→403 on write), health endpoint returns 200 without auth, audit log entries created on mutations, notifications CRUD functional, password reset flow works end-to-end, CSRF blocks non-origin requests",
|
|
"test_files": [
|
|
"tests/conftest.py",
|
|
"tests/test_auth.py",
|
|
"tests/test_tenant.py",
|
|
"tests/test_health.py",
|
|
"tests/test_notifications.py"
|
|
],
|
|
"coverage_target": 85
|
|
},
|
|
"dependencies": [],
|
|
"estimated_lines": 500,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v1"
|
|
},
|
|
{
|
|
"id": "T02",
|
|
"title": "Company + Contact + Import/Export System",
|
|
"description": "Komplettes Company- und Contact-Modul: SQLAlchemy Models (companies, contacts, company_contacts), Pydantic Schemas, Services (CRUD mit soft-delete, N:M links, search, filter, pagination, sort), Routers (alle Company/Contact/Import/Export Endpoints). Import-System (CSV mit dry-run preview, entity_type parameter). Export-System (CSV + XLSX via openpyxl). Full-Text-Search auf companies und contacts via tsvector. GDPR Hard-Delete mit deletion_log. Audit-Log auf alle Mutationen.",
|
|
"requirement_ids": [
|
|
"F-COMP-01",
|
|
"F-COMP-02",
|
|
"F-COMP-03",
|
|
"F-COMP-04",
|
|
"F-COMP-05",
|
|
"F-COMP-06",
|
|
"F-COMP-07",
|
|
"F-COMP-08",
|
|
"F-CONT-01",
|
|
"F-CONT-02",
|
|
"F-CONT-03",
|
|
"F-CONT-04",
|
|
"F-CONT-05",
|
|
"F-CONT-06",
|
|
"F-CONT-07",
|
|
"F-DATA-01",
|
|
"F-DATA-02",
|
|
"F-MIG-01",
|
|
"F-CORE-06",
|
|
"F-CORE-11",
|
|
"F-CORE-13",
|
|
"F-SEARCH-01",
|
|
"F-DATA-03",
|
|
"F-DATA-04",
|
|
"F-TEST-01"
|
|
],
|
|
"acceptance_criteria": [
|
|
"GET /api/v1/companies → 200 + paginated list with total/page/page_size",
|
|
"GET /api/v1/companies?search=Tech → 200 + FTS results",
|
|
"GET /api/v1/companies?industry=IT&sort_by=name&sort_order=asc → 200 + filtered+sorted",
|
|
"POST /api/v1/companies mit valid data → 201 + company object",
|
|
"POST /api/v1/companies mit missing name → 422",
|
|
"GET /api/v1/companies/{id} → 200 + company detail inkl. contacts array",
|
|
"PUT /api/v1/companies/{id} → 200 + updated company",
|
|
"DELETE /api/v1/companies/{id} → 204, deleted_at gesetzt",
|
|
"DELETE /api/v1/companies/{id}?cascade=true → 204, company + links geloescht",
|
|
"POST /api/v1/companies/{id}/contacts/{cid} → 200, N:M link erstellt",
|
|
"DELETE /api/v1/companies/{id}/contacts/{cid} → 204, N:M link entfernt",
|
|
"GET /api/v1/companies/export?format=csv → 200 + text/csv content-type",
|
|
"GET /api/v1/companies/export?format=xlsx → 200 + application/vnd.openxmlformats",
|
|
"GET /api/v1/contacts → 200 + paginated list",
|
|
"POST /api/v1/contacts mit company_ids array → 201 + N:M links erstellt",
|
|
"GET /api/v1/contacts/{id} → 200 + contact detail inkl. companies array",
|
|
"PUT /api/v1/contacts/{id} → 200",
|
|
"DELETE /api/v1/contacts/{id} → 204, soft-delete",
|
|
"DELETE /api/v1/contacts/{id}?gdpr=true → 204, hard-delete + deletion_log entry",
|
|
"POST /api/v1/import mit CSV file + entity_type=companies → 200 + import result",
|
|
"POST /api/v1/import/preview mit CSV → 200 + dry-run result (no DB changes)",
|
|
"GET /api/v1/companies/{id}/emails → 200 (empty array wenn mail plugin inactive)",
|
|
"Audit log entry on every company/contact mutation",
|
|
"Soft-deleted company not in GET list (deleted_at IS NULL filter)"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/backend && python -m pytest tests/test_companies.py tests/test_contacts.py tests/test_import_export.py -v --tb=short",
|
|
"cd /app/backend && python -m pytest tests/test_companies.py tests/test_contacts.py --cov=app/models/company --cov=app/models/contact --cov=app/services/company --cov=app/services/contact --cov=app/routes/companies --cov=app/routes/contacts --cov-report=term-missing",
|
|
"cd /app/backend && python -m pytest -k 'import or export' -v"
|
|
],
|
|
"expected_results": "All company CRUD tests pass, contact CRUD tests pass, N:M linking works, CSV import creates records, dry-run preview does not modify DB, CSV+XLSX export returns correct content-type, FTS search returns relevant results, soft-delete hides records, GDPR hard-delete creates deletion_log entry, audit log captures all mutations",
|
|
"test_files": [
|
|
"tests/test_companies.py",
|
|
"tests/test_contacts.py",
|
|
"tests/test_import_export.py"
|
|
],
|
|
"coverage_target": 85
|
|
},
|
|
"dependencies": [
|
|
"T01"
|
|
],
|
|
"estimated_lines": 600,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v1"
|
|
},
|
|
{
|
|
"id": "T03",
|
|
"title": "Plugin System Framework",
|
|
"description": "Komplettes Plugin-Framework: Plugin Registry (DB-backed), Plugin Manifest Schema (Pydantic), Lifecycle Hooks (install/activate/deactivate/uninstall), Plugin DB Migration Runner (mit plugin_migrations tracking table), UI Registry (fuer Frontend Plugin Component Registration), Plugin Endpoints (list/install/activate/deactivate/uninstall/manifest). Built-in Plugin Discovery (scannt app/plugins/builtins/). Event Bus Integration (plugins register event listeners during activate). Service Container Injection (plugins receive db, cache, event_bus, storage, notifications). Plugin Migration Validator (checks tenant_id on all plugin tables).",
|
|
"requirement_ids": [
|
|
"F-PLUGIN-01",
|
|
"F-PLUGIN-02",
|
|
"F-CORE-01",
|
|
"F-CORE-03",
|
|
"F-CORE-04",
|
|
"F-CORE-05",
|
|
"F-TEST-01"
|
|
],
|
|
"acceptance_criteria": [
|
|
"GET /api/v1/plugins → 200 + list of plugins with status",
|
|
"POST /api/v1/plugins/{name}/install → 200, plugin status=installed, migrations run",
|
|
"POST /api/v1/plugins/{name}/activate → 200, plugin status=active, routes registered",
|
|
"POST /api/v1/plugins/{name}/deactivate → 200, plugin status=inactive, routes unregistered",
|
|
"DELETE /api/v1/plugins/{name} → 200, plugin removed",
|
|
"DELETE /api/v1/plugins/{name}?remove_data=true → 200, plugin tables dropped",
|
|
"GET /api/v1/plugins/manifest → 200 + manifest schema documentation",
|
|
"Plugin activation registers event listeners on event bus",
|
|
"Plugin deactivation unregisters event listeners",
|
|
"Plugin migration creates tables with tenant_id column",
|
|
"Plugin migration validator rejects tables without tenant_id",
|
|
"Plugin DB migrations tracked in plugin_migrations table",
|
|
"Activating already-active plugin → idempotent (200, no error)",
|
|
"Deactivating inactive plugin → idempotent (200)"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/backend && python -m pytest tests/test_plugins.py -v --tb=short",
|
|
"cd /app/backend && python -m pytest tests/test_plugins.py --cov=app/plugins --cov-report=term-missing",
|
|
"cd /app/backend && python -m pytest -k 'plugin and (install or activate or lifecycle)' -v"
|
|
],
|
|
"expected_results": "All plugin lifecycle tests pass, install/activate/deactivate/uninstall transitions work, migrations run and track in plugin_migrations, validator rejects missing tenant_id, event bus registration/unregistration works, idempotent operations return 200",
|
|
"test_files": [
|
|
"tests/test_plugins.py"
|
|
],
|
|
"coverage_target": 85
|
|
},
|
|
"dependencies": [
|
|
"T01"
|
|
],
|
|
"estimated_lines": 500,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v1"
|
|
},
|
|
{
|
|
"id": "T04",
|
|
"title": "DMS Plugin Backend (Folders, Files, Preview, OnlyOffice, Share Links)",
|
|
"description": "DMS plugin: folder hierarchy, file upload/operations, PDF preview, OnlyOffice edit sessions, share links, public access, bulk operations, search.",
|
|
"requirement_ids": [
|
|
"F-DMS-04",
|
|
"F-DMS-01",
|
|
"F-FILEUI-03",
|
|
"F-FILEUI-02",
|
|
"F-DMS-05",
|
|
"F-DMS-03",
|
|
"F-FILEUI-01",
|
|
"F-DMS-02",
|
|
"F-DMS-07",
|
|
"F-DMS-06",
|
|
"F-FILEUI-04",
|
|
"F-FILE-01",
|
|
"F-FILE-02",
|
|
"F-FILE-03",
|
|
"F-FILE-04"
|
|
],
|
|
"acceptance_criteria": [
|
|
"GET /api/v1/dms/folders → 200 + folder tree",
|
|
"POST /api/v1/dms/folders → 201, folder created with path",
|
|
"PATCH /api/v1/dms/folders/{id} → 200, folder renamed/moved",
|
|
"DELETE /api/v1/dms/folders/{id} → 204, soft-delete",
|
|
"POST /api/v1/dms/files/upload (multipart) → 201, file stored + metadata",
|
|
"GET /api/v1/dms/files/{id} → 200 + file metadata",
|
|
"PATCH /api/v1/dms/files/{id} → 200, renamed/moved",
|
|
"DELETE /api/v1/dms/files/{id} → 204, soft-delete",
|
|
"POST /api/v1/dms/files/{id}/restore → 200, restored from trash",
|
|
"GET /api/v1/dms/files/{id}/preview → 200 + PDF stream",
|
|
"POST /api/v1/dms/files/{id}/edit-session → 200 + OnlyOffice config",
|
|
"POST /api/v1/dms/files/{id}/share → 200, internal share created",
|
|
"DELETE /api/v1/dms/files/{id}/share → 204, share removed",
|
|
"GET /api/public/share/{token} → 200 (no auth, public access)",
|
|
"GET /api/public/share/{token} mit password → 401 ohne password",
|
|
"GET /api/v1/dms/search?q=text → 200 + matching files",
|
|
"GET /api/v1/dms/shared-with-me → 200 + shared files list",
|
|
"POST /api/v1/dms/files/bulk-move → 200, files moved",
|
|
"POST /api/v1/dms/files/bulk-delete → 200, files soft-deleted"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/backend && python -m pytest tests/test_dms.py -v --tb=short",
|
|
"cd /app/backend && python -m pytest tests/test_dms.py --cov=app/plugins/builtins/dms --cov-report=term-missing",
|
|
"cd /app/backend && python -m pytest -k 'dms and (upload or share or permission or bulk)' -v"
|
|
],
|
|
"expected_results": "All DMS tests pass: folder tree, file upload, permissions enforced, shares work, public share links work with password+expiry, bulk operations functional, OnlyOffice session created, DMS search returns results.",
|
|
"test_files": [
|
|
"tests/test_dms.py"
|
|
],
|
|
"coverage_target": 80
|
|
},
|
|
"dependencies": [
|
|
"T01",
|
|
"T03"
|
|
],
|
|
"estimated_lines": 700,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v2"
|
|
},
|
|
{
|
|
"id": "T05",
|
|
"title": "Calendar Plugin (Appointments, Tasks, Kanban, Resources, ICS)",
|
|
"description": "Komplettes Calendar Plugin als Built-in: Models (calendars, calendar_entries, calendar_entry_links, calendar_shares, user_calendar_visibility, subtasks, resources, resource_bookings). Calendar Service (CRUD calendars, share, visibility). Entry Service (create appointments+tasks, update (drag&drop via PATCH start_at/end_at), delete, link to entities, subtasks CRUD, bulk actions, kanban view query). Recurrence Engine (RRULE-style patterns: daily/weekly/monthly/yearly + custom rules + exceptions). Reminder System (JSONB reminder config → ARQ job scheduling). ICS Export (calendar feed mit token auth) + ICS Import (parse .ics files). Resource Booking (create resources, book resources for entries, conflict detection). Calendar Sharing (user/group permissions). Plugin Manifest + Migrations.",
|
|
"requirement_ids": [
|
|
"F-CAL-01",
|
|
"F-CAL-02",
|
|
"F-CAL-03",
|
|
"F-CAL-04",
|
|
"F-CAL-05",
|
|
"F-CAL-06",
|
|
"F-CAL-07",
|
|
"F-CAL-08",
|
|
"F-CAL-09",
|
|
"F-CAL-10",
|
|
"F-CAL-11",
|
|
"F-CAL-12",
|
|
"F-CAL-13",
|
|
"F-CAL-14",
|
|
"F-CAL-15",
|
|
"F-CAL-16",
|
|
"F-CAL-17",
|
|
"F-CAL-18",
|
|
"F-TEST-01"
|
|
],
|
|
"acceptance_criteria": [
|
|
"GET /api/v1/calendars → 200 + calendar list",
|
|
"POST /api/v1/calendars → 201, calendar created",
|
|
"PATCH /api/v1/calendars/{id} → 200",
|
|
"DELETE /api/v1/calendars/{id} → 204, cascade delete entries",
|
|
"POST /api/v1/calendars/{id}/share → 200, calendar shared",
|
|
"GET /api/v1/calendars/{id}/permissions → 200 + permission list",
|
|
"GET /api/v1/calendar/entries?start=2026-01-01&end=2026-12-31 → 200 + entries in range",
|
|
"POST /api/v1/calendar/entries (appointment) → 201, entry created with start_at/end_at",
|
|
"POST /api/v1/calendar/entries (task) → 201, entry created with due_date/priority/status",
|
|
"GET /api/v1/calendar/entries/{id} → 200 + entry detail with links+subtasks",
|
|
"PATCH /api/v1/calendar/entries/{id} → 200, updated (drag&drop: PATCH start_at+end_at)",
|
|
"PATCH /api/v1/calendar/entries/{id} status=done → 200, status updated",
|
|
"DELETE /api/v1/calendar/entries/{id} → 204",
|
|
"POST /api/v1/calendar/entries/{id}/link → 200, linked to company/contact",
|
|
"POST /api/v1/calendar/entries/{id}/subtasks → 201, subtask created",
|
|
"PATCH /api/v1/calendar/entries/{id}/subtasks/{sub_id} → 200, completed toggled",
|
|
"POST /api/v1/calendar/entries/bulk → 200, bulk status change/delete",
|
|
"GET /api/v1/calendar/kanban → 200 + tasks grouped by status columns",
|
|
"GET /api/v1/calendar/entries/export?format=csv → 200 + CSV",
|
|
"GET /api/v1/calendar/{calendar_id}/ics-feed?token=valid → 200 + text/calendar",
|
|
"GET /api/v1/calendar/{calendar_id}/ics-feed?token=invalid → 401",
|
|
"POST /api/v1/calendar/import mit .ics file → 200 + import result",
|
|
"POST /api/v1/resources → 201 (admin only)",
|
|
"POST /api/v1/calendar/entries/{id}/book-resource → 200, resource booked",
|
|
"POST /api/v1/calendar/entries/{id}/book-resource (conflict) → 409",
|
|
"Recurrence: weekly entry generates correct occurrences for date range query",
|
|
"Recurrence: exception date excluded from occurrences",
|
|
"Reminder: ARQ job scheduled when reminder JSONB set",
|
|
"Calendar share: user with read permission can view, cannot edit (403)",
|
|
"Private subtype: only owner+admin can see entry"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/backend && python -m pytest tests/test_calendar.py -v --tb=short",
|
|
"cd /app/backend && python -m pytest tests/test_calendar.py --cov=app/plugins/builtins/calendar --cov-report=term-missing",
|
|
"cd /app/backend && python -m pytest -k 'calendar and (recurrence or kanban or ics or resource)' -v"
|
|
],
|
|
"expected_results": "All calendar tests pass: appointment+task CRUD, kanban view returns grouped tasks, recurrence generates correct occurrences with exceptions, ICS export with token auth works, ICS import creates entries, resource booking with conflict detection, subtask toggle, bulk actions, calendar sharing with permissions, reminders schedule ARQ jobs, private entries hidden from non-owners",
|
|
"test_files": [
|
|
"tests/test_calendar.py"
|
|
],
|
|
"coverage_target": 80
|
|
},
|
|
"dependencies": [
|
|
"T01",
|
|
"T03"
|
|
],
|
|
"estimated_lines": 700,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v2"
|
|
},
|
|
{
|
|
"id": "T06",
|
|
"title": "Mail Plugin (IMAP/SMTP, Threading, Templates, Rules, PGP, Delegates)",
|
|
"description": "Komplettes Mail Plugin als Built-in: Models (mail_accounts, mail_folders, mails, mail_attachments, mail_labels, mail_label_assignments, mail_rules, mail_templates, mail_signatures, vacation_sent_log, mail_seen_by, mail_account_delegates, mail_account_send_permissions, pgp_keys, contact_pgp_keys). Mail Account Service (CRUD, encrypted credentials via AES-256, IMAP connection test). IMAP Sync Service (background ARQ job, sync folders+mails, update unread/total counts, store body_tsv for FTS). SMTP Send Service (send, reply, forward, with signature). Mail Folder Service (list, create, rename, delete). Mail List Service (filter by folder/account/flags, FTS search, pagination). Thread Service (group by thread_id, threaded view). Template Service (CRUD templates, variable substitution). Signature Service (CRUD). Mail Rule Engine (condition matching → actions: move, label, mark, forward). Vacation Auto-Reply (config + dedup via vacation_sent_log). Label Service (CRUD labels, assign to mails). PGP Integration (import private key, encrypt/decrypt, contact public keys). Delegate/Permission System (delegate access read/full, send permissions). Attachment Service (download, link to DMS). Contact/Company Linking (manual + auto from email addresses). Create Calendar Event from Mail. Plugin Manifest + Migrations.",
|
|
"requirement_ids": [
|
|
"F-MAIL-01",
|
|
"F-MAIL-02",
|
|
"F-MAIL-03",
|
|
"F-MAIL-04",
|
|
"F-MAIL-05",
|
|
"F-MAIL-06",
|
|
"F-MAIL-07",
|
|
"F-MAIL-08",
|
|
"F-MAIL-09",
|
|
"F-MAIL-10",
|
|
"F-MAIL-11",
|
|
"F-MAIL-12",
|
|
"F-MAIL-13",
|
|
"F-MAIL-14",
|
|
"F-MAIL-15",
|
|
"F-MAIL-16",
|
|
"F-MAIL-17",
|
|
"F-MAIL-18",
|
|
"F-MAIL-19",
|
|
"F-TEST-01"
|
|
],
|
|
"acceptance_criteria": [
|
|
"GET /api/v1/mail/accounts → 200 + account list (password nicht in response)",
|
|
"POST /api/v1/mail/accounts → 201, password AES-256 encrypted in DB",
|
|
"PATCH /api/v1/mail/accounts/{id} → 200",
|
|
"GET /api/v1/mail/accounts/shared → 200 + shared mailboxes",
|
|
"POST /api/v1/mail/accounts/{id}/users → 200, shared mailbox users assigned",
|
|
"POST /api/v1/mail/accounts/{id}/delegates → 200, delegate access granted",
|
|
"POST /api/v1/mail/accounts/{id}/send-permissions → 200, send permission granted",
|
|
"GET /api/v1/mail/folders?account_id=X → 200 + folder list with counts",
|
|
"POST /api/v1/mail/folders → 201, folder created",
|
|
"PATCH /api/v1/mail/folders/{id} → 200, renamed",
|
|
"DELETE /api/v1/mail/folders/{id} → 204, deleted",
|
|
"GET /api/v1/mail?folder_id=X&page=1 → 200 + paginated mails",
|
|
"GET /api/v1/mail/{id} → 200 + mail detail (body_html sanitized, attachments listed)",
|
|
"POST /api/v1/mail/send → 200, mail sent via SMTP",
|
|
"POST /api/v1/mail/{id}/reply → 200, reply sent with In-Reply-To header",
|
|
"POST /api/v1/mail/{id}/forward → 200, forwarded with original as attachment",
|
|
"PATCH /api/v1/mail/{id}/flags → 200, seen/flagged toggled",
|
|
"GET /api/v1/mail/{id}/attachments/{att_id} → 200 + file stream",
|
|
"POST /api/mail/{id}/link → 200, manual contact/company link created",
|
|
"POST /api/v1/mail/{id}/create-event → 200, calendar event created from mail",
|
|
"GET /api/v1/mail/search?q=text → 200 + FTS results (body_tsv)",
|
|
"GET /api/v1/mail/threads → 200 + threaded view grouped by thread_id",
|
|
"POST /api/v1/mail/templates → 201, template created",
|
|
"GET /api/v1/mail/templates → 200 + template list",
|
|
"POST /api/v1/mail/signatures → 201, signature created",
|
|
"GET /api/v1/mail/signatures → 200 + signature list",
|
|
"POST /api/v1/mail/rules → 201, rule created with conditions+actions",
|
|
"GET /api/v1/mail/rules → 200 + rule list sorted by priority",
|
|
"DELETE /api/v1/mail/rules/{id} → 204",
|
|
"POST /api/v1/mail/vacation → 200, vacation auto-reply configured",
|
|
"Vacation dedup: second auto-reply to same sender within 24h → not sent (vacation_sent_log)",
|
|
"POST /api/v1/mail/pgp/keys → 201, private key imported (encrypted)",
|
|
"POST /api/v1/contacts/{id}/pgp-key → 201, contact public key stored",
|
|
"POST /api/v1/mail/labels → 201, label created",
|
|
"POST /api/v1/mail/{id}/labels → 200, label assigned",
|
|
"IMAP sync (ARQ job): mails fetched and stored with body_tsv",
|
|
"Mail rule engine: incoming mail matching condition → action executed (move/label/flag)",
|
|
"Body HTML sanitized (no script tags) via DOMPurify-equivalent",
|
|
"Mail account password never returned in any API response",
|
|
"Shared mailbox: delegated user can read but not delete (permission=read → 403 on DELETE)"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/backend && python -m pytest tests/test_mail.py -v --tb=short",
|
|
"cd /app/backend && python -m pytest tests/test_mail.py --cov=app/plugins/builtins/mail --cov-report=term-missing",
|
|
"cd /app/backend && python -m pytest -k 'mail and (send or sync or rule or pgp or vacation or delegate)' -v"
|
|
],
|
|
"expected_results": "All mail tests pass: account CRUD with encrypted credentials, IMAP sync stores mails with FTS, SMTP send/reply/forward works, threading groups by thread_id, templates+signatures CRUD, rule engine executes actions on matching mails, vacation dedup works, PGP key import+contact keys, labels CRUD+assign, attachments downloadable, body HTML sanitized, shared mailbox permissions enforced, delegate access read/full enforced, send permissions enforced",
|
|
"test_files": [
|
|
"tests/test_mail.py"
|
|
],
|
|
"coverage_target": 80
|
|
},
|
|
"dependencies": [
|
|
"T01",
|
|
"T03"
|
|
],
|
|
"estimated_lines": 800,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v2"
|
|
},
|
|
{
|
|
"id": "T07a",
|
|
"title": "Frontend Core SPA — Shell, Auth, Routing, i18n, UI Library, Accessibility",
|
|
"description": "React 18 SPA Foundation: Vite setup, App.tsx mit Router+Providers (TanStack Query, Zustand, i18n). API Client (axios mit interceptors, session cookie handling, error normalization). Layout Shell (Sidebar mit Plugin-Menu, TopBar mit Tenant-Switcher+Search+Notifications+User-Menu, ContentArea). Auth Pages (Login, Password-Reset Request+Confirm). Shared UI Component Library (Button, Input, Select, Modal, Toast, Table, Card, Badge, Avatar, Pagination, EmptyState, Skeleton, ConfirmDialog). Accessibility (ARIA, 44px targets, keyboard nav, reduced-motion, sr-only). Tailwind CSS Setup mit Design Tokens aus Prototype. i18n Setup (de/en locales).",
|
|
"requirement_ids": [
|
|
"F-AUTH-01",
|
|
"F-AUTH-02",
|
|
"F-AUTH-03",
|
|
"F-AUTH-05",
|
|
"F-AUTH-07",
|
|
"F-CORE-06",
|
|
"F-CORE-07",
|
|
"F-CORE-08",
|
|
"F-CORE-09",
|
|
"F-CORE-13",
|
|
"F-A11Y-01",
|
|
"F-A11Y-02",
|
|
"F-A11Y-03",
|
|
"F-INT-01",
|
|
"F-NAV-01",
|
|
"F-UI-01",
|
|
"F-UI-02",
|
|
"F-UI-03",
|
|
"F-UI-04",
|
|
"F-UI-05",
|
|
"F-UI-06",
|
|
"F-UI-08",
|
|
"F-TEST-01"
|
|
],
|
|
"acceptance_criteria": [
|
|
"Login page renders with email+password form",
|
|
"Login with valid credentials → redirect to Dashboard",
|
|
"Login with invalid credentials → error toast shown",
|
|
"Password reset request page renders and submits",
|
|
"Password reset confirm page renders with token validation",
|
|
"App shell renders with sidebar (plugin menu), topbar (tenant switcher, search, notifications, user menu), content area",
|
|
"Router navigates between routes without page reload (SPA)",
|
|
"Protected routes redirect to /login when not authenticated",
|
|
"Tenant switcher shows current tenant and allows switching",
|
|
"API client sends session cookie automatically via axios interceptor",
|
|
"API client handles 401 → redirect to login",
|
|
"API client handles 422 → display validation errors",
|
|
"i18n: German locale loads by default",
|
|
"i18n: English locale switchable via settings",
|
|
"UI Library: Button renders with variants (primary, secondary, danger, ghost)",
|
|
"UI Library: Input renders with label, error, helper text",
|
|
"UI Library: Modal opens/closes with backdrop click and ESC",
|
|
"UI Library: Toast notifications appear and auto-dismiss",
|
|
"UI Library: Table renders with sortable headers",
|
|
"UI Library: Card, Badge, Avatar, Pagination, EmptyState, Skeleton, ConfirmDialog render correctly",
|
|
"Accessibility: All interactive elements have ARIA labels",
|
|
"Accessibility: Keyboard navigation works (Tab, Enter, Escape, Arrow keys)",
|
|
"Accessibility: 44px minimum touch targets on mobile",
|
|
"Accessibility: prefers-reduced-motion respected",
|
|
"Vite dev server starts without errors",
|
|
"Production build (npm run build) succeeds with 0 errors",
|
|
"TypeScript: tsc --noEmit passes with 0 errors"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/frontend && npx vitest run src/__tests__/shell/ src/__tests__/auth/ src/__tests__/ui/ --reporter=verbose",
|
|
"cd /app/frontend && npx vitest run src/__tests__/shell/ src/__tests__/ui/ --coverage",
|
|
"cd /app/frontend && npm run build",
|
|
"cd /app/frontend && npx tsc --noEmit"
|
|
],
|
|
"expected_results": "All shell tests pass: router, auth pages, layout shell, tenant switcher. UI library tests pass: all components render with variants. Accessibility tests pass: ARIA, keyboard nav, touch targets. i18n tests pass: locale switching. Build succeeds with 0 errors. TypeScript passes.",
|
|
"test_files": [
|
|
"src/__tests__/shell/",
|
|
"src/__tests__/auth/",
|
|
"src/__tests__/ui/"
|
|
],
|
|
"coverage_target": 80
|
|
},
|
|
"dependencies": [
|
|
"T01"
|
|
],
|
|
"estimated_lines": 800,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v1"
|
|
},
|
|
{
|
|
"id": "T07b",
|
|
"title": "Frontend Core SPA — Companies, Contacts, Settings, Audit Log, Dashboard, Global Search",
|
|
"description": "React 18 SPA Feature Pages: Companies Feature (List mit TanStack Table: search/filter/sort/pagination, Detail mit Tabs incl. Contacts-Tab, Form mit React Hook Form+Zod, Import/Export). Contacts Feature (List, Detail mit Tabs, Form, multi-company assignment). Settings Feature (Settings Tree Navigation, Profile Settings, Role Editor, User Management). Audit Log Page. Dashboard (Stat-Cards, Recent Activity). Global Search Results Page with filters and highlighting.",
|
|
"requirement_ids": [
|
|
"F-COMP-01",
|
|
"F-COMP-02",
|
|
"F-COMP-03",
|
|
"F-COMP-04",
|
|
"F-COMP-05",
|
|
"F-COMP-06",
|
|
"F-CONT-01",
|
|
"F-CONT-02",
|
|
"F-CONT-03",
|
|
"F-CONT-04",
|
|
"F-CONT-05",
|
|
"F-CONT-06",
|
|
"F-SET-01",
|
|
"F-SEARCH-01",
|
|
"F-DATA-06"
|
|
],
|
|
"acceptance_criteria": [
|
|
"Companies list page renders with TanStack Table (search, filter, sort, pagination)",
|
|
"Company detail page renders with tabs (overview, contacts, files, activity)",
|
|
"Company create/edit form validates required fields (name, type) with Zod",
|
|
"Company import: CSV upload → preview → import → success toast",
|
|
"Company export: download CSV with current filters applied",
|
|
"Contacts list page renders with TanStack Table",
|
|
"Contact detail page renders with tabs (overview, companies, files, activity)",
|
|
"Contact create/edit form validates required fields (first_name, last_name, email)",
|
|
"Contact can be assigned to multiple companies",
|
|
"Settings page renders with tree navigation (Profile, Roles, Users, System)",
|
|
"Profile settings: update name, email, password, avatar",
|
|
"Role editor: create role, assign permissions, save",
|
|
"User management: list users, invite user, change role, deactivate",
|
|
"Audit log page renders with filterable table (date, user, action, entity)",
|
|
"Dashboard renders with stat cards and recent activity feed",
|
|
"Global search bar in topbar returns results dropdown",
|
|
"Global search results page renders with filters (entity type, date)",
|
|
"Search results highlight matched terms",
|
|
"Search works across companies, contacts, and files (v1 scope)",
|
|
"Companies list: empty state shows helpful message + create button",
|
|
"Contacts list: loading state shows skeleton rows",
|
|
"Company form: error state shows inline validation errors",
|
|
"Settings: unsaved changes warning when navigating away"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/frontend && npx vitest run src/__tests__/companies/ src/__tests__/contacts/ src/__tests__/settings/ src/__tests__/dashboard/ src/__tests__/search/ --reporter=verbose",
|
|
"cd /app/frontend && npx vitest run src/__tests__/companies/ src/__tests__/contacts/ --coverage",
|
|
"cd /app/frontend && npm run build",
|
|
"cd /app/frontend && npx tsc --noEmit"
|
|
],
|
|
"expected_results": "All Companies tests pass: list, detail, form, import, export. Contacts tests pass: list, detail, form, multi-company. Settings tests pass: profile, roles, users. Audit log renders with filters. Dashboard renders with stats. Global search works with filters and highlighting. Build succeeds. TypeScript passes.",
|
|
"test_files": [
|
|
"src/__tests__/companies/",
|
|
"src/__tests__/contacts/",
|
|
"src/__tests__/settings/",
|
|
"src/__tests__/dashboard/",
|
|
"src/__tests__/search/"
|
|
],
|
|
"coverage_target": 80
|
|
},
|
|
"dependencies": [
|
|
"T01",
|
|
"T02",
|
|
"T07a"
|
|
],
|
|
"estimated_lines": 1200,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v1"
|
|
},
|
|
{
|
|
"id": "T08a",
|
|
"title": "Frontend DMS + Tags + Permissions UI",
|
|
"description": "Frontend UI for DMS plugin (file browser, upload, preview, share, trash), Tags UI (assign, bulk, tag cloud), and Permissions UI (share links, permission display).",
|
|
"requirement_ids": [
|
|
"F-LINK-04",
|
|
"F-LINK-05",
|
|
"F-LINK-01",
|
|
"F-DMS-04",
|
|
"F-PERM-03",
|
|
"F-DMS-01",
|
|
"F-LINK-03",
|
|
"F-FILEUI-03",
|
|
"F-FILEUI-02",
|
|
"F-TAG-04",
|
|
"F-DMS-05",
|
|
"F-LINK-02",
|
|
"F-DMS-03",
|
|
"F-FILEUI-01",
|
|
"F-PERM-05",
|
|
"F-TAG-02",
|
|
"F-PERM-04",
|
|
"F-DMS-02",
|
|
"F-DMS-07",
|
|
"F-DMS-06",
|
|
"F-TAG-03",
|
|
"F-FILEUI-04",
|
|
"F-TAG-01",
|
|
"F-FILEUI-05",
|
|
"F-FILEUI-06"
|
|
],
|
|
"acceptance_criteria": [
|
|
"DMS route /dms renders file browser with folder tree + file grid",
|
|
"DMS upload: drag file to dropzone → upload progress → file appears in list",
|
|
"DMS file preview modal opens with PDF.js for PDF files",
|
|
"DMS share dialog: select user/group, set permission, share created",
|
|
"DMS public share link: copy button generates URL, optional password+expiry fields",
|
|
"DMS bulk select → bulk-move or bulk-delete actions appear",
|
|
"DMS trash view: deleted files list, restore button per file",
|
|
"Mail: shared mailbox selector → switch between personal+shared accounts",
|
|
"Tags: tag picker on company/contact detail → assign/unassign",
|
|
"Tags: bulk select entities → bulk-tag dialog",
|
|
"Plugin deactivate → plugin route+menu-item disappear from SPA",
|
|
"Plugin activate → plugin route+menu-item appear in SPA"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/frontend && npx vitest run src/__tests__/dms/ src/__tests__/tags/ src/__tests__/permissions/ --reporter=verbose",
|
|
"cd /app/frontend && npx vitest run src/__tests__/dms/ src/__tests__/tags/ --coverage",
|
|
"cd /app/frontend && npm run build",
|
|
"cd /app/frontend && npx playwright test e2e/dms.spec.ts e2e/tags.spec.ts"
|
|
],
|
|
"expected_results": "All DMS UI tests pass: file browser renders, upload works, preview opens, share dialog functional, trash restore works. Tag UI tests pass: assign, bulk assign, tag cloud. Permission UI tests pass: share links, permission display.",
|
|
"test_files": [
|
|
"src/__tests__/dms/",
|
|
"src/__tests__/tags/",
|
|
"src/__tests__/permissions/",
|
|
"e2e/dms.spec.ts",
|
|
"e2e/tags.spec.ts"
|
|
],
|
|
"coverage_target": 80
|
|
},
|
|
"dependencies": [
|
|
"T04",
|
|
"T07b"
|
|
],
|
|
"estimated_lines": 600,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v2"
|
|
},
|
|
{
|
|
"id": "T08b",
|
|
"title": "Frontend Calendar UI",
|
|
"description": "Frontend UI for Calendar plugin (month/week/day views, drag & drop, kanban, subtasks, ICS import/export, resource booking, sharing).",
|
|
"requirement_ids": [
|
|
"F-CAL-12",
|
|
"F-CAL-01",
|
|
"F-CAL-04",
|
|
"F-CAL-17",
|
|
"F-CAL-09",
|
|
"F-CAL-02",
|
|
"F-CAL-06",
|
|
"F-CAL-05",
|
|
"F-CAL-11",
|
|
"F-CAL-08",
|
|
"F-CAL-14",
|
|
"F-CAL-16",
|
|
"F-CAL-03"
|
|
],
|
|
"acceptance_criteria": [
|
|
"Calendar route /calendar renders month view with entries",
|
|
"Calendar: click time slot → appointment create modal opens",
|
|
"Calendar: drag entry to different time → PATCH start_at/end_at",
|
|
"Calendar kanban /calendar/kanban renders task columns (open/in_progress/done)",
|
|
"Calendar: task card drag between kanban columns → status update",
|
|
"Calendar: subtask checklist renders under task detail",
|
|
"Calendar: ICS export button → downloads .ics file",
|
|
"Calendar: ICS import button → file picker → imports events",
|
|
"Calendar: resource booking → select resource, conflict warning if overlap",
|
|
"Calendar: sharing settings → add user/group with permission",
|
|
"Mail: create event from mail → calendar event modal pre-filled"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/frontend && npx vitest run src/__tests__/calendar/ --reporter=verbose",
|
|
"cd /app/frontend && npx vitest run src/__tests__/calendar/ --coverage",
|
|
"cd /app/frontend && npm run build",
|
|
"cd /app/frontend && npx playwright test e2e/calendar.spec.ts"
|
|
],
|
|
"expected_results": "All Calendar UI tests pass: calendar views render, drag & drop works, kanban board functional, subtask creation, ICS import/export, resource management.",
|
|
"test_files": [
|
|
"src/__tests__/calendar/",
|
|
"e2e/calendar.spec.ts"
|
|
],
|
|
"coverage_target": 80
|
|
},
|
|
"dependencies": [
|
|
"T05",
|
|
"T07b"
|
|
],
|
|
"estimated_lines": 600,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v2"
|
|
},
|
|
{
|
|
"id": "T08c",
|
|
"title": "Frontend Mail UI + Global Search UI",
|
|
"description": "Frontend UI for Mail plugin (folder tree, mail list, reading pane, compose, templates, signatures, rules, labels, PGP, vacation, shared mailbox, delegates) and Global Search UI.",
|
|
"requirement_ids": [
|
|
"F-MAIL-14",
|
|
"F-MAIL-07",
|
|
"F-MAIL-02",
|
|
"F-MAIL-13",
|
|
"F-MAIL-01",
|
|
"F-MAIL-04",
|
|
"F-MAIL-11",
|
|
"F-MAIL-05",
|
|
"F-MAIL-09",
|
|
"F-MAIL-06",
|
|
"F-MAIL-15",
|
|
"F-MAIL-08",
|
|
"F-MAIL-10",
|
|
"F-MAIL-12",
|
|
"F-MAIL-03",
|
|
"F-SEARCH-01"
|
|
],
|
|
"acceptance_criteria": [
|
|
"DMS route /dms renders file browser with folder tree + file grid",
|
|
"Mail route /mail renders folder tree + mail list + reading pane",
|
|
"Mail: click folder → mail list updates with folder mails",
|
|
"Mail: click mail → detail with sanitized HTML body + attachments",
|
|
"Mail: compose button → TipTap editor with toolbar (bold, italic, link, template insert)",
|
|
"Mail: reply/forward buttons → compose pre-filled",
|
|
"Mail: template picker dropdown in compose → inserts template body",
|
|
"Mail: signature manager in settings → create/edit/delete signatures",
|
|
"Mail: rule editor → condition builder + action selector",
|
|
"Mail: label manager → create labels with colors, assign to mails",
|
|
"Mail: PGP settings → import private key, view contact public keys",
|
|
"Mail: vacation responder toggle → date range + auto-reply text",
|
|
"Mail: shared mailbox selector → switch between personal+shared accounts",
|
|
"Mail: attachment download → file stream downloaded",
|
|
"Mail: create event from mail → calendar event modal pre-filled",
|
|
"Global search results page → tabs for companies/contacts/mails/files/events",
|
|
"Docker Compose: docker compose up → all services start",
|
|
"Global search autocomplete in TopBar → dropdown with suggestions"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/frontend && npx vitest run src/__tests__/mail/ src/__tests__/search/ --reporter=verbose",
|
|
"cd /app/frontend && npx vitest run src/__tests__/mail/ src/__tests__/search/ --coverage",
|
|
"cd /app/frontend && npm run build",
|
|
"cd /app/frontend && npx playwright test e2e/mail.spec.ts e2e/search.spec.ts"
|
|
],
|
|
"expected_results": "All Mail UI tests pass: mail list renders, compose works, template picker functional, rule editor saves, PGP settings display. Global search UI tests pass: search results, filters, highlighting.",
|
|
"test_files": [
|
|
"src/__tests__/mail/",
|
|
"src/__tests__/search/",
|
|
"e2e/mail.spec.ts",
|
|
"e2e/search.spec.ts"
|
|
],
|
|
"coverage_target": 80
|
|
},
|
|
"dependencies": [
|
|
"T06",
|
|
"T07b"
|
|
],
|
|
"estimated_lines": 700,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v2"
|
|
},
|
|
{
|
|
"id": "T09",
|
|
"title": "KI-Copilot API + Hybrid Workflow Engine Backend",
|
|
"description": "Zwei Module in einem Task: (1) KI-Copilot: ai_conversations Model, Copilot Service (Natural-Language → API-Call-Translation via konfigurierbarem LLM-Client), Query Endpoint (POST /api/v1/ai/copilot/query → returns proposed API calls), Execute Endpoint (POST /api/v1/ai/copilot/execute → fuehrt API-Call durch RBAC-Middleware), History Endpoint (GET /api/v1/ai/copilot/history). LLM-Client via Env-Vars (AI_MODEL, AI_API_KEY). RBAC-Durchsetzung: Copilot nutzt User-Session, gleiche Middleware, gleiche Field-Level Permissions, gleiche Tenant-Isolation. Audit-Log als entity_type=ai_copilot. (2) Workflow Engine: workflows, workflow_instances, workflow_step_history Models. Workflow Definition Service (CRUD workflows mit steps JSONB). Workflow Instance Service (start, advance step, approve/reject, cancel). Code-Engine: hartkodierte Workflows in app/workflows/code/ (onboarding, plugin_sequence, mail_sync_trigger). Event Bus Integration: event-triggered workflows starten automatisch. Configurable workflows via Admin-UI. Step types: action, approval, notification, condition. Alle Workflow-Mutationen werden in workflow_step_history protokolliert.",
|
|
"requirement_ids": [
|
|
"F-AI-01",
|
|
"F-WF-01",
|
|
"F-CORE-01",
|
|
"F-CORE-06",
|
|
"F-TEST-01"
|
|
],
|
|
"acceptance_criteria": [
|
|
"POST /api/v1/ai/copilot/query mit NL input → 200 + proposed_actions array",
|
|
"POST /api/v1/ai/copilot/execute mit proposed action → 200 + API result (RBAC enforced)",
|
|
"POST /api/v1/ai/copilot/execute als viewer mit delete action → 403 (RBAC blocks)",
|
|
"GET /api/v1/ai/copilot/history → 200 + paginated conversation history",
|
|
"Copilot action logged in audit_log with entity_type=ai_copilot",
|
|
"Copilot respects tenant isolation: cross-tenant → 404",
|
|
"Copilot respects field-level permissions: hidden fields not in response",
|
|
"POST /api/v1/workflows mit valid steps JSONB → 201 + workflow definition",
|
|
"GET /api/v1/workflows → 200 + paginated list",
|
|
"GET /api/v1/workflows/{id} → 200 + workflow detail with steps",
|
|
"PATCH /api/v1/workflows/{id} → 200, updated",
|
|
"DELETE /api/v1/workflows/{id} → 204",
|
|
"POST /api/v1/workflows/{id}/instances → 201, instance created with status=pending",
|
|
"GET /api/v1/workflows/instances?status=in_progress → 200 + filtered list",
|
|
"GET /api/v1/workflows/instances/{id} → 200 + current_step_index + history",
|
|
"POST /api/v1/workflows/instances/{id}/advance (approve) → 200, step advanced",
|
|
"POST /api/v1/workflows/instances/{id}/advance (reject) → 200, status=rejected, initiator notified",
|
|
"POST /api/v1/workflows/instances/{id}/cancel → 200, status=cancelled",
|
|
"Event-triggered workflow: publish event → workflow instance auto-starts",
|
|
"workflow_step_history entry created on every step transition",
|
|
"Code-engine workflow: onboarding workflow runs on user creation",
|
|
"Approval step timeout → auto-reject after configured hours (tested with mock timer)"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/backend && python -m pytest tests/test_ai_copilot.py tests/test_workflows.py -v --tb=short",
|
|
"cd /app/backend && python -m pytest tests/test_ai_copilot.py tests/test_workflows.py --cov=app/ai --cov=app/workflows --cov-report=term-missing",
|
|
"cd /app/backend && python -m pytest -k 'copilot and (rbac or tenant)' -v && python -m pytest -k 'workflow and (instance or approval or event)' -v"
|
|
],
|
|
"expected_results": "All KI-Copilot tests pass: query returns proposed API calls, execute enforces RBAC (viewer→403 on delete), history paginated, audit log entries created, tenant isolation enforced, field-level permissions respected. All Workflow tests pass: CRUD definitions, instances start/advance/approve/reject/cancel, event triggers auto-start, step history logged, code-engine onboarding runs, approval timeout auto-rejects.",
|
|
"test_files": [
|
|
"tests/test_ai_copilot.py",
|
|
"tests/test_workflows.py"
|
|
],
|
|
"coverage_target": 80
|
|
},
|
|
"dependencies": [
|
|
"T01",
|
|
"T02"
|
|
],
|
|
"estimated_lines": 700,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v1"
|
|
},
|
|
{
|
|
"id": "T10",
|
|
"title": "Monitoring, Performance, Documentation & Environment Config",
|
|
"description": "Drei Module in einem Task: (1) Monitoring & Alerting: Extended Health Endpoint (GET /api/v1/health gibt DB+Redis+Storage+Worker Status zurueck), Prometheus Metrics Endpoint (GET /api/v1/metrics mit http_requests_total, request_duration, db_pool, redis_pool, arq_jobs, tenant_sessions metrics), Structured JSON Logging (structlog mit Method/Path/Status/Duration/Tenant/User), Alerting (DB pool exhausted, worker queue >100, response >2s, backup failure). (2) Performance: Performance test script (scripts/seed_perf_data.py fuer 200k contacts), DB index verification script, pagination limit enforcement (max 100), keyset pagination fuer >10k results, streaming CSV export via StreamingResponse. Performance test: 200k seed → list <500ms, FTS <500ms. (3) Documentation: README.md mit Setup-Anleitung (Dev + Prod), API-Doku via FastAPI auto-gen OpenAPI/Swagger (schon verfuegbar, dokumentiert in README), docs/admin-guide.md (Deploy, Backup, Restore, Env-Vars, Troubleshooting), docs/api-overview.md (Endpoint-Übersicht).",
|
|
"requirement_ids": [
|
|
"F-INFRA-04",
|
|
"F-PERF-01",
|
|
"F-DOC-01",
|
|
"F-INFRA-01",
|
|
"F-INFRA-02",
|
|
"F-INFRA-03",
|
|
"F-TEST-01",
|
|
"F-ENV-01"
|
|
],
|
|
"acceptance_criteria": [
|
|
"GET /api/v1/health → 200 + JSON with status, checks.database, checks.redis, checks.storage, checks.worker",
|
|
"GET /api/v1/health mit DB down → 200 + status=degraded, checks.database.status=down",
|
|
"GET /api/v1/metrics → 200 + text/plain Prometheus format (admin only, 403 for non-admin)",
|
|
"Prometheus metrics include leocrm_http_requests_total, leocrm_db_pool_connections, leocrm_arq_jobs_total",
|
|
"Structured JSON log entry for API request: {timestamp, level, event, method, path, status, duration_ms, tenant_id}",
|
|
"Error log includes stacktrace and request context",
|
|
"scripts/seed_perf_data.py --count 200000 → creates 200k contacts in test DB",
|
|
"GET /api/v1/contacts?page=1&page_size=25 with 200k records → response time <500ms",
|
|
"GET /api/v1/contacts?search=Mueller with 200k records → response time <500ms",
|
|
"page_size > 100 → 422 (max page_size enforced)",
|
|
"CSV export >1000 records → ARQ background job started → notification on completion",
|
|
"Streaming CSV export: GET /api/v1/contacts/export?format=csv → text/csv stream (not buffered in memory)",
|
|
"README.md exists with Setup-Anleitung (dev + prod), API section, links to admin-guide",
|
|
"Swagger UI available at /api/v1/docs (FastAPI auto-gen)",
|
|
"docs/admin-guide.md exists with Deploy, Backup, Restore, Env-Vars, Troubleshooting sections",
|
|
"docs/api-overview.md exists with endpoint summary table",
|
|
".env.example file exists with all required variables documented (database, redis, smtp, storage, secret_key)",
|
|
"Environment-specific config: dev, test, prod profiles documented in docs/admin-guide.md"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/backend && python -m pytest tests/test_monitoring.py tests/test_performance.py -v --tb=short",
|
|
"cd /app/backend && python -m pytest tests/test_monitoring.py --cov=app/core/monitoring --cov-report=term-missing",
|
|
"cd /app/backend && python scripts/seed_perf_data.py --count 200000 && python -m pytest tests/test_performance.py -k 'perf' -v --tb=short",
|
|
"cd /app && test -f README.md && test -f docs/admin-guide.md && test -f docs/api-overview.md && echo 'Docs OK'",
|
|
"cd /app/backend && python -m pytest tests/test_health.py -v"
|
|
],
|
|
"expected_results": "All monitoring tests pass: extended health check returns structured status, Prometheus metrics endpoint returns correct format with admin auth, structured JSON logging verified, alerting conditions logged. Performance tests pass: 200k seed completes, list endpoint <500ms, FTS search <500ms, page_size >100 rejected, streaming export works. Documentation files exist and contain required sections. README setup instructions are complete.",
|
|
"test_files": [
|
|
"tests/test_monitoring.py",
|
|
"tests/test_performance.py",
|
|
"tests/test_health.py"
|
|
],
|
|
"coverage_target": 80
|
|
},
|
|
"dependencies": [
|
|
"T01",
|
|
"T02"
|
|
],
|
|
"estimated_lines": 500,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v1"
|
|
},
|
|
{
|
|
"id": "T11",
|
|
"title": "Tags Plugin + Permissions Plugin + Entity Links Backend",
|
|
"description": "Tags plugin (CRUD, assign, bulk-assign, filter), Permissions plugin (personal root, shared root, share with users/groups, share links, permission display), Entity links (files to companies/contacts, reverse links, multi-links).",
|
|
"requirement_ids": [
|
|
"F-LINK-04",
|
|
"F-LINK-05",
|
|
"F-LINK-01",
|
|
"F-PERM-03",
|
|
"F-LINK-03",
|
|
"F-PERM-02",
|
|
"F-PERM-06",
|
|
"F-TAG-04",
|
|
"F-LINK-02",
|
|
"F-PERM-05",
|
|
"F-TAG-02",
|
|
"F-PERM-04",
|
|
"F-PERM-01",
|
|
"F-TAG-03",
|
|
"F-TAG-01",
|
|
"F-LINK-06"
|
|
],
|
|
"acceptance_criteria": [
|
|
"GET /api/v1/dms/files/{id}/permissions → 200 + permission list",
|
|
"POST /api/v1/dms/files/{id}/link → 200, file linked to entity",
|
|
"DELETE /api/v1/dms/files/{id}/link → 204, link removed",
|
|
"POST /api/v1/dms/files/{id}/share-link → 200 + public token URL",
|
|
"GET /api/public/share/{token} mit expired link → 410",
|
|
"GET /api/v1/tags → 200 + tags with counts",
|
|
"POST /api/v1/tags → 201, tag created",
|
|
"PATCH /api/v1/tags/{id} → 200",
|
|
"DELETE /api/v1/tags/{id} → 204, cascade delete assignments",
|
|
"POST /api/v1/tags/assign → 200, tag assigned to entity",
|
|
"DELETE /api/v1/tags/assign → 204, tag removed",
|
|
"POST /api/v1/tags/bulk-assign → 200, multiple tags assigned",
|
|
"DMS plugin listens to company.deleted event → linked files cleanup",
|
|
"Folder permissions enforced: user without read → 403"
|
|
],
|
|
"test_spec": {
|
|
"commands": [
|
|
"cd /app/backend && python -m pytest tests/test_tags.py tests/test_permissions.py tests/test_entity_links.py -v --tb=short",
|
|
"cd /app/backend && python -m pytest tests/test_tags.py tests/test_permissions.py --cov=app/plugins/builtins/tags --cov=app/plugins/builtins/permissions --cov-report=term-missing",
|
|
"cd /app/backend && python -m pytest tests/test_entity_links.py --cov=app/plugins/builtins/entity_links --cov-report=term-missing",
|
|
"cd /app/backend && python -m pytest -k 'tag or permission or link' -v"
|
|
],
|
|
"expected_results": "All Tag tests pass: CRUD, assignment, bulk assign, cascade delete. All Permission tests pass: personal root, shared root, share with users/groups, share links with password+expiry, permission display. Entity link tests pass: link file to company, reverse links, multi-links, event cleanup on entity deletion.",
|
|
"test_files": [
|
|
"tests/test_tags.py",
|
|
"tests/test_permissions.py",
|
|
"tests/test_entity_links.py"
|
|
],
|
|
"coverage_target": 80
|
|
},
|
|
"dependencies": [
|
|
"T01",
|
|
"T03"
|
|
],
|
|
"estimated_lines": 500,
|
|
"subagent_profile": "implementation_engineer",
|
|
"phase_scope": "v2"
|
|
}
|
|
],
|
|
"execution_plan": {
|
|
"v1_phases": [
|
|
{
|
|
"phase": 1,
|
|
"tasks": [
|
|
"T01"
|
|
],
|
|
"description": "Foundation: Core infrastructure, auth, multi-tenant, RLS policies, rate limiting. Must complete first.",
|
|
"parallel": false
|
|
},
|
|
{
|
|
"phase": 2,
|
|
"tasks": [
|
|
"T02",
|
|
"T03"
|
|
],
|
|
"description": "Parallel: Company/Contact system + Plugin framework. Both depend only on T01.",
|
|
"parallel": true
|
|
},
|
|
{
|
|
"phase": 3,
|
|
"tasks": [
|
|
"T07a",
|
|
"T09"
|
|
],
|
|
"description": "Parallel: Frontend SPA shell+auth+UI library + KI-Copilot/Workflow backend. T07a depends on T01, T09 depends on T01+T02.",
|
|
"parallel": true
|
|
},
|
|
{
|
|
"phase": 4,
|
|
"tasks": [
|
|
"T07b"
|
|
],
|
|
"description": "Frontend feature pages: Companies, Contacts, Settings, Dashboard, Search. Depends on T07a + T02.",
|
|
"parallel": false
|
|
},
|
|
{
|
|
"phase": 5,
|
|
"tasks": [
|
|
"T10"
|
|
],
|
|
"description": "Monitoring, performance, documentation, environment config. Depends on T01+T02.",
|
|
"parallel": false
|
|
}
|
|
],
|
|
"v2_phases": [
|
|
{
|
|
"phase": 6,
|
|
"tasks": [
|
|
"T04",
|
|
"T05",
|
|
"T06",
|
|
"T11"
|
|
],
|
|
"description": "Parallel: All plugin backends (DMS, Calendar, Mail, Tags+Permissions+Links). All depend on T01+T03.",
|
|
"parallel": true
|
|
},
|
|
{
|
|
"phase": 7,
|
|
"tasks": [
|
|
"T08a",
|
|
"T08b",
|
|
"T08c"
|
|
],
|
|
"description": "Parallel: All plugin frontends. Each depends on its backend + T07b.",
|
|
"parallel": true
|
|
}
|
|
]
|
|
},
|
|
"feature_coverage_summary": {
|
|
"total_features": 143,
|
|
"v1_features": 73,
|
|
"v2_features": 70,
|
|
"covered_by_tasks": {
|
|
"T01": 25,
|
|
"T02": 25,
|
|
"T03": 7,
|
|
"T04": 15,
|
|
"T05": 19,
|
|
"T06": 20,
|
|
"T07a": 23,
|
|
"T07b": 15,
|
|
"T08a": 25,
|
|
"T08b": 13,
|
|
"T08c": 16,
|
|
"T09": 5,
|
|
"T10": 8,
|
|
"T11": 16
|
|
},
|
|
"v1_tasks": [
|
|
"T01",
|
|
"T02",
|
|
"T03",
|
|
"T07",
|
|
"T09",
|
|
"T10"
|
|
],
|
|
"v2_tasks": [
|
|
"T04",
|
|
"T05",
|
|
"T06",
|
|
"T11",
|
|
"T08a",
|
|
"T08b",
|
|
"T08c"
|
|
],
|
|
"note": "v1 tasks cover all 73 core features. v2 tasks cover all 70 plugin features. Feature IDs overlap across tasks where backend API and frontend UI cover the same feature from different layers.",
|
|
"total_tasks": 14
|
|
}
|
|
} |