# OutlookAddin — Product Requirements Document

## Overview
A Windows VSTO/COM Outlook Add-in (C#/.NET Framework 4.8) that integrates Outlook desktop with EspoCRM. Targets 10 lawyers at marcus-law.co.il who run Outlook desktop with IMAP-connected Gmail mailboxes. The server-side `MailRouter v1.2.0` extension is already deployed and exposes `POST /api/v1/MailRouter/file` for filing parsed emails into Case/Lead/Contact/Account records.

The add-in must support Microsoft 365, Office 2021, and Office 2019 (not 2016). Distribution via ClickOnce hosted at https://platform.dev.marcus-law.co.il/outlook-addin/, signed with a self-signed code certificate trusted via GPO push on company-managed PCs.

## Tech stack
- .NET Framework 4.8 (VSTO host) — net48 for Core/UI/Tests projects (SDK-style csproj)
- WPF for dialogs (ElementHost inside WinForms UserControl for CustomTaskPane)
- HttpClient + Polly for HTTP (retry, timeout, circuit breaker)
- System.Text.Json (NuGet polyfill for 4.8)
- Serilog with File sink (daily rolling, 14-day retention)
- CommunityToolkit.Mvvm (source generators)
- xUnit + Moq + FluentAssertions for tests
- DPAPI for API key storage (`%APPDATA%\MarcusLaw\OutlookAddin\creds.dat`)
- Settings as JSON in `%APPDATA%\MarcusLaw\OutlookAddin\settings.json`
- Logs in `%LOCALAPPDATA%\MarcusLaw\OutlookAddin\logs\`

## Tasks

### Task 1: Infrastructure setup (Week 0)
Provision a Windows runner on Coolify (Windows 11 Pro VM, 4 vCPU/8GB) with VS Build Tools (workloads: VisualStudioExtension + VSTO). Install gitea/act_runner as a service, registered against gitea.dev.marcus-law.co.il with label `windows`. Generate a self-signed code-signing certificate (`New-SelfSignedCertificate`, EKU=CodeSigning, 3-year validity). Install the cert PFX in the runner's `CurrentUser\My` store. Push the public cert to all 10 lawyer machines via GPO into Trusted Publishers + Trusted Root CA. Add CODESIGN_THUMBPRINT, CODESIGN_PFX_BASE64, CODESIGN_PASSWORD, PLATFORM_DEV_SSH_KEY to Infisical `/outlook-addin` (dev env). Verify the runner can build the existing solution scaffold by pushing a no-op commit. Dependencies: none. Priority: high.

### Task 2: EspoCrmClient + Core services (Week 1)
Implement `MarcusLaw.OutlookAddin.Core.Services.EspoCrmClient` — a typed HTTP wrapper for the EspoCRM REST API. Methods: `FileMailAsync(FileEmailRequest)`, `GlobalSearchAsync(query)`, `EmailAddressSearchAsync(addr, entityType)`, `GetCaseAsync(id)`, `GetAccountAsync(id)`, `GetContactAsync(id)`, `TestConnectionAsync()` (calls GET /api/v1/App/user). Use HttpClient with Polly chain: Timeout(15s) → Retry(3, exponential 500ms) → CircuitBreaker(5 fails / 30s). Auth via `Espo-Authorization: <base64(username:apiKey)>` header. Add corresponding DTOs in `Core/Models/`: FileEmailRequest, FileEmailResponse, EspoEntityRef, SearchResultGroup. Implement DpapiCredentialStore (ProtectedData.Protect with sha256 entropy). Implement SettingsManager (load/save JSON to %APPDATA%). Implement LoggerFactory (Serilog with daily rolling sink). Write xUnit tests with mocked HttpMessageHandler covering happy path + 401 + 409 + network failure. Dependencies: Task 1. Priority: high.

### Task 3: Feature 1 — File existing mail to case (Week 1-2)
Implement the primary "File to EspoCRM" feature. UI: Explorer ribbon button "File to EspoCRM" (enabled when 1+ MailItems selected). FileToCaseDialog (WPF, RTL, 600x500): debounced live-search calling GlobalSearch, grouped results by entity type, "Recent" sidebar (10 cached in settings.json), "Create new Contact from sender" button. FilingService.FileAsync extracts each MailItem's properties on the STA thread (subject, from, to/cc/bcc, body, dateSent, PR_INTERNET_MESSAGE_ID via PropertyAccessor), reads attachments via SaveAsFile-to-temp + base64-encode, then POSTs to /MailRouter/file. On success: set MailItem.Categories += "Filed: <name>" (create the category in the store first). On 401: re-enter API key modal. On 409: treat as success. On failure: enqueue in DiskRetryQueue. Toast summary at the end. Dependencies: Task 2. Priority: high.

### Task 4: Feature 2 — Reading-pane sidebar (Week 3)
Implement the CustomTaskPane sidebar that shows matched Case/Contact for the selected email's sender. Register CustomTaskPane for olExplorer, docked right, 320px. WPF view bound to ReadingPaneViewModel. ExplorerSelectionHandler debounces SelectionChange (200ms), captures MailItem.SenderEmailAddress on STA, calls MatchingService.LookupAsync. MatchingService: 1) GET /EmailAddress/search?q=<sender>&entityType=Contact, 2) if 1 hit, follow accountId + recent cases via GET /Case?where[linkedWith]=contacts:<id>&maxSize=5, 3) cache 10 min in MemoryCache. Show match cards with "Open in EspoCRM" deep link (https://crm.../#Case/view/<id>), "File to this", "File elsewhere". Empty state with inline search. Dependencies: Task 3. Priority: medium.

### Task 5: Feature 3 — Compose from Case (Week 4)
Implement bidirectional compose flow. Outlook→EspoCRM: Inspector ribbon button "Compose from Case" visible only on MailItem compose windows. ComposeFromCaseDialog (filtered to Case results). On confirm: GET /Case/<id> → set MailItem.To from primary contact's email, MailItem.Subject = "[<case.number>] ", append HTML footer with case deep link. Stamp UserProperty `EspoCaseId` = caseId. EspoCRM→Outlook: register URL protocol `outlookaddin://` under HKCU\Software\Classes at install time. Build a small OutlookAddinProtocolHandler.exe that writes to a named pipe `\\.\pipe\MarcusLaw.OutlookAddin`. The Add-in opens the pipe on startup; pipe message triggers compose flow. ItemSend handler: when MailItem.UserProperties["EspoCaseId"] is set, after send completes (need to handle IMAP latency via Items.ItemAdd watcher on Sent Items with 60s fallback), auto-file via FilingService. Dependencies: Task 3. Priority: medium.

### Task 6: Feature 4 — Folder auto-sync (Week 5)
Implement folder watching. Settings tab "Folders": TreeView mirroring Outlook's folder hierarchy with checkboxes. Per watched folder: default parent (optional dropdown via entity search), mode (Auto-file when confident / Notify only), confidence threshold. FolderWatcher singleton holds List<Outlook.Items> in a STATIC field (critical to prevent GC unsubscribe). For each watched folder: subscribe ItemAdd. On ItemAdd: capture EntryID immediately, dedup via HashSet, queue to STA-bound TaskScheduler, call MatchingService.LookupAsync(sender). 1 hit + auto-mode → FilingService. Else → MailItem.Categories += "Needs filing" + Windows toast via Microsoft.Toolkit.Uwp.Notifications. Persist (StoreId, FolderPath, EntryID) in settings.json. Re-bind on startup. Dependencies: Task 4. Priority: medium.

### Task 7: Localization + RTL theme (Week 6)
Implement Hebrew + English localization. LocalizationManager singleton holding current CultureInfo, exposes Get(key). WPF markup extension `{l:Loc Key=...}` for XAML bindings. Strings.he.resx + Strings.en.resx covering all dialog text, error messages, ribbon labels, toast titles. RTL themes (FlowDirection=RightToLeft for all WPF root elements). Hebrew font stack (Segoe UI, David, Frank Ruehl) in Themes/RtlFonts.xaml. Default culture from CultureInfo.CurrentUICulture, override-able in Settings (requires restart). Test all 4 features render correctly in he-IL. Dependencies: Task 3, 4, 5, 6 (UI must exist before localizing). Priority: medium.

### Task 8: ClickOnce publish + release pipeline (Week 6)
Wire up the full release pipeline. Update .gitea/workflows/build.yml: invoke mage.exe to create ClickOnce manifests, sign .vsto + .application + DLLs with signtool using the cert from Infisical. Rsync publish/ to platform.dev.marcus-law.co.il:/var/www/outlook-addin/ via SSH (key from Infisical /outlook-addin/PLATFORM_DEV_SSH_KEY). Configure platform.dev nginx to serve /outlook-addin/* with proper MIME types (.vsto, .application, .manifest). Post Mattermost notification to #git-verelasim on successful release (reuse existing webhook from Infisical /mattermost). Tag the first release v1.0.0. Test end-to-end install on a clean Windows VM. Document the manual GPO trust deployment in docs/IT-SETUP.md. Dependencies: Task 1, 7. Priority: high.

### Task 9: Documentation + rollout (Week 6)
Finalize docs/ONBOARDING.md (Hebrew, lawyer-facing) and docs/IT-SETUP.md (admin: cert generation, GPO push, API key provisioning). Record a 5-minute screen capture demoing all 4 features. Coordinate with IT to push the self-signed cert to all 10 machines via GPO BEFORE the install link goes out. Generate API keys for all 10 lawyers in EspoCRM Admin → API Users (or per-user keys via User Profile). Distribute the install link + per-user API key by individual secure email. Provide office hours for the first 48 hours. Dependencies: Task 8. Priority: high.
