Advanced email search: structured filters, sort, date-integrity (closes #288, #247, #298, #304, #372)#382
Closed
kisst wants to merge 51 commits into
Closed
Advanced email search: structured filters, sort, date-integrity (closes #288, #247, #298, #304, #372)#382kisst wants to merge 51 commits into
kisst wants to merge 51 commits into
Conversation
Adds vitest.config.ts and one smoke test per package, plus test/test:watch scripts. Dependency declared in package.json; install deferred to verification phase.
…bs-OU#372) Allow archived emails to record that the original Date header was missing or unparseable, rather than silently substituting the ingestion timestamp. Adds OriginalDateSource union and ArchivedEmail.originalDateSource.
Adds popover, calendar, range-calendar, date-picker, command, combobox, toggle-group, tabs, sheet, and tooltip components. No business-logic consumers yet; primitives only.
The Bulgarian locale ships in packages/frontend/src/lib/translations/bg/ and the settings page already lists it as a selectable language, but the type union omitted it, causing a svelte-check error on the settings page. Pre-existing on main; surfacing it during this PR's svelte-check runs.
|
I have read the CLA Document and I hereby sign the CLA You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #381 (umbrella). Closes #288, #247, #298, #304, #372.
This PR ships the full advanced-search initiative as one cohesive change. The work is split into 51 atomic commits organized by the master plan in
docs/plans/advanced-search.md, so reviewers can audit each slice (P0 → P6) independently even though the merge is one PR.What this PR delivers
Bug fixes
POST /v1/searchhonors a typedfiltersobject;GET /v1/searchno longer 400s on missingkeywords(deprecated, kept for back-compat withDeprecation/Sunsetheaders per RFC 8594).Dateheader is preserved instead of silently falling back to ingestion time. When no usable date can be recovered,sentAtisnulland the UI says "Original date unknown" rather than lying. Existing rows are repairable via a new backfill worker.New features
from,to,cc,bcc,subject,timestamp,path,tags,hasAttachments,sizeBytes,isOnLegalHold,threadId,attachments.sha256,ingestionSourceId,userEmail.Backend infrastructure
packages/backend/src/services/search/filterTranslator.ts— field allowlist, op allowlist per kind, escaped-quote rendering,ingestionSourceIdgroup expansion preserved, dotted-key flattening forattachments.sha256,path.excludesupport.reindexQueue+ processor + worker +ReindexService+ admin REST endpoints at/api/v1/admin/reindex) for re-indexing email subsets into Meilisearch after schema changes.dateBackfillQueue+ processor + worker +DateBackfillService+ admin REST endpoints at/api/v1/admin/jobs/date-backfill) — streamsarchived_emailscursor-paginated, re-parses.emlfrom storage, recomputessentAtandoriginalDateSource, enqueues reindex only for changed rows. Idempotent resume via thedate_backfilled_atcolumn. CLI script atpackages/backend/scripts/run-date-backfill.ts.path,tags,hasAttachments,sizeBytes,isOnLegalHold,threadId,attachments.sha256all filterable;subject,sizeBytes,fromall sortable;maxValuesPerFacet: 10000to fix fix: increase maxValuesPerFacet to fix Top Senders dashboard panel #363).archived_emails.original_date_source('header' | 'received' | 'unknown', default'header') andarchived_emails.date_backfilled_at(nullable). Migration0035_lonely_roulette.sql.Frontend
GET /search?keywords=toPOST /searchwith full structured body.Decisions recorded for review
The master plan flagged 10 open questions (
docs/plans/advanced-search.md§7). Decisions taken — push back on any of these and I'll adjust:limit25 onPOST, 10 onGETshimlimitsearch:filterpermissionsent_at_idxDB index addeduserPreferencesstays localStorage in v1/v1/tagsendpoint yet/v1/archive/mailboxesendpointRollout
The migration is non-destructive but must run before the new code starts ingesting:
Estimated reindex time: a few minutes per 100k emails on local storage, longer on S3 (storage-bound). The queue is pausable.
Commit map (51 atomic commits)
Reviewable by slice. Each commit builds independently and passes its own tests.
edd975etest scaffolding9ca2f91types,75f2a88translator,b993932service wiring,7a1cb6bPOST endpoint,c0ea672tests1007839db41c2bschema + migration98fa81dextractor,fea8369connectors,433bcedservices,4a53d78OpenAPI77d32d4i18n,ee2c7c9UI null-handling,4b85765Archived-on row3afd81cqueue/worker,24e110bservice+REST,bcfca5cCLI,0713225tests,74c6e75OpenAPI47e688atypes,c8aa586Meili settings,98882eftranslator allowlist,e606769indexer,053da53reindex orchestrator,755158etests,811a2aeOpenAPId767676UI primitives885f4abSearchResults extraction811a99bURL state,d4d90ddpreferences,ce1e6c4tests7efb494filter components,8b3b73apanel,495f189POST switch,c700a15meta strip,ac3b45di18n,c96c825clear-all fix2559f83types widening,3d17f97sort precedence,94824aeSortControl,510ee56i18nbdd1881preference UI,6f21235i18n35bc1dcjsdom,135e01bSQL annotation,46467f1vi.hoisted,37f0ee1vitest alias,5a2d3f2OpenAPI regene6e5269plan doc,5a05fcebg locale fixTest plan
\d archived_emailsshowssent_atnullable plus the two new columns.sentAtmatches the originalDateheader.Date:header removed; confirmsentAtis null and detail view shows "Original date unknown" with "Archived on: ..." separately.POST /v1/search { "filters": { "from": { "op": "contains", "value": "@acme.com" } } }returns matches with noquery.GET /v1/search(nokeywords) returns 200 withDeprecation: trueheader (regression for API search not using filters parameter #288).POST /v1/admin/jobs/date-backfillreturns ajobId;GET /:jobId/statusreports progress.POST /v1/admin/reindex { "scope": "full" }re-indexes the corpus;POST /v1/search { "filters": { "hasAttachments": true } }returns matches after completion./dashboard/search; advanced filter panel toggles open; apply a date-range + From filter; URL contains both as flat query params; reload preserves filters.sort=sizeBytes:desc.Follow-ups (not in this PR)
/v1/archive/mailboxesendpoint to unblock the MailboxFilter/v1/tagsendpoint or facet-driven tag autocompletearchived_emails.sent_atfor retention-policy queriesuserPreferencesfrom localStorage to DB-backed tablecc / refs: #146 #244 #130 #40 #212 #137 #363