114 Commits

Author SHA1 Message Date
PointStar 2368764251 feat(sidebar): Task #4 — reading-pane sidebar with sender matching
Core:
- IEspoCrmClient.ListCasesForContactAsync (paged where[]=linkedWith query)
- EspoListResponse<T> generic envelope for /list endpoints
- IMatchingService + MatchingService: EmailAddress/search → Contact →
  Account → recent 5 Cases. MemoryCache 10-min TTL; caches null and
  ambiguous results too. Returns null for 0 matches, IsAmbiguous=true
  for 2+, populated MatchResult for exactly 1.
- MatchResult DTO with Contact / Account / RecentCases / IsAmbiguous

UI:
- ReadingPaneView (WPF UserControl, RTL): 6 states — Empty / Loading /
  Match / NoMatch / Ambiguous / Error — switched via Visibility bindings
- ReadingPaneViewModel: state machine, FileRequested + OpenInBrowserRequested
  events, Reset()/LoadAsync() with cancellation chain (every selection
  cancels the previous lookup)

Host:
- ExplorerSelectionHandler: subscribes to Outlook.Explorer.SelectionChange,
  200ms debounce via Timer, dedupes by last sender, marshals to WPF
  dispatcher before reading COM state
- SidebarController: attaches a CustomTaskPane per Explorer
  (ElementHost wrapping ReadingPaneView), tracks bindings by COM identity,
  unhooks on Explorer.Close. Sidebar defers attach until CRM client is
  configured (subscribes to CrmClientChanged)
- AddInHost: MatchingService field, MemoryCache shared across lookups,
  InitializeSidebar(taskPanes) invoked from ThisAddIn_Startup

Core/UI/Tests green (38 tests passing); VSTO host still needs VS
Installer Repair locally.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:42:40 +03:00
PointStar aa65546fb1 feat(settings): add first-run Settings dialog and ribbon entry
- SettingsDialog (WPF, RTL): General tab (URL/username/API key/locale) +
  About tab; PasswordBox-bound API key, Test Connection probe, Save/Cancel
- SettingsViewModel: loads from SettingsManager + DpapiCredentialStore,
  Test Connection spins a transient HttpClient + EspoCrmClient and reports
  401 vs network failures separately; Save persists then signals dialog
  close
- Ribbon: second "הגדרות" button in Marcus-Law group; "File to EspoCRM"
  now offers to open Settings inline when not configured
- AddInHost.LaunchSettings tears down and rebuilds CRM/filing/retry stack
  so new credentials take effect immediately (CrmClientChanged event)
- Tag .taskmaster/tasks/tasks.json: Task #3 in-review with implementation
  notes (was already locally modified)

Core/UI/Tests green (38 tests passing); VSTO host project still requires
VS Installer Repair to compile locally.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:37:39 +03:00
chaim 923a0b657f fix(host): enable AutoGenerateBindingRedirects for System.Text.Json deps
VSTO csproj template disables binding redirects, but System.Text.Json's
transitive deps (System.Text.Encodings.Web, System.Runtime.CompilerServices.Unsafe,
System.Memory) ship as out-of-band NuGet packs whose versions diverge
from .NET Framework 4.8's facade assemblies. Without redirects, the
JIT loads the wrong Unsafe.dll for DefaultJavaScriptEncoder's static
init, throwing FileLoadException wrapped in TypeInitializationException
when SettingsManager.JsonOptions is touched.

GenerateBindingRedirectsOutputType=true ensures the generated
{MarcusLaw.OutlookAddin.dll}.config goes alongside the assembly so
the VSTO loader actually sees it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:36:54 +00:00
chaim e8265400f8 fix(host): copy Core's NuGet refs (System.Text.Json, ProtectedData, Polly, Caching)
Legacy VSTO csproj doesn't follow PackageReferences transitively from
ProjectReferences — at runtime the host's bin\ ends up without the
satellite DLLs that Core depends on. JIT'ing SettingsManager throws
a type-initializer exception because JavaScriptEncoder.UnsafeRelaxedJsonEscaping
(in System.Text.Encodings.Web, transitive of System.Text.Json) is missing.

