# How to Add a Knowledge Base to Your App (Copy-Paste Prompts Included)

- Tool: App Features
- Last updated: July 2026

## TL;DR

A knowledge base needs four pieces: a rich text editor (Tiptap) for writing articles, a PostgreSQL full-text search index (tsvector) so readers find answers as they type, a category taxonomy for navigation, and a feedback widget to surface low-quality content. With Lovable or V0 you can ship a working help center in 2–4 days for $0–$25/month — Supabase handles both storage and search, so no paid search service is required at launch.

## What a Knowledge Base Feature Actually Is

A knowledge base is a searchable repository of articles that answers user questions before they become support tickets. A SaaS app ships a help center where customers find setup guides and error explanations. An internal tool team builds a wiki where contributors document processes. An e-commerce app hosts a returns FAQ. The reading experience is the same across all three: full-text search with instant results, a hierarchical category sidebar for browsing, and readable typography that renders images and code blocks correctly. The writing experience — the admin side — is what differentiates a proper knowledge base from a blog: draft/publish workflow, last-updated timestamps, and reader feedback that tells editors which articles need work.

## Anatomy of the Feature

Six components — the search input and article viewer are where readers spend all their time, so they need the most attention. The admin editor and feedback widget are lower-traffic but define content quality over time.

- **Search input + results dropdown** (ui): A React component using shadcn/ui Combobox that sends a debounced query to Supabase full-text search (to_tsvector / plainto_tsquery on PostgreSQL). Results appear as a dropdown list of article titles with a highlighted matching excerpt.
- **Article editor (admin)** (ui): Rich text editor using Tiptap (open-source, extensible) for the admin panel. Tiptap outputs clean JSON that stores in Supabase and converts to HTML for rendering. Code blocks use the lowlight extension for syntax highlighting. BlockNote is an alternative with a Notion-style block UI.
- **Article viewer** (ui): Renders stored HTML or Markdown with react-markdown + remark-gfm (GitHub Flavored Markdown: tables, strikethrough) + rehype-highlight for code syntax. Table of contents extracted from headings using remark-toc and rendered as a sticky sidebar on desktop.
- **Category + tag taxonomy** (data): Supabase tables: categories(id, name, slug, parent_id, sort_order) enabling nested categories, and an article_tags join table for cross-category labeling. The parent_id self-reference enables a tree structure for the sidebar.
- **Full-text search index** (backend): A tsvector column on the articles table, populated by a PostgreSQL trigger on INSERT and UPDATE. A GIN index on the tsvector column makes full-text queries run in milliseconds regardless of article count.
- **Feedback widget** (ui): Thumbs up/down buttons plus an optional free-text comment field at the bottom of every article. Responses are collected via a Supabase insert into article_feedback. A Supabase query surfaces articles sorted by lowest rating to the admin dashboard for review.

## Data model

Three tables cover articles, categories, and reader feedback. The tsvector column with its trigger is the piece most likely to be missing from an AI-generated schema. Run this in the Supabase SQL editor:

```sql
create table public.categories (
  id uuid primary key default gen_random_uuid(),
  name text not null,
  slug text not null unique,
  parent_id uuid references public.categories(id) on delete set null,
  sort_order int not null default 0
);

create table public.articles (
  id uuid primary key default gen_random_uuid(),
  category_id uuid references public.categories(id) on delete set null,
  title text not null,
  slug text not null unique,
  body_html text not null default '',
  body_search tsvector generated always as (
    to_tsvector('english', coalesce(title, '') || ' ' || coalesce(body_html, ''))
  ) stored,
  is_published boolean not null default false,
  views int not null default 0,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

create index articles_search_gin_idx
  on public.articles using gin(body_search);

create index articles_category_views_idx
  on public.articles (category_id, views desc);

create table public.article_feedback (
  id uuid primary key default gen_random_uuid(),
  article_id uuid references public.articles(id) on delete cascade not null,
  rating int not null check (rating in (1, -1)),
  comment text,
  created_at timestamptz not null default now()
);

alter table public.articles enable row level security;
alter table public.categories enable row level security;
alter table public.article_feedback enable row level security;

create policy "Public can read published articles"
  on public.articles for select
  using (is_published = true);

create policy "Admins can manage articles"
  on public.articles for all
  using (auth.jwt() ->> 'role' = 'admin');

create policy "Public can read categories"
  on public.categories for select
  using (true);

create policy "Anyone can submit feedback"
  on public.article_feedback for insert
  with check (true);
```

