Context
A public knowledge base reduces ticket volume by letting users self-serve common questions (e.g., "How do I import parcels from RVO?"). Agents can also link KB articles when replying to tickets, ensuring consistent answers.
Depends on: #599 (MVP — support routes and layout must exist)
Scope
In Scope
- Schema:
kb_articles table (title, slug, body as Markdown, category, is_published, view_count, author_id)
- Article CRUD: create, update, publish/unpublish, delete (soft)
- Categories: grouping articles by topic (percelen, bemesting, account, etc.)
- Full-text search:
pg_trgm fuzzy matching on title + body with GIN indexes
- Public browse UI (
/support/kb): categorized article list with search
- Article view (
/support/kb/$article_id): rendered Markdown with feedback widget
- Article feedback: "Was dit artikel nuttig?" thumbs up/down (stored per article)
- Agent KB editor (
/admin/support/kb): create/edit articles with Markdown preview
- Link articles in replies: agent can reference KB article in a ticket reply
- View count tracking: increment on each unique view
Acceptance Criteria
Technical Implementation
1. Schema
export const kbArticles = fdmHelpdeskSchema.table(
"kb_articles",
{
article_id: text().primaryKey(),
slug: text().notNull().unique(),
title: text().notNull(),
body: text().notNull(), // Markdown content
category: text().notNull().default("general"),
is_published: boolean().notNull().default(false),
author_id: text().notNull(), // Agent who created it
view_count: integer().notNull().default(0),
created: timestamp({ withTimezone: true }).notNull().defaultNow(),
updated: timestamp({ withTimezone: true }),
},
(table) => [
index("kb_category_idx").on(table.category),
index("kb_published_idx").on(table.is_published),
// GIN trigram indexes for fuzzy search
index("kb_title_trgm_idx").using("gin", sql`${table.title} gin_trgm_ops`),
index("kb_body_trgm_idx").using("gin", sql`${table.body} gin_trgm_ops`),
],
)
2. Search Function
export async function searchArticles(fdm: FdmType, query: string, limit = 10) {
return fdm.select().from(kbArticles)
.where(and(
eq(kbArticles.is_published, true),
or(
sql`${kbArticles.title} % ${query}`,
sql`${kbArticles.body} % ${query}`,
),
))
.orderBy(sql`similarity(${kbArticles.title}, ${query}) DESC`)
.limit(limit)
}
3. App Routes
| Route |
Purpose |
support.kb.tsx |
KB listing with categories and search |
support.kb.$slug.tsx |
Article view (rendered Markdown + feedback) |
admin.support.kb.tsx |
KB article list (published/draft) |
admin.support.kb.new.tsx |
Create article (Markdown editor) |
admin.support.kb.$slug.edit.tsx |
Edit article |
4. UI — Public KB (/support/kb)
┌────────────────────────────────────────────────────────────┐
│ Kennisbank 🔍 Zoek in artikelen... │
├────────────────────────────────────────────────────────────┤
│ │
│ Veelgestelde vragen │
│ ├── 📄 Hoe importeer ik percelen via de RVO-koppeling? │
│ ├── 📄 Hoe werkt het bemestingsadvies? │
│ └── 📄 Kan ik mijn bedrijf delen met een adviseur? │
│ │
│ Account & inloggen │
│ ├── 📄 Hoe wijzig ik mijn wachtwoord? │
│ └── 📄 Ik kan niet inloggen │
│ │
│ ── Article view ── │
│ [Rendered Markdown content] │
│ │
│ Was dit artikel nuttig? [👍 Ja] [👎 Nee] │
└────────────────────────────────────────────────────────────┘
5. UI — Agent Editor (/admin/support/kb)
┌────────────────────────────────────────────────────────────┐
│ Kennisbank beheer [+ Nieuw artikel] │
├────────────────────────────────────────────────────────────┤
│ │
│ Titel [Hoe importeer ik percelen via de RVO-koppeling?] │
│ Slug [hoe-importeer-ik-percelen-rvo ] │
│ Categorie [Veelgestelde vragen ▾] │
│ │
│ ┌─ Editor (Markdown) ──────┐ ┌─ Preview ─────────────┐ │
│ │ ## Stap 1: Ga naar... │ │ Stap 1: Ga naar... │ │
│ │ │ │ │ │
│ │ Klik op **RVO-koppeling**│ │ Klik op RVO-koppeling │ │
│ │ in het menu. │ │ in het menu. │ │
│ └──────────────────────────┘ └────────────────────────┘ │
│ │
│ [💾 Opslaan als concept] [🌐 Publiceren] │
└────────────────────────────────────────────────────────────┘
6. Dependencies
react-markdown (already in fdm-app)
remark-gfm (for GitHub-flavored Markdown: tables, strikethrough)
pg_trgm PostgreSQL extension (enable via migration)
7. Suggested Default Categories
| Category |
Description |
veelgesteld |
Veelgestelde vragen (FAQ) |
aan-de-slag |
Aan de slag / Getting started |
percelen |
Percelen & kaart |
bemesting |
Bemesting & advies |
account |
Account & inloggen |
Testing Requirements
- Integration tests: Create article → publish → verify visible in search → feedback
- Unit tests: Slug generation, Markdown rendering (no XSS), search query building
- Manual test: Search finds article with typo (trigram fuzzy), verify categories render
Definition of Done
Users can browse and search a knowledge base to find answers before creating a ticket. Agents can create and maintain articles in Markdown with a live preview.
Context
A public knowledge base reduces ticket volume by letting users self-serve common questions (e.g., "How do I import parcels from RVO?"). Agents can also link KB articles when replying to tickets, ensuring consistent answers.
Depends on: #599 (MVP — support routes and layout must exist)
Scope
In Scope
kb_articlestable (title, slug, body as Markdown, category, is_published, view_count, author_id)pg_trgmfuzzy matching on title + body with GIN indexes/support/kb): categorized article list with search/support/kb/$article_id): rendered Markdown with feedback widget/admin/support/kb): create/edit articles with Markdown previewAcceptance Criteria
/support/kbfor all authenticated userspg_trgmextension is enabled and GIN indexes are created via migrationTechnical Implementation
1. Schema
2. Search Function
3. App Routes
support.kb.tsxsupport.kb.$slug.tsxadmin.support.kb.tsxadmin.support.kb.new.tsxadmin.support.kb.$slug.edit.tsx4. UI — Public KB (
/support/kb)5. UI — Agent Editor (
/admin/support/kb)6. Dependencies
react-markdown(already in fdm-app)remark-gfm(for GitHub-flavored Markdown: tables, strikethrough)pg_trgmPostgreSQL extension (enable via migration)7. Suggested Default Categories
veelgesteldaan-de-slagpercelenbemestingaccountTesting Requirements
Definition of Done
Users can browse and search a knowledge base to find answers before creating a ticket. Agents can create and maintain articles in Markdown with a live preview.