Pull all four runtime NuGet packs into the host directly. Versions
mirror Core.csproj exactly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:31:40 +00:00
chaim daf3c422ca fix(host): reference System.Net.Http for HttpClient in legacy VSTO csproj
The legacy VSTO csproj doesn't include System.Net.Http in its default
references. Adding it so HttpClient resolves in AddInHost.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:29:42 +00:00
chaim 12e0013f28 fix(host): pass HttpClient to EspoCrmClient ctor + dispose on shutdown
The composition root was calling EspoCrmClient(baseUrl, user, key, logger)
which doesn't match the actual ctor signature
EspoCrmClient(HttpClient, string, string, string, ILogger). One missing
HttpClient argument = one compile error blocking the host build.

- AddInHost now owns a single HttpClient (Timeout=30s), passed to
  EspoCrmClient on init, disposed alongside the retry processor and
  Serilog on shutdown.
- baseUrl.ToString() satisfies the string parameter; the Uri.TryCreate
  upstream still validates the URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:26:25 +00:00
chaim 9bac4025e8 fix(host): set LangVersion=latest + Nullable=enable on VSTO csproj
The legacy VSTO csproj defaults to C# 7.3, but the host code (e.g.
AddInHost, MailItemExtractor) uses nullable reference types — which
require C# 8.0+. Building fails with ~12x
"Feature 'nullable reference types' is not available in C# 7.3".

Sync with the SDK-style Core/UI/Tests projects that already declare
LangVersion=latest + Nullable=enable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:23:58 +00:00
PointStar 14ed1f6142 feat(filing): wire Feature 1 host (ribbon, extractor, retry processor)
OutlookAddin host project:
- ExplorerRibbon (IRibbonExtensibility + ExplorerRibbon.xml embedded): adds
  "תייק ל-EspoCRM" button to Mail Home tab, enabled only when 1+ MailItems
  selected; invalidates on Explorer.SelectionChange
- MailItemExtractor: STA-side conversion of Outlook.MailItem to MailEnvelope
  primitives (subject, from, to/cc/bcc, body, PR_INTERNET_MESSAGE_ID,
  attachments base64), with COM RCW release on each iteration
- RetryQueueProcessor: 30s background drain, max 3 attempts per item,
  401 short-circuits the loop, items abandoned (not deleted) after max
- AddInHost: composition root — Logger, SettingsManager, DpapiCredentialStore,
  EspoCrmClient, FilingService, RetryQueueProcessor. LaunchFileToCaseAsync
  reads selection, extracts, opens dialog, files, stamps "Filed: {name}"
  category on success, promotes target into Settings.RecentEntities (max 10),
  shows summary MessageBox.
- ThisAddIn: instantiate AddInHost in Startup; CreateRibbonExtensibilityObject
  returns ExplorerRibbon

VSTO targets are missing on this machine — host project not built locally.
Core/UI/Tests still green (38 tests passing).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:11:36 +03:00
PointStar e527aa80af feat(filing): scaffold Task #3 Feature 1 — file mail to Case/Contact
Core layer:
- FilingService: orchestrates batch filing with 401-aborts-batch, 409-treats-as-success, transient errors fall to DiskRetryQueue
- DiskRetryQueue: atomic write (tmp + rename), Hebrew UTF-8 round-trip, idempotent remove
- Models: MailEnvelope (STA-extracted primitives), FilingTarget, FilingOutcome enum, FilingItemResult, FilingBatchSummary, RetryQueueItem
- EspoCrmClient.CreateContactAsync for "create contact from sender" flow

UI layer:
- FileToCaseDialog (WPF, RTL, Hebrew labels) with grouped search results + recent sidebar
- FileToCaseViewModel: 250ms debounced GlobalSearch, create-contact-from-sender command, DialogResult signaling

Tests (38 passing):
- FilingServiceTests: happy path, 409, 401 aborts batch, transient enqueues, queue failure → Failed, target propagation, null guards
- DiskRetryQueueTests: id assignment, Hebrew round-trip, corrupt-file skip, idempotent remove, atomic overwrite