The body_search column uses a GENERATED ALWAYS AS expression so the tsvector stays in sync automatically on every INSERT and UPDATE — no trigger required. The GIN index on body_search makes full-text queries run in under 10ms for a library of thousands of articles. Query it with: `WHERE body_search @@ plainto_tsquery('english', $1)`.

## Build paths

### Lovable — fit 4/10, 2–4 days

Lovable's Supabase integration handles the full-text search setup and admin auth automatically. Good for a self-contained help center with a simple admin panel. Works on web and mobile-responsive.

1. Create a new Lovable project and connect Lovable Cloud to auto-provision Supabase
2. Run the SQL schema from this page in the Supabase SQL editor to create articles, categories, and feedback tables with the GIN index
3. Paste the prompt below into Agent Mode — it builds the reader-facing search and article viewer, the admin editor, and the feedback widget
4. Open the Cloud tab → Users & Auth to configure admin role logic so only designated users can publish articles
5. Publish and test the search by typing partial words — if results don't appear, verify the body_search column and GIN index exist in the Supabase Dashboard

Starter prompt:

```
Build a knowledge base app with two modes: public reader view and authenticated admin view. Reader view: a search bar at the top using Supabase full-text search on an 'articles' table (query field: body_search, using plainto_tsquery) with results appearing as the user types after 300ms debounce; a category sidebar showing nested categories from a 'categories' table with parent_id tree structure; an article page that renders body_html content with react-markdown, shows the category breadcrumb path above the title, displays the updated_at timestamp, and renders a 'Was this helpful? Yes / No' feedback widget at the bottom that inserts into article_feedback; a related articles section below the feedback widget showing 3 articles from the same category sorted by views DESC. Admin view (requires auth): an article list with draft/published status toggle; an article editor using Tiptap with StarterKit plus CodeBlock with lowlight syntax highlighting; category management (create, rename, reorder); a low-rated articles dashboard sorted by rating ascending. Handle the empty search results state with the message 'No articles found — try different keywords' and a link to contact support.
```

Limitations:

- Lovable may default to a plain textarea for the admin editor — explicitly ask for Tiptap in the prompt and verify the code includes it after generation
- Next.js ISR for fast public article pages is not available in Lovable (Vite/React); all article content fetches on the client on each visit
- Rich text stored as Tiptap JSON requires generateHTML() on render — if Lovable stores it as a string and renders it raw, it will display as JSON text

### V0 — fit 4/10, 2–4 days

V0 produces polished article layouts with shadcn/ui Typography and sidebar navigation. Ideal for teams embedding a docs-style knowledge base into an existing Next.js app. ISR makes public article pages load instantly.

1. Prompt V0 with the spec below to generate the reader layout, search component, and admin editor pages
2. Add Supabase environment variables in the V0 Vars panel: NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY
3. Run the SQL schema from this page in the Supabase SQL editor — V0 will not provision the tsvector index automatically
4. In the article page route, add `export const revalidate = 3600` for ISR so article content is cached at the CDN edge and serves instantly for public readers
5. Connect to GitHub via the V0 Git panel and merge the generated branch to deploy to Vercel

Starter prompt:

```
Build a Next.js knowledge base with two sections: public reader and admin. Public reader: a /kb route with a search input that queries Supabase articles via full-text search (WHERE body_search @@ plainto_tsquery('english', searchTerm)), debounced 300ms, showing results as a dropdown with article title and category; a /kb/[category]/[slug] article route with ISR (revalidate 3600) rendering article body_html with react-markdown + remark-gfm + rehype-highlight, showing the breadcrumb (category name > article title), the updated_at date formatted as 'Last updated Jan 15, 2026', a sticky table-of-contents sidebar on desktop extracted from article headings, and a 'Was this helpful?' feedback widget using shadcn/ui thumbs-up/down buttons that inserts into article_feedback; a related articles section showing 3 cards from the same category sorted by views. Admin (/admin/kb, require auth): article list with is_published toggle; article editor with Tiptap (StarterKit + CodeBlockLowlight); category tree sidebar with add/rename. Handle empty search state and empty category state.
```

Limitations:

