Files
Inboxintel/docs/discovery/01-architecture-review.md
cesnimda 4ce2df0a2b
CI / backend (push) Successful in 52s
CI / frontend (push) Successful in 14s
Deploy Staging / deploy (push) Successful in 18s
CI / backend (pull_request) Successful in 52s
CI / frontend (pull_request) Successful in 15s
Security / secrets (push) Successful in 4s
Security / dependencies (push) Successful in 55s
Security / secrets (pull_request) Successful in 4s
Security / dependencies (pull_request) Successful in 54s
docs: discovery blueprint + multi-provider design (#8)
2026-07-01 19:59:53 +02:00

89 lines
5.3 KiB
Markdown

# 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). `Email` designed for 100k+ rows/user; a
**generated `tsvector`** column backs full-text search.
- **Background:** hosted workers — `GmailSyncWorker` (scheduled sync), `DigestWorker` (digest).
- **AI seam (already present):** `IAiProvider` with `NullAiProvider` (disabled),
`OllamaProvider` (local `/api/chat`), `OpenAiProvider` (cloud). Contract today is a
single `CompleteAsync(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)
1. **`GmailQueryParser`** (Application) parses `from: to: domain: after: before:
is:unread|read has:attachment`; remaining text → free-text.
2. **`SearchService`** (Infrastructure) composes structured filters as EF `WHERE`
clauses, and free text via Postgres FTS:
`SearchVector.Matches(PlainToTsQuery('english', term))`, where
`SearchVector = to_tsvector('english', coalesce(Subject,'') || ' ' || coalesce(BodyText,''))`.
3. Results are per-user filtered (IDOR-safe), **ordered by `SentAtUtc DESC`**,
offset-paginated, projected to `EmailSummaryDto`.
## 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** (no `pg_trgm`).
- Category is a **single heuristic enum** — no multi-label, confidence, or learning.
- **`IAiProvider` is 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↔EmailLabel` relationship 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 (need `pg_trgm` GIN 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.