Files
SRCmail/runs/2026-08-07-v1.7.8-baseline/inventory.md
T
Bernd Rodler a622e3755b fix: Phase 1 critical+high fixes (17/18 items)
CRITICAL fixes:
- C1: Error swallowing - throw TransportError on network failure in getEmails/searchEmails
- C2: Recurrence expansion ID delimiter changed from ':' to '::occurrence::'
- C3: Cross-account calendar event UID dedup after multi-account aggregation
- C4: Admin session token revocation via JTI blacklist on logout
- C6: FTS5 schema-drop - add warning log for automatic reindex trigger
- C7: Settings lock - gate updateSetting() with isSettingLocked() check
- C8: Offline push pause - add offline event handler that closes push transports

HIGH fixes:
- H1: Push handler - add ContactCard and FileNode branches
- H2: WS fallback - await state snapshot before reconcileAfterWebSocketFallback
- H3: Auth rate limiting - add checkUserAuthRateLimit to session and token routes
- H4: OAuth logs - strip access_token from error log context
- H7: Template XSS - apply DOMPurify to HTML template body on import
- H8: Secure cookie - derive from x-forwarded-proto, not NODE_ENV
- H9: bcrypt fix - remove bcrypt prefixes from isHashed() so scrypt-only
- H13: calendarTasksEnabled - apply admin gate at runtime in calendar page
- H14: Task mutations - add try/catch error handling to update/delete/toggle
- H18: autoSelectReplyIdentity default changed from false to true

Deferred: P1.3 (C5 auth localStorage encryption) - requires custom Zustand persist adapter.
2026-08-07 12:17:41 +02:00

291 lines
16 KiB
Markdown

