5.3 KiB
01 — Architecture Review (current state)
Phase 1 deliverable: a grounded assessment of InboxIntel as it exists today, from the source. This is the baseline the redesign builds on.
Architecture
Clean Architecture, .NET 8 — strict dependency rule Api → Infrastructure → Application → Domain.
| Layer | Responsibility | Key contents |
|---|---|---|
| Domain | Entities + enums, no external deps | Email, Sender, Domain, MailThread, Label/EmailLabel, Attachment; EmailCategory |
| Application | Interfaces, DTOs, validation, parsing | ISearchService et al., GmailQueryParser, FluentValidation |
| Infrastructure | EF Core/Npgsql, integrations, workers | SearchService, CleanupService, AnalyticsService, HeuristicClassifier, AI providers, exports, GmailSyncWorker, DigestWorker |
| Api | ASP.NET Core Web API | Thin controllers, DI, Serilog, OAuth |
| Frontend | React 18 + Vite SPA | Chart.js, react-grid-layout (draggable dashboard), Tailwind |
- Data: PostgreSQL (EF Core + Npgsql).
Emaildesigned for 100k+ rows/user; a generatedtsvectorcolumn backs full-text search. - Background: hosted workers —
GmailSyncWorker(scheduled sync),DigestWorker(digest). - AI seam (already present):
IAiProviderwithNullAiProvider(disabled),OllamaProvider(local/api/chat),OpenAiProvider(cloud). Contract today is a singleCompleteAsync(systemPrompt, userPrompt). - Security: Google OAuth2 (read-only Gmail), cookie session + JWT, refresh tokens
encrypted via Data Protection API, IDOR-safe global query filters, SSRF egress
guard, non-root containers, destructive actions require
Confirmed+ server preview. - Delivery: Docker Compose (Postgres/API/frontend/optional nginx) + Gitea CI/CD.
Feature set
Gmail connect + sync → Postgres · analytics dashboard (draggable widgets) · advanced search (Gmail operators + FTS) · safe bulk cleanup · unsubscribe management (List-Unsubscribe / one-click) · heuristic categorisation (smart folders) · exports (PDF/CSV/JSON) · optional advisory AI · sender/domain aggregation.
Existing search implementation (flagship)
GmailQueryParser(Application) parsesfrom: to: domain: after: before: is:unread|read has:attachment; remaining text → free-text.SearchService(Infrastructure) composes structured filters as EFWHEREclauses, and free text via Postgres FTS:SearchVector.Matches(PlainToTsQuery('english', term)), whereSearchVector = to_tsvector('english', coalesce(Subject,'') || ' ' || coalesce(BodyText,'')).- Results are per-user filtered (IDOR-safe), ordered by
SentAtUtc DESC, offset-paginated, projected toEmailSummaryDto.
Strengths
- Clean, testable layering; DI throughout; 39 tests + CI/CD gate.
- Real Postgres FTS (generated tsvector), not naïve
LIKE. - Security-forward (IDOR filters, encrypted tokens, SSRF guard, confirmed destructive ops).
- AI already decoupled behind
IAiProvider— the "no-AI / Ollama / future" requirement is architecturally seeded. - Read-only scope + advisory AI = privacy-respecting.
Weaknesses
- Search is single-mode: ordered by date, not relevance (no
ts_rank); no fuzzy/typo tolerance, no semantic/vector search, no grouping, no "why matched," no saved/recent/suggested searches. - FTS is English-only and covers only Subject + Body (not sender, attachment names, labels).
- Sender/domain filters use
.Contains()→ non-sargable ILIKE scans (nopg_trgm). - Category is a single heuristic enum — no multi-label, confidence, or learning.
IAiProvideris chat-only — no embeddings/classification/extraction contract, so semantic search & structured extraction can't yet be expressed.- Threading (
ThreadId) exists but isn't surfaced as conversation intelligence.
Technical debt
- EF global-query-filter vs required
Email↔EmailLabelrelationship warning (in logs). - Hardcoded English FTS config.
- 678 KB single JS chunk (no code-splitting) — cold-load cost.
- Relevance-blind ordering.
- AI interface too narrow for the roadmap.
Performance bottlenecks
.Contains()sender/domain → sequential scans (needpg_trgmGIN indexes).- Offset pagination (
Skip/Take+Count) degrades on deep pages → keyset/cursor. - No score-based top-N (no ranking) → sorts full match set by date.
- Single JS chunk (~219 KB gzip) slows cold loads.
- Full-mailbox sync latency at 100k+ (batching/Polly present, but per-message fetch).
Documentation quality
Strong for a scaffold: README, docs/ARCHITECTURE.md, OAuth setup, docs/specs/*,
AGENTS.md, plus WORKFLOW.md/CHANGELOG; meaningful XML-doc comments.
Gaps: no API reference, no ERD/data-model doc, no ADRs, no search/AI design docs —
which this discovery produces.
Verdict
A clean, secure, well-tested foundation with a genuine FTS base and an AI seam already in place. The biggest opportunities are exactly where the product wants to win: relevance-ranked, multi-mode, assisted search; a richer AI contract (embeddings/classification/extraction); conversation intelligence; and a modern, approachable UX. None of these require a rewrite — they extend the existing seams.