feat: backend-powered search (full-text, semantic, hybrid) #14

Closed
opened 2026-03-14 22:17:54 +00:00 by forgejo_admin · 0 comments

Lineage

plan-pal-e-docs → Phase F1 (phase-pal-e-docs-frontend-search)

Repo

forgejo_admin/pal-e-app

User Story

As a platform operator
I want to search all pal-e-docs notes by content from the browser
So that I can find SOPs, phases, and conventions without relying on MCP tools or client-side title filtering

Context

The pal-e-docs backend has a full search API (GET /notes/search) supporting three modes:

  • keyword: PostgreSQL tsvector full-text search with ts_headline() snippets
  • semantic: pgvector cosine distance via Ollama embeddings
  • hybrid: Reciprocal Rank Fusion (RRF) of both

All three modes are tested and deployed. The frontend currently only has client-side title/slug filtering on /notes. This issue exposes the backend search through a dedicated /search route.

The API response shape is:

[{
  "slug": "plan-pal-e-docs",
  "title": "Interactive Knowledge Platform",
  "note_type": "plan",
  "status": "active",
  "project": "pal-e-docs",
  "headline": "**plan** for the **knowledge** platform...",
  "rank": 3.14
}]

Query params: q (required), mode (keyword|semantic|hybrid, default keyword), alpha (0-1 hybrid weight), note_type, project, limit (1-100, default 10).

File Targets

Files to create:

  • src/routes/search/+page.svelte — search results page
  • src/routes/search/+page.server.ts — server-side search call

Files to modify:

  • src/lib/api.ts — add searchNotes() function
  • src/routes/+layout.svelte — add search input to nav bar + Cmd+K keyboard shortcut

Files NOT to touch:

  • src/lib/components/blocks/ — block renderers are unrelated
  • src/routes/boards/ — board pages are separate scope

Acceptance Criteria

  • When I navigate to /search?q=deploy+recovery, then I see ranked search results with headline snippets
  • When I type in the nav bar search input and press Enter, then I am navigated to /search?q=myquery
  • When I press / or Cmd+K anywhere, then the search input in the nav bar is focused
  • When I toggle between keyword/semantic/hybrid modes, then results update and the mode is persisted in the URL
  • When I search with semantic mode, then a loading indicator shows during the Ollama embedding latency
  • When results are empty, then I see helpful search tips
  • When I click a search result, then I navigate to the note detail page (/notes/{slug})
  • Each result shows note_type badge with the correct color from typeColor() and project name if available

Test Expectations

  • Manual test: search for "deploy recovery" in hybrid mode, verify results appear with snippets
  • Manual test: verify Cmd+K focuses search, / focuses search
  • Manual test: verify URL persistence — reload page with ?q=test&mode=semantic and see same results
  • Manual test: verify note_type badges use correct colors from colors.ts

Constraints

  • Match existing dark theme: #0a0a14 background, #e94560 accent, gray-300 text
  • Use typeColor() from src/lib/colors.ts for note_type badges — do NOT duplicate color mappings
  • All API calls must go through server-side +page.server.ts (not client-side fetch) — match existing pattern
  • Search input in nav should not interfere with existing nav links layout
  • headline field from API contains **word** bold markers (from ts_headline) — render as <strong> tags
  • Default search mode should be hybrid for best results
  • Sanitize any HTML in results using DOMPurify (already a dependency)

Checklist

  • PR opened with Closes #1
  • No unrelated changes
  • Dark theme consistent with existing pages
  • Keyboard shortcuts don't conflict with browser defaults
  • phase-pal-e-docs-frontend-search — plan phase in pal-e-docs
  • plan-pal-e-docs — parent plan
### Lineage `plan-pal-e-docs` → Phase F1 (`phase-pal-e-docs-frontend-search`) ### Repo `forgejo_admin/pal-e-app` ### User Story As a platform operator I want to search all pal-e-docs notes by content from the browser So that I can find SOPs, phases, and conventions without relying on MCP tools or client-side title filtering ### Context The pal-e-docs backend has a full search API (`GET /notes/search`) supporting three modes: - **keyword**: PostgreSQL tsvector full-text search with `ts_headline()` snippets - **semantic**: pgvector cosine distance via Ollama embeddings - **hybrid**: Reciprocal Rank Fusion (RRF) of both All three modes are tested and deployed. The frontend currently only has client-side title/slug filtering on `/notes`. This issue exposes the backend search through a dedicated `/search` route. The API response shape is: ```json [{ "slug": "plan-pal-e-docs", "title": "Interactive Knowledge Platform", "note_type": "plan", "status": "active", "project": "pal-e-docs", "headline": "**plan** for the **knowledge** platform...", "rank": 3.14 }] ``` Query params: `q` (required), `mode` (keyword|semantic|hybrid, default keyword), `alpha` (0-1 hybrid weight), `note_type`, `project`, `limit` (1-100, default 10). ### File Targets Files to create: - `src/routes/search/+page.svelte` — search results page - `src/routes/search/+page.server.ts` — server-side search call Files to modify: - `src/lib/api.ts` — add `searchNotes()` function - `src/routes/+layout.svelte` — add search input to nav bar + Cmd+K keyboard shortcut Files NOT to touch: - `src/lib/components/blocks/` — block renderers are unrelated - `src/routes/boards/` — board pages are separate scope ### Acceptance Criteria - [ ] When I navigate to `/search?q=deploy+recovery`, then I see ranked search results with headline snippets - [ ] When I type in the nav bar search input and press Enter, then I am navigated to `/search?q=myquery` - [ ] When I press `/` or `Cmd+K` anywhere, then the search input in the nav bar is focused - [ ] When I toggle between keyword/semantic/hybrid modes, then results update and the mode is persisted in the URL - [ ] When I search with semantic mode, then a loading indicator shows during the Ollama embedding latency - [ ] When results are empty, then I see helpful search tips - [ ] When I click a search result, then I navigate to the note detail page (`/notes/{slug}`) - [ ] Each result shows note_type badge with the correct color from `typeColor()` and project name if available ### Test Expectations - [ ] Manual test: search for "deploy recovery" in hybrid mode, verify results appear with snippets - [ ] Manual test: verify Cmd+K focuses search, / focuses search - [ ] Manual test: verify URL persistence — reload page with `?q=test&mode=semantic` and see same results - [ ] Manual test: verify note_type badges use correct colors from colors.ts ### Constraints - Match existing dark theme: `#0a0a14` background, `#e94560` accent, `gray-300` text - Use `typeColor()` from `src/lib/colors.ts` for note_type badges — do NOT duplicate color mappings - All API calls must go through server-side `+page.server.ts` (not client-side fetch) — match existing pattern - Search input in nav should not interfere with existing nav links layout - `headline` field from API contains `**word**` bold markers (from ts_headline) — render as `<strong>` tags - Default search mode should be `hybrid` for best results - Sanitize any HTML in results using DOMPurify (already a dependency) ### Checklist - [ ] PR opened with `Closes #1` - [ ] No unrelated changes - [ ] Dark theme consistent with existing pages - [ ] Keyboard shortcuts don't conflict with browser defaults ### Related - `phase-pal-e-docs-frontend-search` — plan phase in pal-e-docs - `plan-pal-e-docs` — parent plan
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/pal-e-docs-app#14
No description provided.