# Wave 0 — Feature Inventory
**Run:** 2026-08-07-v1.7.8-baseline
**Skill:** VNCmailgraph (adapted for Next.js/Zustand)
**Commit:** d8bebb531f86cab3507aed2113e8d0e6a03c1aa8
**Version:** vnc-v0.3.0-94-gd8bebb53 (VERSION=1.7.8)
**Codebase:** ~188K LOC across 745 TS/TSX files (excluding node_modules, .git)
**Framework:** Next.js 16 (App Router) + React 19 + Zustand 5
**Backend:** Stalwart Mail Server (JMAP protocol)
**Targets:** Web (PWA), Electron Desktop, Native (planned via Capacitor/RN)
---
## Method Adaptation
The original VNCmailgraph methodology assumes Angular + NgRx + `isCordova`/`isElectron` gates. This codebase uses:
- **Next.js 16 App Router** (not Angular) — routes defined via file-system routing
- **Zustand** (not NgRx) — stores in `stores/*.ts`, accessed via hooks
- **`isElectronShell()`** (not `isCordova`/`isElectron`) — platform detection via `window.vnc`
- **No `zimbra-features.ts`** — feature flags are in `lib/admin/types.ts` (`FeatureGates`, `SettingsPolicy`)
- **JMAP protocol** (not Zimbra SOAP) — `lib/jmap/client.ts` (7446 lines)
The audit method translates cleanly: feature domains = page routes + component trees; shared substrate = stores + lib services; coupling = cross-store imports.
---
## Feature Domains (derived from code)
### F1 — Mail / Email (CORE)
- **Routes:** `/app/(main)/[locale]/page.tsx` (3758 lines — main mail client)
- **Components:** `components/email/` (24 files): email-list, email-viewer (5102 lines), email-composer (3432 lines), thread-conversation-view, rich-text-editor (TipTap), tag-picker, email-hover-actions, recipient-popover, calendar-invitation-banner, unsubscribe-banner, read-receipt-banner, message-list-tabs
- **Store:** `stores/email-store.ts` (4087 lines) — largest store, manages emails, mailboxes, threads, search, tags, push connection, cross-account views
- **Protocol:** `lib/jmap/client.ts` (7446 lines) — the JMAP client powering all mail operations
- **Sub-features:** Compose/drafts, threading, unified mailbox, cross-account views, search, tags/keywords, attachments, scheduled send, read receipts (MDN), archive modes, virtual scrolling, TNEF extraction, .eml import, print
### F2 — Calendar
- **Routes:** `/app/(main)/[locale]/calendar/page.tsx`
- **Components:** `components/calendar/` (22 files): month/week/day/agenda views, event-modal (1375 lines), mini-calendar, task-modal, recurrence-editor, ical-import/subscription modals, participant-input
- **Store:** `stores/calendar-store.ts` (1289 lines) — calendars, events, multi-account aggregation, recurrence expansion, iMIP, CalDAV
- **Sub-features:** Month/week/day/agenda views, drag-to-reschedule, recurring events, iMIP invitations, .ics import, birthday calendar, virtual locations, tasks, CalDAV shared calendars
### F3 — Contacts
- **Routes:** `/app/(main)/[locale]/contacts/page.tsx`
- **Components:** `components/contacts/` (17 files): contact-list, contact-detail, contact-form, import-dialog, groups
- **Store:** `stores/contact-store.ts` (1146 lines) — contact cards, address books, multi-account, vCard import/export
- **Sub-features:** JMAP sync (RFC 9553/9610), address books, groups, vCard import/export, trusted senders, autocomplete
### F4 — Files / Briefcase
- **Routes:** `/app/(main)/[locale]/files/page.tsx`
- **Components:** `components/files/` (10 files): file-browser (2022 lines), folder-tree, upload-area, preview-modal
- **Stores:** `stores/file-store.ts` (1050 lines) + `stores/webdav-store.ts` (480 lines) — dual storage backends
- **Sub-features:** JMAP FileNode browsing, WebDAV upload with progress, grid/list views, preview, cut/copy/paste, favorites, sharing (RFC 9670)
### F5 — Tasks
- **Store:** `stores/task-store.ts` (95 lines) — VTODO CRUD, filter by pending/completed/overdue
- **Components:** `components/calendar/task-modal.tsx`, `task-list-view.tsx`, `task-toolbar.tsx`
- **Feature gate:** `calendarTasksEnabled` in admin policy
### F6 — Settings / Preferences
- **Routes:** `/app/(main)/[locale]/settings/page.tsx`
- **Components:** `components/settings/` (33 files) — account, appearance, themes, layout, reading, composing, notification, folder, filter, vacation, identity, template, keyword, calendar, contacts, files, downloads, sidebar-apps, plugins, language, protocol-handler, AI, debug, about
- **Store:** `stores/settings-store.ts` (1221 lines) — all user settings with cross-device encrypted sync
- **Sub-features:** Theme/density/font, layout preferences, reply/signature behavior, notification preferences, mailto:/webcal: protocol handling, settings sync (AES-256-GCM)
### F7 — Filters / Sieve
- **Components:** `components/filters/` (2 files): filter-rule-modal (534 lines), sieve-editor-modal
- **Store:** `stores/filter-store.ts` (254 lines) — Sieve script management
- **Lib:** `lib/sieve/` (parser + generator) — round-trip for external scripts
- **Sub-features:** Visual rule builder, raw Sieve editor, vacation responder, opaque script preservation
### F8 — Templates
- **Components:** `components/templates/` (4 files): template-picker, template-form, manager-modal, placeholder-fill
- **Store:** `stores/template-store.ts` (153 lines) — CRUD, favorites, import/export
- **Feature gate:** `templatesEnabled`
### F9 — Identity / Aliases
- **Components:** `components/identity/` (3 files): identity-manager-modal (407 lines), identity-form, sub-address-helper
- **Store:** `stores/identity-store.ts` (140 lines) — sender identities, sub-addressing
- **Sub-features:** Multiple sender identities per account, sub-addressing (`user+tag@domain`)
### F10 — AI Assistant
- **Components:** `components/ai/ai-ask-button.tsx` (264 lines)
- **Lib:** `lib/ai/` (9 files + retrieval/): local-client, local-discovery, opencode, entitlement, key-store, retrieval/fusion
- **API:** `app/api/ai/` (server/chat, server/models, retrieve, opencode/chat, opencode/models, policy)
- **Sub-features:** Local LLM (Ollama), server-hosted AI, BYOK, OpenCode runtime, mail retrieval with RRF fusion, FTS5 search index
- **Feature gate:** `aiAssistantEnabled` (default=true)
### F11 — Admin / Management
- **Routes:** 14 admin pages (dashboard, settings, branding, auth, password, policy, plugins, themes, marketplace, version, telemetry, logs)
- **Lib:** `lib/admin/` (18 files): config-manager, session, password, audit, plugin-registry, plugin-approvals, plugin-signing, bundled-plugins, domain-branding, CSP
- **Store:** `stores/admin-tab-store.ts` (42 lines)
### F12 — Plugin System
- **Components:** `components/plugins/` (7 files): plugin-slot, iframe-slot, dialog-host, consent-dialog, error-boundary
- **Store:** `stores/plugin-store.ts` (596 lines) — lifecycle management
- **Lib:** `lib/plugin-sandbox/` (13 files): runtime, host-bridge, host-api, loader, tier, protocol, registry, bundle-integrity, bundle-signing, consent, shortcuts
- **Sub-features:** Sandboxed iframe execution, postMessage RPC, tiered permissions (untrusted/privileged), admin approval gates, marketplace, dev-mode loading
### F13 — Pro Multi-Tab Shell
- **Routes:** `/app/(main)/[locale]/pro/page.tsx`
- **Components:** `components/pro/` (4 files): tab-bar, email-tab-body, compose-tab-body, interface-redirect
- **Store:** `stores/pro-tab-store.ts` (576 lines) — multi-tab management, split pane layout
### F14 — Search
- **Components:** `components/search/` (2 files): search-chips, advanced-search-panel
- **Backend:** `lib/mail-index/` (8 files) — encrypted SQLite/FTS5 index (Electron-only)
- **API:** `app/api/offline/search`, `app/api/ai/retrieve`
- **Coupling:** Heavily coupled with email-store (search state lives there)
### F15 — Authentication
- **Lib:** `lib/auth/` (7 files): crypto, session-cookie, session-secret, verify-jmap-auth, pair-reauth, pairing-store, active-account-slot
- **Store:** `stores/auth-store.ts` (2033 lines) — THE hub; manages login, logout, token refresh, multi-account sessions
- **Sub-features:** Basic auth, OAuth/OIDC with PKCE, demo mode, device pairing, TOTP 2FA, impersonation (JWT)
- **API:** `app/api/auth/` (10 routes)
### F16 — Setup Wizard
- **Routes:** `/app/(main)/setup/*`
- **Lib:** `lib/setup/` (3 files): session, state, token
- **API:** `app/api/setup/` (6 routes)
---
## Shared Substrate
### S1 — State Management (Zustand stores)
- 28 store files in `stores/` — Zustand with `persist` middleware
- **Central hub:** `auth-store.ts` imports 7 other stores; bootstraps all feature stores after login
- **Bidirectional cycle:** `email-store``message-list-tabs-store`
- **Anti-cycle pattern:** `client-registry.ts` — utility indirection to avoid auth-store cycles
- **Clean leaves:** `locale-store`, `policy-store`, `toast-store`, `ui-store` (0 dependencies)
### S2 — JMAP Protocol Layer
- `lib/jmap/client.ts` (7446 lines) — the communication backbone for ALL features
- `lib/jmap/types.ts` (938 lines) — shared type definitions
- `lib/jmap/client-interface.ts` (358 lines) — `IJMAPClient` interface (real + demo implementations)
- `lib/jmap/transport-health.ts` — failure counter for offline fallback gating
- `lib/jmap/request-limits.ts` — request batching utilities
- `lib/jmap/search-utils.ts` — search query building
### S3 — Auth / Session / Multi-Account
- `lib/auth/*` — AES-256-GCM cookie encryption, session lifecycle, device pairing
- `lib/oauth/*` — OAuth2/OIDC discovery, PKCE, token exchange
- `lib/impersonation/*` — JWT platform auth
- `lib/stalwart/*` — server-side Stalwart auth context, JMAP passthrough
- `stores/account-store.ts` — multi-account registry
- `stores/account-security-store.ts` — TOTP 2FA, app passwords, API keys
### S4 — Offline Replica (encrypted delta-sync mail store)
- `lib/offline-replica/` (13 files): engine, sync (1122 lines), store (997 lines), apply, jmap, states, read, retention, errors, schema, types
- SQLCipher-encrypted SQLite; delta sync via JMAP `/changes`
- Two-tier storage (envelope + body); cursor provenance with branded types
- **Fallback only** — consulted after live JMAP read fails; online session never sees replica data
### S5 — Local Search Index (encrypted FTS5)
- `lib/mail-index/` (8 files): store (534 lines), jmap (388 lines), extract (311 lines), reindex (385 lines), key (203 lines), paths, binding
- SQLCipher-encrypted SQLite with FTS5, **Electron/desktop only**
- Event-driven (triggered by JMAP push changes via API routes)
- Key transport uses inherited fd (pipe), not env var
### S6 — Platform Bridge
- `lib/electron-bridge.ts` (55 lines) — `isElectronShell()`, `showElectronNotification()`
- `lib/platform-capabilities.ts` (29 lines) — single source of truth for platform feature availability
- `lib/web-push.ts` — web push for PWA
- `electron/main.ts` (424 lines) — Electron main process (spawns Next.js server)
- `electron/preload.ts` (27 lines) — contextBridge, nodeIntegration=false, sandbox=true
### S7 — Plugin Sandbox
- `lib/plugin-sandbox/` (13 files) — iframe isolation, postMessage RPC, tier gating
- `lib/plugin-types.ts` (1092 lines) — massive type definitions
- `lib/plugin-hooks.ts` — hook registration for email/calendar/composer/sidebar slots
- `lib/plugin-loader.ts`, `lib/plugin-validator.ts`, `lib/plugin-storage.ts`
### S8 — HTTP Proxy / API Gateway
- `proxy.ts` (211 lines) — Next.js middleware: CSP, nonce, setup-state gating, intl routing
- `app/api/*` — 24 API endpoint groups (auth, admin, AI, offline, setup, etc.)
### S9 — Security / Sanitization
- `lib/security/url-guard.ts` (67 lines) — SSRF prevention, loopback/private-IP blocking
- `lib/email-sanitization.ts` — DOMPurify HTML sanitization
- `lib/smime-ca/` (5 files) — S/MIME certificate authority (EJBCA + local dev CA)
### S10 — Theme System
- `stores/theme-store.ts` (593 lines) — light/dark/system, custom theme installation
- `lib/theme-compiler.ts`, `lib/theme-loader.ts`, `lib/theme-logo.ts`
- `lib/builtin-themes.ts` — 8 built-in themes (2 shipping, 6 hidden)
- `lib/color-transform.ts` — luminance-based color remapping for dark mode
### S11 — Internationalization
- `stores/locale-store.ts` (19 lines)
- `i18n/routing.ts` — next-intl configuration
- `locales/` — 24 language translations
- `lib/jalali-utils.ts` — Persian calendar support
### S12 — Cross-Device Settings Sync
- `lib/settings-sync.ts` — encrypted settings sync (AES-256-GCM)
### S13 — Telemetry
- `lib/telemetry/` (7 files) — anonymous heartbeat, opt-in, HMAC-hashed logins
### S14 — Version Check
- `lib/version-check/` (5 files) — polls version server, daily jittered schedule
- `stores/update-store.ts` (118 lines)
---
## Feature Flag Registry (from lib/admin/types.ts)
| Flag | Default | Description |
|------|---------|-------------|
| `pluginsEnabled` | false | Plugin system on/off |
| `pluginsUploadEnabled` | true | Allow manual plugin upload |
| `requirePluginApproval` | true | Admin must approve plugins |
| `themesEnabled` | true | Theme system on/off |
| `sidebarAppsEnabled` | true | Sidebar app visibility/order |
| `userThemesEnabled` | true | Users can install custom themes |
| `settingsExportEnabled` | true | Settings export |
| `customKeywordsEnabled` | true | Custom keyword/tag creation |
| `templatesEnabled` | true | Email templates |
| `calendarEnabled` | true | Calendar feature |
| `calendarTasksEnabled` | true | Calendar tasks |
| `smimeEnabled` | true | S/MIME |
| `externalContentEnabled` | true | External content in emails |
| `debugModeEnabled` | true | Debug tools |
| `folderIconsEnabled` | true | Custom folder icons |
| `hoverActionsConfigEnabled` | true | Hover action configuration |
| `filesEnabled` | true | File browser |
| `contactsEnabled` | true | Contacts |
| `crossAllViewEnabled` | false | Cross-account All Mail |
| `crossUnreadViewEnabled` | false | Cross-account Unread |
| `crossStarredViewEnabled` | false | Cross-account Starred |
| `unifiedCrossAccountEnabled` | false | Cross-account unified inbox |
| `aiAssistantEnabled` | true | AI assistant (visible by default — local ships free) |
---
## Dependency / Coupling DAG (Store Layer)
```
auth-store (HUB) ──→ identity-store
├──→ account-store
├──→ calendar-store
├──→ contact-store
├──→ filter-store
├──→ settings-store
└──→ vacation-store
email-store ──→ calendar-store
├──→ auth-store
├──→ account-store
├──→ settings-store
└──→ message-list-tabs-store ←── (BIDIRECTIONAL CYCLE)
settings-store ──→ theme-store
└──→ locale-store
plugin-store ──→ locale-store
└──→ policy-store
theme-store ──→ policy-store
account-security-store ──→ auth-store
Standalone (14): file-store, task-store, filter-store, identity-store,
account-store, pro-tab-store, ui-store, vacation-store, totp-reauth-store,
calendar-notification-store, managed-account-store, update-store,
toast-store, admin-tab-store, template-store, webdav-store
```
**Critical coupling paths to audit in Wave 2:**
1. `auth-store` → bootstraps 7 feature stores on login → any bootstrap failure cascades
2. `email-store``message-list-tabs-store` — bidirectional cycle
3. `email-store``calendar-store` — cross-feature coupling (invitation banners, birthday calendar)
4. `settings-store``theme-store` → theme injection affects ALL components
5. JMAP client (`lib/jmap/client.ts`) → used by ALL feature stores via `client-registry`
---
## Platform Parity Surface
| Feature | Web (PWA) | Electron Desktop | Native (planned) |
|---------|-----------|------------------|------------------|
| Mail | Full | Full | Full (planned) |
| Calendar | Full | Full | Full (planned) |
| Contacts | Full | Full | Full (planned) |
| Files | Full | Full | Full (planned) |
| Local Search Index | ❌ | SQLCipher FTS5 | ❌ (planned) |
| Offline Replica | ❌ | SQLCipher SQLite | ❌ (planned) |
| Native Notifications | Web Push | Electron Notification | Native (planned) |
| AI Local LLM | Browser CORS | No CORS (loopback) | Native (planned) |
| S/MIME | Full | Full | Full (planned) |