feat(api): unified FTS search

Single GET /api/search?q=&space_id=&kinds=&limit=&offset= unions FTS
hits across pages / refs / source_docs / messages with a `kind`
discriminator and ts_rank ordering. Each branch's to_tsvector matches
the GIN index expression on its source table so indexes are used.
Messages have no space_id and are excluded when a space filter is set.
Hybrid vector / RRF lands in Plan 3.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
root
2026-06-01 02:04:57 +10:00
parent ec96e4e2e3
commit 69e26ada98
5 changed files with 289 additions and 0 deletions

View File

@@ -19,6 +19,7 @@ import { router as tagsRouter, entityScopedRouter as tagsByEntityRouter } from '
import { router as linksRouter } from './routes/links.js';
import { router as pendingChangesRouter } from './routes/pending_changes.js';
import { router as auditRouter } from './routes/audit.js';
import { router as searchRouter } from './routes/search.js';
export function mountApi(app) {
const api = Router();
@@ -45,6 +46,7 @@ export function mountApi(app) {
api.use('/links', linksRouter);
api.use('/pending-changes', pendingChangesRouter);
api.use('/audit', auditRouter);
api.use('/search', searchRouter);
api.use('/:entity_type/:entity_id/tags', tagsByEntityRouter);
api.use((_req, _res, next) => next(new NotFoundError('route not found')));