Three different surfaces let users and authors search the Knowledge Base. They all hit the same backend endpoint and apply the same MySQL FULLTEXT ranking — only the UI differs.
The three search entry points
| Surface | Where | Returns |
|---|---|---|
| Public reader hub | Search bar at the top of / | Up to 50 articles, ranked by relevance, opening at /a/<slug>. |
| Chat-widget Help tab | Search input at the top of the widget — see The chat-widget Help tab. | Up to 50 articles, opened inside the widget without leaving the chat. |
| Agent / API | GET /api/kb/search?q=<query> (no auth) | JSON array of { id, slug, title }, sorted by FTS rank. |
All three call the same searchPublished() query helper that runs:
SELECT id, slug, title FROM kb_article
WHERE status = 'PUBLISHED'
AND MATCH(title, body_html) AGAINST (? IN NATURAL LANGUAGE MODE)
ORDER BY MATCH(title, body_html) AGAINST (? IN NATURAL LANGUAGE MODE) DESC
LIMIT 50
What's indexed
The FULLTEXT index sits on kb_article(title, body_html). Both fields contribute to the score:
title— the article's headline. A query that matches the title scores higher than the same query matching only the body.body_html— the rendered article body, after sanitisation. Tags themselves don't match —<strong>is invisible to the index — but the text inside them is.
What's not indexed by search
- The
keywordsfield. It feeds the Related articles panel, not the search index. - Drafts and archived articles. Only
status = 'PUBLISHED'rows are searchable. See Article statuses field definitions. - Folder names. The folder tree is browsed, not searched.
- Image alt text inside
<img>attributes. The text doesn't reach the index because the FULLTEXT parser indexes word tokens between markup, not attribute values.
How natural-language ranking works
MySQL's FULLTEXT in IN NATURAL LANGUAGE MODE ignores stop-words (the, is, of, …), splits on word boundaries, and scores each row by how many query terms appear, weighted by inverse document frequency (rare terms count more). Two practical implications:
- Single-word queries find the most general match. Searching
dashboardreturns every article that mentions the word — usually the article literally titled "The Dashboard" comes first because the term is in its title. - Multi-word queries narrow.
dashboard attendanceranks higher articles that contain both terms close together than articles that have only one.
MySQL's default minimum word length is 3 characters (innodb_ft_min_token_size = 3). Words shorter than 3 characters are silently ignored — searching pdf finds nothing because pdf is exactly 3 characters but dt would be ignored.
Tips for getting good search results
- Search for nouns, not verbs. "clock in" finds the right article; "how do I clock in" finds the same article plus every article that uses the word "how".
- Use distinctive words. A query like "setup" or "manage" matches almost everything. "folder rename" or "dead letter" are far more selective.
- Quotes are not phrase-matching. Natural-language mode treats quotes as ordinary characters. If you need exact-phrase matching, the API endpoint can be enhanced to support
BOOLEAN MODE— open an issue. - Try synonyms. The index doesn't expand to synonyms. "login" and "sign-in" each find their own subset.
Searching from the agent / a script
curl -s 'https://mydoc24.org/api/kb/search?q=dashboard%20attendance' | jq
Returns:
[
{ "id": 2, "slug": "the-dashboard", "title": "The Dashboard" },
{ "id": 4, "slug": "attendance-status-field-definitions", "title": "Attendance status field definitions" },
{ "id": 3, "slug": "clock-in-and-out-remotely", "title": "Clock in and out remotely" }
]
No X-API-Key header needed — search is a public read endpoint with Access-Control-Allow-Origin: *.
Use this from a script when you want to dedupe before importing — search for an existing slug or title before calling the import endpoint, so you upsert rather than create duplicates.
Search vs related articles
Different jobs:
| Tool | Initiated by | Returns |
|---|---|---|
| Search | The user, with an explicit query. | Articles whose title + body match the query. |
| Related | The system, automatically per article. | Other articles in the same folder cluster whose title + body match the current article's keywords + headings. |
The two share infrastructure (FULLTEXT, MATCH AGAINST) but differ in who supplies the query. The keywords field is therefore important for discoverability via the Related panel — see The Editor — but it doesn't help raw search.
Related
- The Knowledge Base — the three reader surfaces.
- The chat-widget Help tab — the widget search.
- The Editor — where keywords are set.
- Article statuses field definitions — visibility rules that affect search.