Search

How full-text search works in WitWiki — from the Wiki list page in the web UI through the REST API to PostgreSQL.

Search matches page title and markdown body (everything stored in wiki_pages). It does not match path segments alone (e.g. searching only product may miss pages whose title and body never contain that word). Paths still appear in results for navigation.

Web UI (/wiki)

The wiki index uses a search field above the page list. Your input is debounced (about 300 ms) so each keystroke does not hit the network.

InputHTTP callResult
EmptyGET /api/pages?limit=100Recently updated pages, newest first
Non-emptyGET /api/search?q=…&limit=100Full-text hits, ranked

The browser sends the same Authorization: Bearer token as the rest of the app (NEXT_PUBLIC_WITWIKI_API_KEY in local dev).

REST API

  • List / browse: GET /api/pages?limit=… — optional prefix= filters by path prefix; no full-text query.
  • Search: GET /api/search?q=…&limit=…q is required; empty q returns 400.

Responses are JSON: { "pages": [ { "path", "title", "updated_at" }, … ] }.

Default limit is 100; the server caps at 500.

Database (PostgreSQL)

Each row in wiki_pages has a generated tsvector column (fts) built from English text of title + content. Search uses:

  • websearch_to_tsquery('english', $1) — web-style query syntax (phrases, etc., per PostgreSQL).
  • fts @@ … — match predicate.
  • ts_rank_cd(fts, …) — relevance ordering, then updated_at DESC as a tie-break.

So this is full-text search, not a simple SQL LIKE on path.

MCP (agents)

Agents use wiki_listPages with optional q for the same full-text behavior as /api/search. Optional prefix narrows by path prefix; limit follows the same cap.

  • architecture — where HTTP and MCP attach to the same wiki service
  • development — env vars and local URLs
  • mcp-tools — tool reference

← index