Skip to content

feat(search): weighted FTS ranking + searchable message bodies#294

Open
salmonumbrella wants to merge 1 commit into
maathimself:mainfrom
salmonumbrella:search/split-1-fts-bodies-rebased
Open

feat(search): weighted FTS ranking + searchable message bodies#294
salmonumbrella wants to merge 1 commit into
maathimself:mainfrom
salmonumbrella:search/split-1-fts-bodies-rebased

Conversation

@salmonumbrella

Copy link
Copy Markdown
Contributor

Split 1/3 of #283, per the review request there. Keyword-search improvements only — no infrastructure changes, no new dependencies, runs on stock postgres:16-alpine.

Summary

Search results are ranked by relevance instead of date-only, and message bodies become searchable across the whole mailbox.

  • Weighted lexical ranking — subject > sender > body (setweight A–D + ts_rank_cd), prefix matching as you type, quoted phrases, served by a GIN index over a trigger-maintained search_fts column. Filter-only queries stay date-ordered.
  • Resumable backfill — fast-DDL migrations only (0035–0037, crash-idempotent, boot-safe); search_fts fills via a background drainer, and not-yet-backfilled rows fall back to the previous query path. The legacy search_vector column stays until a follow-up removes it once backfill completes on real installs.
  • Body materialization — a provider-gated background IMAP drainer fills body_text (apple/yahoo/generic on; Gmail/PurelyMail/Microsoft off given their throttle history), with circuit breakers, poison-message forward progress, and background_jobs progress rows.
  • The REST response carries a constant mode: 'lexical' field — the stable contract the semantic follow-up PR extends with real modes.

Rebased on current main; resolves the imapManager.test.js overlap with the recent IMAP connect-backoff change by keeping both test groups.

The split is a re-partition, not a rewrite: with all three split PRs applied, the tree is byte-identical to the reviewed #283 head (3773150).

Testing

  • Backend: 767 passed / 0 failed, lint clean (--max-warnings 0)
  • Frontend: 1,390 passed / 0 failed, lint clean, production build clean

Contributor License Agreement

By submitting this pull request I confirm that:

  • I have read and agree to the Contributor License Agreement.
  • My contribution is my own original work (or I have identified any third-party material and confirmed it is compatible with the CLA).
  • I have the right to submit this contribution under the terms of the CLA.

🤖 Generated with Claude Code

Results ranked by relevance instead of date-only: subject > sender > body
(setweight A-D + ts_rank_cd), prefix matching as you type, quoted phrases,
served by a GIN index over a trigger-maintained search_fts column. Backfill
runs as a resumable background drainer (fast-DDL migrations 0035-0037, no
boot-blocking rewrite); not-yet-backfilled rows fall back to the previous
query path. Body text is materialized by a provider-gated background IMAP
drainer with circuit breakers, poison-message forward progress, and
progress reporting. Filter-only queries stay date-ordered.

No infrastructure changes - runs on stock postgres:16-alpine.

Split 1/3 of maathimself#283.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant