Search
Cross-library full-text search over document titles, content, and folder names. Powered by Postgres tsvector columns + websearch query syntax. Debounced and capped.
Search in sweetdocs runs against the database’s full-text index, cross-library, and returns matches across every document and folder you have access to.
- Auth migration plan My Documents…the auth migration rewrites the cookie store as part of the v2 cutover, with a feature flag controlling the…
- Billing v2 RFC Acme Engineering…dependent on the auth migration shipping first so token claims carry the new tenant id; until then bill…
- Q1 retro notes My Documents…The biggest win was that the auth migration shipped two weeks early and unblocked the SSO work…
- Auth migration Acme EngineeringFolder · 12 docs
Where to search
There are two surfaces:
| Surface | Best for |
|---|---|
| Command palette (⌘K) | Open or jump to a specific doc by title; recent documents are surfaced first |
| Dedicated search input (sidebar / search panel) | Free-text queries with snippets and content matches |
The command palette covers fast “I know what I want” jumps; the dedicated search covers exploratory queries.
How matching works
Search is backed by Postgres tsvector columns:
documents.search_tsv— built from title + contentfolders.search_tsv— built from name
Queries use Postgres websearch_to_tsquery, which understands a small natural syntax:
| You type | Means |
|---|---|
auth migration | Both words must appear (implicit AND) |
"auth migration" | Exact phrase match |
auth OR migration | Either word |
auth -migration | Documents matching “auth” but not “migration” |
migration:* | Prefix match (any word starting with “migration”) |
These are real Postgres semantics — what websearch_to_tsquery understands is what works here.
Scope
Search reads across every library you have access to, including:
- Your personal library
- Org libraries you’re a member of
- Any individual documents shared with you
Results show the library name next to each match so you know where the doc lives.
What’s returned
For each result:
| Field | Source |
|---|---|
| Title (docs) / Name (folders) | From the row |
| Library name | ”My Documents” for the personal library, the org library name otherwise |
| Snippet (~120 chars) | Computed client-side from the document content, centered on the match |
| Doc-type icon | Markdown / SVG / table / etc. — folders use the folder icon |
| Updated time | For documents |
Snippets are computed client-side because supabase-js doesn’t expose Postgres’s native ts_headline snippet function. The 120-char window is a fixed slice around the first match in the content.
Performance details
- Queries are debounced by 250 ms — typing fast doesn’t fire a request per keystroke
- Results are capped at a fixed row limit so the response stays fast
- Soft-deleted rows (in the Recycling Bin) are excluded — the search only sees live documents
What’s not in v1
| Missing | Notes |
|---|---|
Filters in the query syntax (e.g., in:Recipes, is:pinned) | Not parsed in v1 — use the sidebar’s folder tree for scoping |
| Search inside comments | Comments have their own panel and aren’t indexed |
| Search inside images (OCR) | Not in v1 |
| Search inside file attachments | Not in v1 |
| Saved searches | Not in v1 |
| Result-quality controls (e.g., “match in title only”) | Not in v1 |
| Search inside the recycling bin | Excluded — restore first, then search |
Permissions and search
Search results respect the same RLS policies as everything else in sweetdocs. The query runs as your user; the database filters out rows you can’t read. There’s no separate “search permission” — if you can open the doc, search can find it; if you can’t, it doesn’t.