- V0 will not provision the Supabase tsvector GIN index — run the SQL schema manually in the Supabase SQL editor before testing search
- Full-text search wiring (using body_search @@ plainto_tsquery rather than LIKE) needs explicit prompt instruction; V0 defaults to LIKE if not specified
- Algolia integration for typo-tolerant search requires additional manual setup beyond what V0 generates

### Flutterflow — fit 2/10, 3–5 days

FlutterFlow can render article lists and content for a mobile companion reader, but rich text display with code blocks and nested lists is limited. Use only for a read-only mobile KB viewer, not for the admin editor.

1. Build the article list screen with a Supabase query on the articles table filtered by is_published = true; display title, category name, and updated_at
2. Use a WebView widget to render article body_html — this is the only practical way to display rich HTML including images and code blocks in FlutterFlow
3. Add a search TextField that filters the article list using a Supabase query with an ilike filter on the title column (full-text search via tsvector is not natively accessible in FlutterFlow without a custom action)
4. Add a feedback widget (thumbs up/down) that inserts into article_feedback via a Supabase Insert action

Limitations:

- No native Markdown or HTML renderer — WebView is the workaround but it creates a nested scroll conflict on iOS
- Full-text tsvector search requires a custom Dart action; the visual action editor only supports basic column filters
- Admin article editing is not feasible in FlutterFlow without significant custom Dart code for the rich text editor

### Custom — fit 5/10, 1–2 weeks

Full control over Tiptap editor versioning, pgvector semantic search, role-based edit permissions, and ISR for public SEO. Required if the KB serves as a public-facing SEO hub where page speed and indexability directly affect traffic.

1. Next.js App Router with generateStaticParams for top articles (SSG) and revalidate for the long tail (ISR) — article pages load from CDN in under 100ms
2. pgvector semantic search as a complement to tsvector keyword search — handles queries like 'how do I connect my account' even when the article says 'linking your profile'
3. Tiptap editor with versioning stored as a jsonb history array — editors can review and restore previous article versions
4. Role-based access: team members can edit their department's articles only, enforced via a Supabase RLS policy on category_id joined to a user_permissions table

Limitations:

- pgvector semantic search requires OpenAI embeddings API or a self-hosted model — adds API cost per article indexed and per search query
- Content migration from an existing help center (Zendesk, Intercom) adds 1–3 days of import scripting to the timeline

## Gotchas

