Commit Graph

5 Commits

Author SHA1 Message Date
cesnimda 4f415ce7bf feat(search): relevance ranking + websearch_to_tsquery
CI / backend (pull_request) Successful in 1m14s
CI / frontend (pull_request) Successful in 29s
Security / secrets (pull_request) Successful in 5s
Security / dependencies (pull_request) Successful in 1m20s
Slice 1 of search-core (docs/discovery/05, MVP): replace date-only ordering with
ts_rank_cd relevance ranking (Npgsql RankCoverDensity) when a free-text query is
present, recency as a tiebreaker; browse-only requests (no query) keep today's
date-descending order unchanged. Upgrade plainto_tsquery -> websearch_to_tsquery
so quotes ("exact phrase"), OR, and -exclusions work as users already expect
from web search boxes.

Verified: ranking SQL semantics (plain/phrase/exclusion/ts_rank_cd score) checked
directly against a live Postgres instance, not just Npgsql's docs. Added a
regression test locking the date-order fallback path (the one behaviour testable
without a live Postgres, matching this repo's existing no-Testcontainers
convention -- see AuthEndpointsTests.TestAppFactory). All 40 tests pass; full
Release build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 21:03:59 +02:00
cesnimda 1e15b84dce fix(search): move pagination clamp to controller (fixes cleanup regression)
Phase 5 re-validation caught a functional regression: the V-10 clamp in
SearchService.SearchAsync also capped CleanupService's internal target resolution
(pageSize 10000 -> 200), silently limiting bulk cleanup-by-query to 200 emails.

The clamp belongs at the user-facing trust boundary, not the shared service: move
MaxPageSize (200) enforcement into SearchController (both the POST body and GET query
paths). Internal callers of ISearchService now request large pages unhindered, while
user requests are still bounded. Adds a regression test proving SearchService returns
a 250-row page uncapped. No security regressions per Phase 5. All 39 tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 00:29:45 +02:00
cesnimda e6a0239436 fix(security): systemic IDOR safeguard via EF global query filters
Defense-in-depth tenant isolation: every user-owned entity (Email, Sender,
MailThread, MailDomain, Attachment, Label, SyncState, AnalyticsAggregate,
WidgetLayout, UnsubscribeItem) gets a global query filter restricting reads to the
authenticated user. AppDbContext takes an optional ICurrentUser; CurrentUserId is
Guid.Empty for background workers / design-time, which DISABLES the filter so sync
and tooling (which already scope by an explicit userId) are unaffected. On the HTTP
attack surface a forgotten manual `WHERE UserId ==` can no longer leak another
tenant's rows.

Phase 1 confirmed no active IDOR; this is preventive, and prioritised now because the
upcoming automation engine will add many new queries.

Also: moved the Npgsql-only tsvector FTS mapping out of EmailConfiguration into
AppDbContext.OnModelCreating, guarded by Database.IsRelational() (Ignored otherwise),
so non-relational test providers work — honouring the existing Email.SearchVector
comment. Production (Npgsql) model is unchanged; no migration needed.

Adds 3 cross-user tenant-isolation integration tests. All 38 tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 00:20:56 +02:00
cesnimda 29a4aa2212 scaffold: EF design ref + initial migration 2026-06-30 16:08:26 +02:00
cesnimda f43ef5f945 chore: init project 2026-06-30 15:53:32 +02:00