From 59522a6e96bb6604460a980bca888d384ea4558a Mon Sep 17 00:00:00 2001 From: cesnimda Date: Thu, 2 Jul 2026 16:10:12 +0200 Subject: [PATCH] docs: Phase 3 recommendations (#25) --- RECOMMENDATIONS.md | 121 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 RECOMMENDATIONS.md diff --git a/RECOMMENDATIONS.md b/RECOMMENDATIONS.md new file mode 100644 index 0000000..12bb16c --- /dev/null +++ b/RECOMMENDATIONS.md @@ -0,0 +1,121 @@ +# InboxIntel — Phase 3 Recommendations + +**Date:** 2026-07-02 · Follows the completed audit remediation ([AUDIT_REPORT.md](AUDIT_REPORT.md)). +Each item: what · concrete benefit · effort (S/M/L) · risk · sources. **Ranked by value-to-effort.** + +> Research notes: grounded in official primary sources (fetched 2026-07-02) plus the +> competitor/feature research already performed in `docs/discovery/02-competitor-analysis.md`. +> (Live web *search* was quota-limited this session; the load-bearing facts below — support +> dates, EF 10 features, Npgsql 10, Renovate/Gitea — were verified against primary docs.) + +--- + +## 1. Migrate .NET 8 → .NET 10 LTS ⚠️ deadline-driven +- **What:** move the solution to .NET 10 / EF Core 10 / Npgsql provider 10; bump + `Pgvector.EntityFrameworkCore` off the 0.2.0 EF8-pin at the same time. +- **Why (hard fact):** **.NET 8 support ends 2026-11-10 — ~4 months away.** After that: no + security patches. .NET 10 is LTS until Nov 2028. This is not optional, only *when*. +- **Bonus value:** EF 10 brings **named query filters** (exactly our multi-filter tenant + scenario — e.g. tenant + soft-delete filters, selectively ignorable), **redacted inlined + constants in SQL logs** (privacy win for an email app), first-class `LeftJoin`, and + better parameterized-collection SQL (plan-cache friendly). +- **Watch-outs:** Npgsql 10 changes `array.Contains(x)` translation to `= ANY(...)` (check + our GIN-indexed paths); the migration touches every csproj + CI images + Dockerfiles. + The live-DB CI job we just added is the safety net for the search paths. +- **Effort: M** (mechanical + verify) · **Risk: M** · Blast radius: whole repo, but staged + behind the pipeline. +- Sources: [.NET support policy](https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core), + [EF Core 10 what's-new](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-10.0/whatsnew), + [Npgsql EF 10 release notes](https://www.npgsql.org/efcore/release-notes/10.0.html). + +## 2. Automated dependency updates via Renovate (self-hosted Gitea) +- **What:** run Renovate against the Gitea instance (PAT with repo/user/issue scopes, + `platform=gitea`); it opens update PRs that ride the existing required CI gates + (build, tests, gitleaks, vuln scan, live-DB). +- **Benefit:** closes the audit's supply-chain gap permanently — the MailKit/System.Text.Json + CVE round we did by hand becomes an automated PR you just merge. NuGet + npm + Dockerfile + + Actions all covered. +- **Effort: S** (a config + a scheduled runner job) · **Risk: L** (PRs are gated by CI). +- Source: [Renovate Gitea platform docs](https://docs.renovatebot.com/modules/platform/gitea/). + +## 3. Database backups (currently none!) +- **What:** nightly `pg_dump` sidecar/cron in compose, rotating N days, written to a + host path covered by your disk-encryption/backup regime (per SECURITY.md). +- **Benefit:** today a bad migration or volume loss = total data loss; the audit fixed + security but the **availability** story is a single Docker volume. Highest + value-per-line-of-config item on this list. +- **Effort: S** · **Risk: L**. Pair with a documented restore drill. + +## 4. Activate semantic search (Ollama + embedding backfill + hybrid ranking) +- **What:** the pgvector column, HNSW index, `IEmbeddingProvider`, and live-DB tests are + already shipped. Remaining: an optional `ollama` compose profile, the embedding + backfill worker (batched, VRAM-aware), and RRF hybrid merge in `SearchService` + (design: `docs/discovery/05/06`). +- **Benefit:** the flagship differentiator from the discovery blueprint — *"gym receipt + march"* finds the email; nobody mainstream offers this locally/privately. +- **Effort: M–L** · **Risk: M** (quality tuning) · Needs the RTX-3080 box to pull + `nomic-embed-text` (~0.5 GB, always-on per the AI strategy). + +## 5. Observability: OpenTelemetry + a dashboard +- **What:** wire .NET's built-in OTel (traces/metrics for ASP.NET, EF, HttpClient) exported + to a compose-profile Prometheus+Grafana (or an OTLP endpoint later). Keep Serilog for logs. +- **Benefit:** today diagnosis = `docker logs`. This gives request latency, sync-job + timings, rate-limit hits, and search-performance baselines — the "what will break first + as usage grows" early-warning system. +- **Effort: M** · **Risk: L** (additive). + +## 6. Named query filters for tenancy (after #1) +- **What:** convert the hand-rolled `CurrentUserId == Guid.Empty || …` filters to EF 10 + named filters (`"Tenant"`, future `"SoftDelete"`), selectively ignorable per-query. +- **Benefit:** cleaner + safer than the worker-bypass convention; directly feeds the + multi-provider platform's isolation model. +- **Effort: S** (post-migration) · **Risk: L** (isolation tests already exist). + +## 7. Frontend bundle code-splitting +- **What:** vite `manualChunks`/dynamic imports to split the 678 KB bundle (charts, + grid-layout, per-route chunks); drop `react-grid-layout` when the Analytics redesign + lands (it's the sole consumer). +- **Benefit:** faster cold loads; audit L-5 closed. Gzip is already on (batch B), so this + is the remaining lever. +- **Effort: S–M** · **Risk: L**. + +## 8. Keyset (cursor) pagination for search +- **What:** replace offset `Skip/Take` with keyset pagination for browse/date-ordered + paths; ranked paths already effectively top-N (design in `docs/discovery/05`). +- **Benefit:** deep-page latency stops degrading linearly at 100k+ mailboxes. +- **Effort: M** (API shape + frontend infinite-scroll cursor) · **Risk: M** (API change). + +## 9. SAST in CI (Semgrep) +- **What:** a `semgrep` job (OSS rules for C#/JS + secrets/OWASP packs) in `ci.yml` — + CodeQL is GitHub-centric; Semgrep runs anywhere Docker does. +- **Benefit:** closes audit L-6; catches injection/crypto misuse patterns the current + gates (gitleaks + dep-audit + tests) don't look for. +- **Effort: S–M** (tuning noise) · **Risk: L** (advisory job first, required later). + +## 10. Settings + feature-flag platform (multi-provider Phase 4) +- **What:** implement `docs/discovery/multi-provider/04` — `feature_flags`/`user_settings` + tables, `IFeatureFlags`/`IAiGate`, admin toggles later. +- **Benefit:** unblocks shipping AI features dark (`ai.enabled` master switch), the + Settings UI, and everything in the multi-provider plan; prerequisite for #4 to be + properly gated per the approved design. +- **Effort: L** · **Risk: M** — the biggest item, but the one the roadmap already commits to. + +--- + +## Value-to-effort ranking (summary) +| # | Item | Effort | Why this rank | +|---|------|--------|---------------| +| 1 | .NET 10 migration | M | **EOL deadline Nov 2026**; unlocks #6 | +| 2 | Renovate | S | Permanent supply-chain automation for one config file | +| 3 | Backups | S | Only protection against total data loss | +| 4 | Semantic search activation | M–L | Flagship product differentiator; infra already live | +| 5 | OpenTelemetry | M | Can't manage what you can't see | +| 6 | Named query filters | S | Cheap once #1 lands | +| 7 | Bundle splitting | S–M | Perceived speed; last audit-perf leftover | +| 8 | Keyset pagination | M | Scales search; roadmap item | +| 9 | Semgrep SAST | S–M | Last unautomated security layer | +| 10 | Settings/flags platform | L | Roadmap-committed foundation | + +**Suggested sequencing:** 2+3 immediately (tiny, standalone) → 1 (deadline) → 6 → 4 (+10 gating if you want flags first) → 5 → 7/8/9 opportunistically. + +**STOP — awaiting your selections before implementing anything (Phase 4).**