ROADMAP: PATTTTERNS Chatbot (MCP-backed)

Status: 🟠 In Progress
Updated: April 2026


Goal

A design pattern assistant embedded on docs.patttterns.com and optionally on patttterns.com itself. The chatbot uses the existing /mcp endpoint as its backend — no new AI infrastructure, no third-party training on private data.


Architecture

User types question
  → Chatbot widget (browser JS)
    → POST /mcp  (tools/call → search_patterns)
      → search-index.json (static, ~instant)
        → returns matching patterns + URLs
          → widget formats + renders reply

No LLM required for basic search mode. Optionally pipe results through an LLM for natural language answers.


Phases

Phase 1 — Embedded Search Widget (No LLM)

What it does: Accepts a text query, calls search_patterns via MCP, renders results as cards with title + description + link.

Files to create:

  • docs/assets/js/chatbot.js — widget logic (vanilla JS, no deps)
  • docs/assets/css/chatbot.scss — widget styles matching brand
  • docs/_includes/head_custom.html — injects script + styles

MCP call pattern:

const res = await fetch('https://patttterns.com/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'tools/call',
    params: {
      name: 'search_patterns',
      arguments: { query: userInput, limit: 5 }
    }
  })
});

UI: Floating button (bottom-right), slide-up panel, input + results list. PATTTTERNS blue #0267FF accent.

Effort: ~1 day
Dependencies: /mcp endpoint live (✅ done)


Phase 2 — Natural Language Mode (LLM layer) ✅ Implemented

What it does: Takes search results from Phase 1, sends them + the user question to Gemini Flash 1.5, returns a streamed synthesized answer with rich pattern cards (cover image + description + link).

Provider: Google Gemini 1.5 Flash — fast, cost-efficient, streaming via SSE.

Architecture:

User query
  → chatbot.js: POST /mcp (search_patterns, limit 8)
    → returns patterns[] with title, description, url, coverImage
      → chatbot.js: POST /.netlify/functions/chatbot-proxy
          body: { query, patterns[] }
        → Gemini 1.5 Flash (server-side, API key never exposed)
          → streams back: { answer, citations[] }
            → widget renders: AI answer text + rich pattern cards

Feature flags (env vars): | Variable | Description | |—|—| | GEMINI_API_KEY | Google AI API key (required for Phase 2) | | ENABLE_AI_CHAT | Set to "true" to activate LLM mode. If absent/false, widget falls back to Phase 1 search-only mode |

Rich card rendering:

  • Cover image (from search-index.json — already present per pattern)
  • Pattern title + description
  • Clickable link to patttterns.com/...
  • AI-generated answer text above the cards with citations

Embed targets:

  • docs.patttterns.com — via docs/_includes/head_custom.html (Phase 1 already wired)
  • patttterns.com — via src/app/layout.tsx, lazy-loaded (Phase 3)

Files created/updated:

  • netlify/functions/chatbot-proxy.ts — Gemini proxy (serverless, streaming SSE)
  • netlify/edge-functions/mcp.ts — updated to include coverImage in search_patterns results
  • docs/assets/js/chatbot.js — AI mode: streaming answer + rich cover-image cards
  • docs/assets/css/chatbot.scss — cover image + AI answer styles

Effort: ~2 days
Dependencies: Phase 1 complete ✅, GEMINI_API_KEY + ENABLE_AI_CHAT=true as Netlify env vars


Phase 3 — Embed on patttterns.com

What it does: Same widget injected into the main site via src/app/layout.tsx.

Considerations:

  • Load lazily (only after interaction) to avoid LCP impact
  • Gate LLM calls to avoid abuse (rate limit by IP at the Netlify Function level)
  • Show only on pattern pages (/patterns/*, /ux-patterns/*)

Effort: ~0.5 days (reuse Phase 1/2 assets)


Phase 4 — MCP Resources (Pattern content)

What it does: Extend the /mcp endpoint to serve full pattern page content via resources/read, not just search index metadata.

Agents and the chatbot can then answer “what does the user-feedback pattern say?” with actual content, not just a URL.

Implementation: Edge function reads from /public/.notion-cache/{id}.json (already built by build:content).

Files to update:

  • netlify/edge-functions/mcp.ts — add resources/list and resources/read methods

Effort: ~1 day
Dependencies: .notion-cache populated (✅ exists)


Widget UX Design

┌─────────────────────────────────┐
│  Ask about design patterns…     │  ← input
├─────────────────────────────────┤
│  ● User Feedback                │
│    Ratings, scores or votes…    │
│    patttterns.com/ux-patterns/… │
│                                 │
│  ● Call to Action               │
│    Pricing, sign-up, paywalls…  │
│    patttterns.com/ux-patterns/… │
└─────────────────────────────────┘
  • Trigger: floating ? button, bottom-right, brand blue
  • Panel: 360px wide, slides up, search-first, no modal overlay
  • Results: max 5, each a clickable card
  • Keyboard: Escape closes, Enter submits, arrow keys navigate results
  • Empty state: “Try searching for ‘onboarding’, ‘checkout’, or ‘navigation’”

Decision Log

Decision Rationale
MCP backend over third-party (Kapa/Inkeep) No data leaves the site; consistent with agent readiness work
Vanilla JS widget No framework dependency; loads in docs and main site equally
Phase 1 first (no LLM) Instant value, zero ongoing cost, validates UX before adding AI cost
Netlify Function proxy for LLM API key stays server-side; rate limiting easier than edge
Extend MCP resources in Phase 4 Full content already cached; natural extension of existing architecture