- **Full-text search returns no results even when articles contain the search term** — The most common AI-generated search bug: the code uses a LIKE query ('%searchTerm%') instead of the tsvector full-text operator, or the body_search column was never created. LIKE scans every row without an index, returns results only for exact substring matches, and misses stemming (searching 'connecting' won't match 'connect'). Fix: In the Supabase SQL editor, verify that the body_search column exists and contains data. In your query code, replace `LIKE '%term%'` with `body_search @@ plainto_tsquery('english', searchTerm)`. If the column is missing, run the data model SQL from this page to add it — it uses a GENERATED ALWAYS AS expression, so it backfills automatically.
- **Rich text content displays as raw HTML tags or JSON in the article viewer** — Tiptap stores content as a JSON document object, not as HTML. If the viewer renders it as a plain string (e.g., using a <p> tag with the content as children), the user sees raw JSON. If the content was stored as HTML but the viewer wraps it in dangerouslySetInnerHTML incorrectly, it displays as visible tag characters. Fix: If content is Tiptap JSON: use Tiptap's `generateHTML(content, extensions)` utility to convert it to HTML before rendering, or add a Tiptap read-only editor component. If content is HTML: use `dangerouslySetInnerHTML={{ __html: bodyHtml }}` — the function name is a security warning, not a bug, and is the correct approach for trusted admin-generated content.
- **Category tree causes a recursive database query error** — The categories table has a self-referential parent_id column. AI-generated code commonly constructs nested category trees with multiple sequential JOINs or recursive JavaScript fetching — resulting in either an infinite loop or N+1 database calls that make the sidebar take 3–10 seconds to load. Fix: Use a PostgreSQL WITH RECURSIVE CTE to fetch the full category tree in a single query: `WITH RECURSIVE cat_tree AS (SELECT * FROM categories WHERE parent_id IS NULL UNION ALL SELECT c.* FROM categories c JOIN cat_tree p ON c.parent_id = p.id) SELECT * FROM cat_tree`. Limit depth to 3 levels with a depth counter in the CTE to prevent runaway recursion.
- **Article pages are slow — 2–4 second loads — for public readers** — Lovable and V0 default to client-side data fetching: the article page mounts, then fetches content from Supabase on the client, causing a blank flash followed by the content appearing. This is perceptible as slow and hurts SEO crawlability. Fix: For Next.js (V0 path): add `export const revalidate = 3600` to the article route file. This enables ISR — the first visitor triggers a server render and the result is cached at Vercel's edge CDN for 1 hour. Subsequent readers get sub-100ms responses. For Lovable (Vite/React), pre-fetch article content in a useEffect with a loading skeleton to reduce perceived latency.

## Best practices

- Name article slugs after the user's question, not the topic: 'how-to-connect-stripe' performs better in both search and SEO than 'stripe-integration'
- Enable the body_search GENERATED ALWAYS AS column — it eliminates the need for a trigger and stays in sync automatically on every insert and update
- Gate the correct_answer and admin fields behind RLS from day one — public SELECT on articles should only read published articles, not drafts
- Surface the low-rated articles dashboard to your content team in the first week — feedback data is only useful if someone acts on it regularly
- Add a view counter increment on article read (a simple Supabase RPC that increments the views column) and use it to sort related articles — views are a stronger signal than recency
- Set up an article age alert: flag articles older than 6 months for review in the admin dashboard so outdated content doesn't accumulate
- For public-facing knowledge bases, add Open Graph meta tags to article pages (og:title, og:description) so shared article links render correctly in Slack and social media

## Frequently asked questions

### What's the difference between a knowledge base and a blog?

A blog is organized chronologically and written for discovery — readers browse by date or topic. A knowledge base is organized by user intent and written for retrieval — readers arrive with a specific question and use search or category navigation to find the answer. The article structure, navigation, and search design are all optimized for 'I have a problem' rather than 'I want to read something.'

### Can I build a searchable help center in Lovable?

Yes. Lovable's Supabase integration auto-provisions the database, and the tsvector full-text search works as long as you run the schema SQL to create the body_search column and GIN index. The main gap is the rich text editor — Lovable may generate a plain textarea by default. Explicitly ask for Tiptap with CodeBlock support in your prompt.

### How do I add full-text search to a Supabase-backed app?

Add a tsvector generated column to your articles table: `body_search tsvector generated always as (to_tsvector('english', title || ' ' || body_html)) stored`. Then add a GIN index on it. In your query, filter with `WHERE body_search @@ plainto_tsquery('english', $1)`. Supabase's PostgREST exposes this via `textSearch` in the client library.

### What rich text editor works best with Lovable or V0?

Tiptap is the best match for both. It's open-source, outputs clean JSON or HTML, integrates with React as a headless component, and supports code blocks (via lowlight), images, and custom extensions. Name it explicitly in your prompt — both Lovable and V0 default to a basic textarea or a simpler editor if you don't specify.

### How do I structure categories in a knowledge base?

A self-referential categories table with a parent_id column supports nested categories. In practice, three levels (Category > Subcategory > Article) is the maximum useful depth — readers get lost deeper than that. Fetch the full tree in one query using a PostgreSQL WITH RECURSIVE CTE rather than multiple round-trip fetches.

### Can readers give feedback on articles?

Yes, and it's one of the highest-value features to include from day one. A thumbs up/down widget inserts a row into an article_feedback table with the article_id and a rating value (1 or -1). In the admin panel, sort articles by average rating ascending to surface the ones that need rewriting. Keep free-text comments optional — required comment fields suppress feedback volume significantly.

### Do I need Algolia or is Supabase search enough?

Supabase PostgreSQL full-text search is sufficient for most knowledge bases, especially those under 10K articles. It handles stemming (connecting matches connect), ranking, and multi-column search with no additional cost or service. Algolia adds typo tolerance (gogle matches google) and faceted filtering — upgrade when users complain about missing results from small typos, which typically happens after significant search volume.

### How much does it cost to host a knowledge base at 10,000 users?

Supabase Pro at $25/month covers the database and search for most knowledge bases up to 10K readers. If search volume is high (thousands of searches per hour), Algolia's pay-as-you-go tier adds roughly $25–75/month. Article image CDN via Cloudinary adds $0–50/month depending on image count and traffic. Total: $50–150/month at 10K users.

---

Source: https://www.rapidevelopers.com/app-features/knowledge-base
© RapidDev — https://www.rapidevelopers.com/app-features/knowledge-base