VSTO host project (OutlookAddin.csproj) regenerated; ThisAddIn wiring in follow-up commits.
gitignore: exclude .claude/settings.local.json (per-machine).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:04:10 +03:00
PointStar f563dd17dd feat(core): implement EspoCrmClient, DPAPI store, settings, logger (Task #2)
- EspoCrmClient: typed REST wrapper with Polly v8 pipeline
  (Timeout 15s -> Retry 3 exp+jitter -> CircuitBreaker 0.5/5/30s).
  Auth via Espo-Authorization header (base64 username:apiKey).
  Treats 409 on /MailRouter/file as success (already-filed dedup),
  401/403 raise EspoCrmAuthorizationException for re-auth UI.
- DTOs in Models/ matching MailRouter v1.2.0 contract from
  PROJECT-BRIEFING.md (FileEmailRequest now includes replyTo + isHtml,
  attachments use contentType+contentBase64).
- DpapiCredentialStore (Security/): ProtectedData.Protect with
  CurrentUser scope, SHA256("MarcusLaw.OutlookAddin.v1") entropy.
- SettingsManager + AppSettings + WatchedFolder (Configuration/):
  System.Text.Json with UnsafeRelaxedJsonEscaping for Hebrew strings,
  UTF-8 without BOM, recovers to defaults on missing/corrupt file.
- LoggerFactory (Logging/): Serilog daily-rolling File sink with
  14-day retention.

24 xUnit tests covering happy/4xx/5xx/auth/Hebrew round-trips all pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 13:27:05 +03:00
PointStar 75505fbbff chore: remove broken VSTO host stub pending VS template regeneration
The hand-written legacy csproj at src/OutlookAddin/ is marked Unsupported
by VS 2022. Per PROJECT-BRIEFING.md (steps 5-11), the host project must
be regenerated from the VSTO template inside Visual Studio with the
Office workload — there is no CLI/dotnet template equivalent.

Removing now so the next VS session starts from a clean slate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 13:26:45 +03:00
chaim 485056d46b docs: add PROJECT-BRIEFING.md for handoff to Windows VS session
Self-contained briefing for a fresh Claude Code session picking up work
on this project from a Windows machine running VS 2022. Covers:

- TL;DR + 4 features
- MailRouter API contract + EspoCRM endpoints
- Tech stack (locked decisions)
- Repo layout + current state
- Step-by-step recipe to regenerate the VSTO host project from the
  template (the hand-written csproj is incompatible with VS)
- Conventions + deferred work + open risks

Read this before doing anything: docs/PROJECT-BRIEFING.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 10:11:45 +00:00
chaim 5e47bca82f chore: bootstrap Task Master with 9-task PRD breakdown
Adds the Task Master AI workspace per ~/espocrm-extensions/CLAUDE.md
convention (per-extension .taskmaster/). The PRD parses into 9 tasks
matching the 6-week implementation plan:

  #1 Windows runner + code signing infra (high)
  #2 Core services: EspoCrmClient, DPAPI, settings, logger (high)
  #3 Feature 1: File mail to case (high)
  #4 Feature 2: Reading-pane sidebar (medium)
  #5 Feature 3: Compose from case (medium)
  #6 Feature 4: Folder auto-sync (medium)
  #7 Localization + RTL (medium)
  #8 ClickOnce publish + release pipeline (high)
  #9 Documentation + rollout (high)

Config uses provider=claude-code (free) per workspace convention.
Removed task-master init's overaggressive .gitignore entries
(*.sln, *.sw?, .vscode, .idea, *.ntvs*, *.njsproj, node_modules/)
that collided with this repo's VS solution file.

Refs Task Master: see .taskmaster/tasks/tasks.json

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 09:21:39 +00:00
chaim cf10db00a3 chore: scaffold Outlook VSTO Add-in for EspoCRM
Initial repo scaffold for a Windows VSTO/COM Outlook Add-in (C#/.NET FW 4.8)
that integrates Outlook desktop with EspoCRM via the existing MailRouter
v1.2.0 endpoint (POST /api/v1/MailRouter/file).

Includes:
- Solution + 4 csproj projects (host, Core, UI, Tests) under src/
- VSTO host project stub (ThisAddIn.cs, requires VS 2022 + Office workload to fully resolve)
- Core/UI/Tests as SDK-style net48 projects (NuGet: Polly, System.Text.Json,
  Serilog, CommunityToolkit.Mvvm, xUnit, Moq, FluentAssertions)
- .gitea/workflows/build.yml for Windows runner CI (publish/sign placeholders)
- docs/ARCHITECTURE.md (component diagram, threading model, per-feature flow)
- docs/ONBOARDING.md (Hebrew lawyer-facing install guide)

Server-side already in place: MailRouter v1.2.0 — see plan
~/.claude/plans/resilient-sauteeing-feather.md for the 6-week implementation
plan.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 09:05:07 +00:00