Agent Zero
7b4a2c0791
fix: embedding migration, worker error handling, path traversal security, response mismatches (unread-count, plugins, manifests), frontend type safety
2026-07-24 14:23:28 +02:00
Agent Zero
c3c5233e58
fix(automation): change list route from / to empty string to match without trailing slash
2026-07-24 10:44:32 +02:00
Agent Zero
992d4b79d4
fix(automation): reorder routes — static paths before dynamic {id} to prevent 400 errors
2026-07-24 10:42:08 +02:00
Agent Zero
7dd4865638
fix: register new deleted_at migration files in all plugin manifests
2026-07-24 10:37:44 +02:00
Agent Zero
eaa71780d4
fix: add missing deleted_at columns to all plugin tables, fix system-settings response schema, fix transaction rollback in permissions
2026-07-24 10:34:38 +02:00
Agent Zero
924d28cbf2
fix: resolve menu duplicates, route prefix conflicts, API path bugs, permissions.deleted_at, remove test plugin from production
2026-07-24 08:19:45 +02:00
Agent Zero
c5588e64f6
fix(plugins): export AutomationPlugin and AIUIControlPlugin from __init__.py so they get discovered
2026-07-24 01:57:27 +02:00
Agent Zero
036e87a9ed
Task 5.25: Dashboard-System — GET /api/v1/dashboard/widgets, DashboardWidgetLoader, DashboardGrid with drag-and-drop, 3 example widgets (RecentContacts, TasksSummary, CalendarUpcoming), updated Dashboard.tsx, i18n, 6 tests
2026-07-24 00:09:26 +02:00
Agent Zero
d54a87cf84
Task 5.23: Deduplication / Merge — ContactMergeHistory model, dedup service, API routes (duplicates/merge/merge-history), DedupDialog frontend, i18n, 5 tests
2026-07-23 23:58:45 +02:00
Agent Zero
182af355d1
feat(5.22): Saved Searches / Smart Lists — reusable filters for list views
...
- SavedFilter model with TenantMixin (name, entity_type, filter_criteria JSONB, user_id)
- Routes: GET/POST /saved-filters, DELETE /saved-filters/{id} with RBAC
- Alembic migration 0029_saved_filters creates saved_filters table
- Frontend: SavedFilters.tsx component with save/load/delete UI
- Frontend: api/savedFilters.ts with React Query hooks
- Integrated into ContactsListPage as example
- i18n keys for savedFilters.* in de.json and en.json
- Tests: test_saved_filters.py (9 tests) + SavedFilters.test.tsx (3 tests)
- Registered SavedFilter in conftest.py
2026-07-23 23:44:50 +02:00
Agent Zero
2c9e74776e
feat(5.21): Tasks Plugin — activities with status, priority, due dates, ARQ reminders
...
- New builtin plugin app/plugins/builtins/tasks/ with full CRUD
- Task model with TenantMixin (title, description, status, priority, due_date, assigned_to, contact_id)
- Routes: GET/POST /tasks, GET/PATCH/DELETE /tasks/{id}, POST /tasks/{id}/assign, POST /tasks/{id}/status
- All routes RBAC-protected (tasks:read, tasks:write, tasks:delete)
- ARQ cron job tasks_due_reminder (daily 8:00) sends notifications for due tasks
- Migration 0001_initial.sql creates tasks table with indexes
- Frontend: Tasks.tsx page with list, filter, create/edit modal, detail modal
- Frontend: api/tasks.ts with React Query hooks
- Route /tasks in routes/index.tsx, sidebar entry via plugin manifest
- i18n keys for nav.tasks and tasks.* in de.json and en.json
- Tests: test_tasks.py (11 tests) + Tasks.test.tsx (3 tests)
- Registered TasksPlugin in conftest.py and worker.py
2026-07-23 23:41:34 +02:00
Agent Zero
bdad91a649
feat(5.20): Custom Fields — plugin-defined fields in Contact UI
...
- Add CustomFieldDefinition to PluginManifest (text/number/date/select/multiselect/boolean)
- Add GET/PATCH /api/v1/contacts/{id}/custom-fields routes
- Merge plugin definitions with stored values in contacts.custom JSONB
- Add CustomFieldRenderer component (read + edit modes)
- Integrate into ContactDetail (read-only) and ContactEditModal (editable)
- Add custom_fields to pluginStore and active manifests API
- Add useCustomFields/useUpdateCustomFields React Query hooks
- Tests: test_custom_fields.py (9 tests) + CustomFieldRenderer.test.tsx (5 tests)
- i18n keys already present (contacts.customFields)
2026-07-23 23:35:35 +02:00
Agent Zero
15f1a57c0f
Phase 5 Batch 5 Task 5.18: Report Generator PDF-Support & Druck-Funktionen
...
- Installed WeasyPrint 69.0 for PDF generation
- Created 5 Jinja2 HTML templates: contact_list, calendar_week, calendar_month, company_list, audit_log
- All templates: A4 landscape, print-optimized CSS (@media print, page margins)
- Extended output_format in schemas.py: added pdf and print
- Created pdf_generator.py: Jinja2 + WeasyPrint pipeline with preset support
- Modified routes.py: PDF/print generation, preset endpoints (/presets, /presets/generate)
- Added RBAC (require_permission) to all report endpoints
- Generate endpoints return StreamingResponse (file download) directly
- 7 backend tests: presets listing, PDF/CSV generation, template CRUD, RBAC
2026-07-23 23:22:33 +02:00
Agent Zero
317d5c81f8
feat: MCP Client plugin (Task 5.17) - integrate external MCP servers for AI agents
...
- New plugin app/plugins/builtins/mcp_client/ with server config CRUD
- Models: McpServerConfig with TenantMixin (name, url, api_token, enabled)
- Routes: GET/POST/PATCH/DELETE /api/v1/mcp-client/servers
- Routes: GET /servers/{id}/tools, POST /servers/{id}/execute
- client.py: async MCP client using httpx for external server calls
- tool_registry_integration.py: registers external MCP tools in AI tool registry
- Migration: 0001_initial.sql for mcp_server_configs table
- Frontend: mcpClient.ts API client with React Query hooks
- Frontend: MCP Client settings UI in SettingsMcp.tsx (server CRUD, tool viewing)
- Tests: 8 tests covering CRUD, auth, tool registry integration
2026-07-23 23:02:07 +02:00
Agent Zero
9d4f701a25
feat: MCP Server plugin (Task 5.16) - expose LeoCRM tools to external AI clients
...
- New plugin app/plugins/builtins/mcp_server/ with 9 MCP tools
- Tools: search_contacts, get_contact, create_contact, list_calendar_entries,
create_calendar_entry, list_emails, send_email, list_files, upload_file
- Routes: GET /api/v1/mcp/tools, POST /api/v1/mcp/tools/{name}/execute, GET /api/v1/mcp/config
- API-token auth via session + RBAC (mcp:read, mcp:write)
- Frontend: mcp.ts API client with React Query hooks
- Frontend: SettingsMcp.tsx settings page with tool listing and execution
- i18n: de.json and en.json updated with MCP entries
- Tests: 7 tests covering tool listing, config, execution, auth, schema validation
2026-07-23 23:01:59 +02:00
Agent Zero
9cfc6bf3b0
Phase 5.15: Automated backup system with pg_dump, file backup, retention, restore, notifications
2026-07-23 22:48:19 +02:00
Agent Zero
66b6c32ed8
Phase 5.14: API documentation - OpenAPI tags, response models, examples, docs
2026-07-23 22:44:54 +02:00
Agent Zero
75a7063bff
feat(5.2): add User Preferences API with full-stack implementation
...
Backend:
- Create app/models/user_preference.py with TenantMixin (user_id, key, value JSONB)
- Create app/routes/user_preferences.py with GET/PUT/DELETE endpoints + RBAC
- Add user_preferences:read/write to CORE_PERMISSIONS
- Add user_preferences to legacy role permissions (admin/editor/viewer)
- Register route in app/main.py and app/routes/__init__.py
- Create alembic migration 0028_user_preferences
- Add UserPreference model to conftest.py for test schema
- Fix pre-existing conftest seed (Contact industry field removed in migration 0027)
Frontend:
- Create frontend/src/api/userPreferences.ts with React Query hooks
- Create frontend/src/hooks/useUserPreferences.ts syncing with uiStore
- Add i18n entries for de.json and en.json
Tests:
- 13 tests covering CRUD, tenant isolation, CSRF, unauthenticated access
- All tests passing
2026-07-23 20:39:42 +02:00
Agent Zero
903d649a0f
Phase 4: KI-UI-Steuerung — AI agent UI control via WebSocket
...
- New ai_ui_control plugin: WS endpoint /ws/ai-ui-control, REST API (POST /command, GET /command/{id}/status, GET /online-users)
- UI-Command-Protocol: 6 command types (navigate, filter, open_contact, modal, tab, settings) with Pydantic schemas
- WebSocket manager: per-user connections, command delivery, feedback storage, stale cleanup
- Frontend useAIUIControl hook: WS client with auto-reconnect, command dispatch, feedback sending
- aiUIControlStore: Zustand store for command state, active modal/tab, pending filter/settings
- AIUIControlIndicator: visual KI indication (Bot icon, toast, pulse animation)
- ContactDetail integration: syncs activeTab and personModalOpen from AI control store
- AppShell integration: useAIUIControl hook + AIUIControlIndicator
- i18n keys for DE/EN
- 18 Vitest tests: command protocol, store actions, feedback, visual indication
- TSC: 0 new errors (only 2 pre-existing Dms.tsx errors)
2026-07-23 20:13:39 +02:00
Agent Zero
5dc6f29ac1
Phase 3.5: Automation & Agents Plugin
...
Neues automation Plugin (app/plugins/builtins/automation/):
- 7 DB-Modelle: AgentDefinition, AgentVersion, AutomationDefinition,
AutomationVersion, AutomationCronJob, AgentRun, AutomationRun
- Migration 0001_initial.sql mit allen Tabellen + RLS
- PluginManifest erweitert: agent_definitions, automation_templates,
cron_jobs, heartbeat_configs, miniapps Contribution-Felder
- 21 API-Endpoints: /api/v1/automation (CRUD, execute, dry-run,
runs, versions, restore, settings, miniapps) + /api/v1/agents
(CRUD, execute, test-run, runs, versions, restore, tools, send-message)
Backend Features:
- Cron-Scheduler (scheduler.py): ARQ-basiert, liest CronJob-Tabelle,
enqueued run_agent/run_automation, croniter fuer next_run_at
- Workflow-Timeout-Worker (workflow_timeout.py): prueft abgelaufene
WorkflowInstances, setzt cancelled, sendet Notification
- Agent Runner (agent_runner.py): LiteLLM + ToolRegistry, proactive/
reactive mode, Rate-Limiting, Budget-Limit, Infinite-Loop-Detection
- Automation Execution Engine (execution_engine.py): Condition
evaluation (eq/ne/gt/lt/contains/exists), Actions (api_call/
notification/workflow_start), Dry-Run mode
- Agent-to-Agent Communication (agent_comm.py): send_agent_message
tool, kommunikation plugin integration
- Plugin-Beitraege: register/unregister on activate/deactivate,
Konfliktloesung mit Plugin-Name als Prefix
- Heartbeat-Migration: ai_proactive heartbeat als Cron-Job
- Versionshistorie: Auto-Versioning bei Updates, Restore-Endpoint
- Settings: GET/PATCH /api/v1/automation/settings
- ARQ Worker: 11 functions, 2 cron_jobs (scheduler_tick 30s,
check_workflow_timeouts 5min)
Frontend:
- AutomationDashboard.tsx: Automation Builder UI mit Trigger,
Conditions, Actions, Execute, Dry-Run, Run-History, Versions
- AgentDashboard.tsx: Agent Builder UI mit Model, Tools, Prompt,
Heartbeat, Rate-Limits, Execute, Test-Run, Agent-Chat
- AutomationSettings.tsx: Settings + MiniApp-Builder
- automation.ts: 24 React Query Hooks
- automation.ts types: TypeScript Interfaces
- routes/index.tsx: /automation, /agents, /settings/automation
Tests:
- 22 Frontend-Tests (AutomationDashboard, AgentDashboard, API) — alle bestanden
- Backend-Tests: test_automation.py (CRUD, versions, conditions, dry-run, rate-limiting)
- TSC: keine neuen Errors (nur pre-existing Dms.tsx)
- croniter dependency installiert
2026-07-23 20:00:37 +02:00
Agent Zero
fc96a2f86c
Phase 3: Plugin-UI-System (WordPress-Style)
...
Backend:
- PluginManifest um 5 neue UI-Felder erweitert: menu_items, page_routes,
detail_tabs, settings_pages, dashboard_widgets (FrontendMenuItem,
FrontendPageRoute, FrontendDetailTab, FrontendSettingsPage,
FrontendDashboardWidget)
- GET /api/v1/plugins/active-manifests Endpoint liefert UI-Manifeste
aller aktiven Plugins
- Registry.get_active_manifests() + PluginService.get_active_manifests()
- 12 Built-in Plugins mit UI-Manifest-Daten gefuellt (menu_items,
page_routes, detail_tabs, settings_pages)
- Plugin-Install-System: POST /upload (ZIP), POST /install-url (URL)
mit Validierung (Manifest, dangerous imports, SQL migrations)
Frontend:
- pluginStore.ts (Zustand) mit PluginUiManifest Typen + Selektoren
- useActivePluginManifests() React Query Hook
- PluginRegistry.tsx — fetcht Manifeste beim App-Start
- PluginLoader.tsx — dynamisches React.lazy() mit ErrorBoundary
- PluginRouteRenderer.tsx — Catch-all fuer Plugin-Routes
- routes/index.tsx — Catch-all Routes fuer Plugin-Pages + Settings
- Sidebar.tsx — dynamische Plugin Menu-Items mit Grouping + Icons
- Settings.tsx — dynamische Plugin Settings-Pages
- ContactDetail.tsx — dynamische Plugin Detail-Tabs mit Permissions
- AppShell.tsx — PluginRegistry Provider eingebunden
- SettingsPlugins.tsx — Install-UI (ZIP Upload + URL Install)
- plugins.ts — useUploadPlugin() + useInstallPluginFromUrl() Hooks
Docs & Templates:
- docs/plugin-development-guide.md — komplette Entwickler-Doku
- templates/plugin-template/ — Boilerplate mit allen Manifest-Feldern
Tests:
- 34 Vitest-Tests (PluginRegistry, PluginLoader, PluginRouteRenderer,
pluginStore) — alle bestanden
- TSC: keine neuen Errors (nur pre-existing Dms.tsx)
2026-07-23 19:01:18 +02:00
Agent Zero
b15a62bec6
Phase 1A: Remove company routes/services/models/schemas, unify to Contact
...
- Removed: app/routes/companies.py, app/services/company_service.py, app/models/company.py, app/schemas/company.py
- Updated: main.py, routes/__init__.py, models/__init__.py (removed company imports)
- Updated: action_mapper.py (company intents → contact intents, /api/v1/companies → /api/v1/contacts)
- Updated: workflows/engine.py (company.created → contact.created)
- Updated: worker.py (removed index_company)
- Updated: roles.py, permission_registry.py, permissions.py, deps.py (companies: → contacts:)
- Updated: permission_registry.py CORE_FIELD_DEFINITIONS (old field names → unified contact fields)
- Updated: address model/schema/service (entity_type company → contact only)
- Updated: ai_copilot_service.py (_exec_companies removed, _exec_contacts extended)
- Updated: ai_proactive services/jobs/context_tools (Company → Contact, company_contacts → contact_persons)
- Updated: unified_search jobs.py (removed index_company), query_understanding.py
- Updated: calendar/models.py, addresses.py docstrings
- Updated: conftest.py (Company → Contact, removed companies/company_contacts from TRUNCATE)
- Updated: test_unified_search.py (index_company → index_contact)
2026-07-23 17:29:53 +02:00
Agent Zero
879106c4eb
Phase 1C: Frontend unified contact UI
2026-07-23 17:17:32 +02:00
Agent Zero
ec81940178
Phase 0 Complete: Tasks 0.7-0.20
...
- 0.7: UI-Design-Richtlinien (docs/ui-design-guidelines.md, 535 lines)
- 0.8: Theme-Customization Backend (4 theme fields, migration 0023)
- 0.9: Theme-Customization Frontend (SettingsTheme.tsx, themeStore.ts, live preview)
- 0.10: RBAC-Audit (4 plugins secured, 53 routes with require_permission)
- 0.11: LiteLLM-Cleanup (llm_client.py migrated from httpx to litellm)
- 0.12: KI-Agent-Framework docs (plugin-development-guide.md, agent_capabilities field)
- 0.13: Heartbeat configurable (ProactiveSettings, migration 0024, frontend UI)
- 0.14: Unified Search Field-Level RBAC (resolve_permissions + filter_fields_by_permission)
- 0.15: Undo/History-System (EntityHistory model, service, routes, migration 0025, HistoryViewer)
- 0.16: Storage Backend (LocalStorage + S3Storage, DMS/attachments/mail updated)
- 0.17: Import/Export unified Contact fields (firstname, surname, email_1, phone_1)
- 0.18: .gitignore & Config-Cleanup (webui→frontend, python-jose removed, .env untracked)
- 0.19: Mail-Salt Security-Fix (per-account random salt, migration 0026)
- 0.20: AGPL replaced (PyMuPDF→pypdf, OnlyOffice→Collabora, LICENSE + THIRD_PARTY_LICENSES.md)
2026-07-23 08:42:26 +02:00
Agent Zero
c2143eea19
debug: add startup print statements for plugin activation
2026-07-22 02:14:29 +02:00
Agent Zero
5116e79fb6
fix: AIParticipantHandler recognizes plugin rooms (locked_by=ai_assistant) as AI-active
2026-07-22 02:11:34 +02:00
Agent Zero
4a71297a1e
fix: add kommunikation dependency to ai_assistant and ai_proactive for correct load order
2026-07-22 02:04:52 +02:00
Agent Zero
69ef8bb7d9
fix: add __init__.py exports for kommunikation and system_notif plugins for discovery
2026-07-22 01:35:27 +02:00
Agent Zero
cc3ac9a43d
feat: Unified Messaging System — kommunikation plugin, AI/Proactive/System participants, MessageSidebar, Rich Content Renderer
...
Phase 1: Backend plugin kommunikation (13 files, 10 tables, REST API, WebSocket, RBAC, DMS Bridge, Participant Registry, Mini-App Registry, Search Provider)
Phase 2: AI plugins as participants (ai_assistant + ai_proactive dock as participants, heartbeat job)
Phase 3: system_notif plugin (system events → chat messages, pinned System room)
Phase 4: Frontend MessageSidebar (replaces AISidebar, same design, comm API client, WebSocket hook, commStore)
Phase 5: Rich Content Block Renderer (11 components: Markdown, HTML, Image, Audio, Video, File, ActionCard, ContactCard, MiniApp, BlockRenderer)
BasePlugin: added services property + _container in on_activate
2026-07-22 01:22:15 +02:00
Leopoldadmin
b16cd5e96f
Fix Bug 5: require groups:read permission for list_groups
2026-07-20 23:13:47 +00:00
Leopoldadmin
9142f8e1b2
Pass denied_permissions through in role create/update routes
2026-07-20 23:13:47 +00:00
Leopoldadmin
cb4c2173f6
Add denied_permissions and permission_version to Role schemas
2026-07-20 23:13:46 +00:00
Leopoldadmin
578f5dbff4
Add deleted_at field to Role model for soft-delete
2026-07-20 23:13:46 +00:00
Leopoldadmin
7bb72f6b9e
Fix Bug 3+4+6: permission_version bump, denied_permissions, soft-delete
2026-07-20 23:13:45 +00:00
Leopoldadmin
26850801fd
Fix Bug 1: Set UserTenant.role_id in create_user and sync in update_user
2026-07-20 23:13:45 +00:00
Agent Zero
e94e64ba6b
DMS redesign: 3-column explorer layout with toolbar, source tree, file details panel
...
- Add backend endpoints: GET /dms/files, GET /dms/folders/{id}/files
- New SourceTree component: sources (Meine Dateien, Geteilte Ordner, Externe Speicher)
- New FileExplorer component: 5 view modes (list, table, icons-sm/md/lg)
- New FileDetails component: right panel with file metadata and actions
- Rewrite Dms.tsx: PluginToolbar + 3-column ResizablePanel layout
- Update DmsFile type: size_bytes + uploaded_by (backward compat aliases)
- Add 60+ i18n keys for de/en
2026-07-20 17:31:04 +02:00
Agent Zero
e1a9a8e33e
fix: retrieve UID after IMAP APPEND + handle uid=None mails in vanished check
2026-07-20 16:48:41 +02:00
Agent Zero
a2d68e1aca
fix: call imap_delete_mail BEFORE db.delete/folder_id change — IMAP sync was broken
2026-07-20 16:38:26 +02:00
Agent Zero
3a5520b46a
fix: remove all deleted_at/soft-delete from mails — standard mail program logic only
2026-07-20 16:08:05 +02:00
Agent Zero
fb92acb52b
fix: bidirectional sync — check sync queue before restoring deleted mails
...
- If mail has deleted_at and is still on IMAP server:
- Check sync queue for pending delete operation
- If pending delete exists: our IMAP delete failed, keep deleted, retry via queue
- If no pending delete: another program restored the mail, restore in DB
- This enables true bidirectional sync like Thunderbird/Outlook
2026-07-20 14:35:36 +02:00
Agent Zero
452828babe
fix: never restore deleted mails during sync — deleted means deleted
...
- Sync was restoring deleted_at mails when found on IMAP server
- This caused deleted mails to reappear in inbox on every sync
- Now deleted mails are always skipped during sync, never restored
- IMAP delete is retried via sync queue
2026-07-20 14:26:07 +02:00
Agent Zero
4acebe55e5
fix: stop cross-folder message_id dedup — mails were being moved between folders
...
- message_id dedup was searching across ALL folders
- A mail in Trash with same message_id as one in INBOX was found and moved to INBOX
- Now message_id dedup only searches within the SAME folder
- This matches how real mail clients work: same message_id in different folders = separate copies
2026-07-20 14:03:19 +02:00
Agent Zero
1a2f7f3ab6
fix: stop sync from moving Trash mails back to Inbox
...
- When mail is moved to Trash in DB (folder_id=Trash, deleted_at set) but IMAP MOVE fails,
the mail stays in INBOX on the IMAP server
- Previously sync restored deleted_at and moved folder_id back to INBOX
- Now sync only restores if mail is in the SAME folder in DB and IMAP
- If mail is in Trash in DB but INBOX on IMAP, skip it — sync queue will retry the MOVE
2026-07-20 13:56:30 +02:00
Agent Zero
7631698215
fix: restore deleted_at mails when still on IMAP server — sync was permanently hiding mails
...
- When IMAP delete fails, deleted_at stays set but mail remains on IMAP server
- Sync was skipping deleted_at mails, so they stayed permanently hidden
- Now sync restores deleted_at=None when mail is found on IMAP server
- This means: if IMAP delete fails, mail reappears in LeoCRM on next sync
- Only truly deleted mails (removed from IMAP server) stay hidden
2026-07-20 13:46:48 +02:00
Agent Zero
04e0c60222
fix: add deleted_at column to mail_sync_queue — process_sync_queue was crashing
...
- MailSyncQueue inherits TenantMixin which includes SoftDeleteMixin (deleted_at)
- Migration 0007 did not create this column
- process_sync_queue crashed on every auto-sync attempt
- Add migration 0008 to add deleted_at column
- Bump plugin version to 1.3.0
2026-07-20 13:42:30 +02:00
Agent Zero
11c2a0c9af
fix: deleted mails showing in inbox — set deleted_at on move to Trash, show in Trash folder
...
- delete_mail: set deleted_at when moving to Trash (not just folder_id)
- empty_folder: same — set deleted_at when moving to Trash
- list_mails: show soft-deleted mails when viewing Trash folder
- This prevents sync from moving deleted mails back to inbox
- Trash folder shows deleted_at mails, all other folders hide them
2026-07-20 13:26:39 +02:00
Agent Zero
b68accb9a1
fix: IMAP sync overhaul - move to Trash, fix func import, fix count queries
...
- Fix missing func import (imap_sync_folder was crashing silently)
- imap_delete_mail now moves to Trash folder instead of permanent delete
- Add permanent parameter: permanent=True for Trash->delete, False for Inbox->Trash
- delete_mail route: move to Trash if not in Trash, permanent delete if in Trash
- empty_folder: move to Trash or permanent delete if already in Trash
- Add Papierkorb/Trash folder to create_mail_account
- Fix not Mail.is_seen -> Mail.is_seen.is_(False) (SQLAlchemy bug)
- Fix select(text("COUNT(*)")) -> select(func.count()).select_from(Mail)
- process_sync_queue reads permanent flag from payload
2026-07-20 13:17:07 +02:00
Agent Zero
5ded6f7d0b
fix: dedup by message_id in imap_sync_folder — stop deleted mails reappearing from Trash
...
- imap_sync_folder now checks message_id in addition to (folder_id, imap_uid)
- If mail was moved to Trash by IMAP server (new UID, same message_id), it is recognized
- Soft-deleted mails with matching message_id are skipped, not re-created
- Prevents deleted mails from reappearing when IMAP server moves them to Trash
2026-07-20 12:59:19 +02:00
Agent Zero
478ea877f9
fix: stop restoring soft-deleted mails during sync — they stay deleted
...
- Removed restore logic from imap_sync_account and imap_sync_folder
- Soft-deleted mails are now skipped during sync (not touched, not restored)
- This prevents deleted mails from reappearing when they are found on IMAP
- The sync queue handles retrying failed IMAP deletes
2026-07-20 12:40:27 +02:00
Agent Zero
61ab481349
fix: incremental IMAP sync - only fetch new UIDs since last known, like real mail clients
...
- imap_sync_folder now searches only UID > max_known_uid instead of ALL
- First sync gets last 50, subsequent syncs only get new mails
- UI loads cached mails immediately from DB, sync runs in background
- Folder counts updated after sync
2026-07-20 12:12:53 +02:00