rushchatbot 1.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/INTEGRATION.md +559 -0
  2. package/index.html +13 -0
  3. package/package/INTEGRATION.md +717 -0
  4. package/package/README.md +717 -0
  5. package/package/package-lock.json +3221 -0
  6. package/package/package.json +101 -0
  7. package/package/src/cli/index.ts +94 -0
  8. package/package/src/client/ChatWidget.tsx +163 -0
  9. package/package/src/client.ts +2 -0
  10. package/package/src/core/RushChatbot.ts +192 -0
  11. package/package/src/index.ts +5 -0
  12. package/package/src/server/guardrails.ts +107 -0
  13. package/package/src/server/index.ts +210 -0
  14. package/package/src/server/matcher.ts +140 -0
  15. package/package/src/shared/types.ts +58 -0
  16. package/package/src/shims-vue.d.ts +5 -0
  17. package/package/src/vanilla/index.ts +302 -0
  18. package/package/src/vanilla.ts +3 -0
  19. package/package/src/vue/ChatWidget.vue +198 -0
  20. package/package/src/vue.ts +3 -0
  21. package/package/src/vue2/ChatWidget.vue +204 -0
  22. package/package/src/vue2.ts +3 -0
  23. package/package/tsconfig.json +19 -0
  24. package/package/vite.config.ts +86 -0
  25. package/package.json +35 -0
  26. package/public/favicon.svg +1 -0
  27. package/public/icons.svg +24 -0
  28. package/server/data/analytics.json +795 -0
  29. package/server/data/chatbot.config.json +26 -0
  30. package/server/data/questions.json +238 -0
  31. package/server/data/questions.tl.json +182 -0
  32. package/server/index.ts +11 -0
  33. package/server/lib/guardrails.ts +107 -0
  34. package/server/lib/matcher.ts +140 -0
  35. package/server/routes/chat.ts +180 -0
  36. package/server/tsconfig.json +11 -0
  37. package/src/App.css +184 -0
  38. package/src/App.tsx +135 -0
  39. package/src/assets/hero.png +0 -0
  40. package/src/assets/react.svg +1 -0
  41. package/src/assets/vite.svg +1 -0
  42. package/src/components/ChatWidget.tsx +417 -0
  43. package/src/components/QuestionTree.tsx +57 -0
  44. package/src/hooks/useChatData.ts +49 -0
  45. package/src/index.css +111 -0
  46. package/src/main.tsx +10 -0
  47. package/src/types/index.ts +40 -0
  48. package/tsconfig.app.json +26 -0
  49. package/tsconfig.json +7 -0
  50. package/tsconfig.node.json +23 -0
  51. package/vite.config.ts +7 -0
@@ -0,0 +1,717 @@
1
+ # RushChatbot
2
+
3
+ **Version:** 1.6.7
4
+
5
+ Embeddable hybrid chatbot plugin that combines a click-based FAQ tree with a free-text query engine backed by n8n. Ships as an npm package with a Node.js/Express server and widgets for React, Vue 3, and Vanilla JS.
6
+
7
+ **Features:**
8
+ - Click-based FAQ question tree with subquestions
9
+ - Fuzzy + keyword matching against your config
10
+ - n8n webhook fallback for unmatched queries
11
+ - Markdown rendering (bold, lists, headings)
12
+ - Multi-bubble paragraph responses
13
+ - Draggable floating chat button
14
+ - Tagalog (TL) language support
15
+ - Input validation and profanity guardrails
16
+ - Session-based analytics
17
+
18
+ ---
19
+
20
+ ## Table of Contents
21
+
22
+ 1. [Requirements](#1-requirements)
23
+ 2. [Installation](#2-installation)
24
+ 3. [Scaffold Config Files](#3-scaffold-config-files)
25
+ 4. [Configure the Chatbot](#4-configure-the-chatbot)
26
+ 5. [Build the FAQ Tree](#5-build-the-faq-tree)
27
+ 6. [Start the Server](#6-start-the-server)
28
+ 7. [Embed the Widget](#7-embed-the-widget)
29
+ 8. [Floating Button Behavior](#8-floating-button-behavior)
30
+ 9. [n8n Webhook Setup](#9-n8n-webhook-setup)
31
+ 10. [n8n Response Formats](#10-n8n-response-formats)
32
+ 11. [Environment Variables](#11-environment-variables)
33
+ 12. [API Reference](#12-api-reference)
34
+ 13. [Analytics](#13-analytics)
35
+ 14. [Troubleshooting](#14-troubleshooting)
36
+
37
+ ---
38
+
39
+ ## 1. Requirements
40
+
41
+ | Requirement | Version |
42
+ |---|---|
43
+ | Node.js | >= 18.0.0 |
44
+ | npm | >= 9.0.0 |
45
+ | React (for React widget) | >= 18.0.0 |
46
+ | Vue (for Vue 3 widget) | >= 3.0.0 |
47
+ | Vue (for Vue 2 widget) | >= 2.5.17 |
48
+ | n8n instance | Any hosted or self-hosted |
49
+
50
+ ---
51
+
52
+ ## 2. Installation
53
+
54
+ ```bash
55
+ npm install rushchatbot
56
+ ```
57
+
58
+ ---
59
+
60
+ ## 3. Scaffold Config Files
61
+
62
+ Run the init command to generate the required config and questions files in a directory of your choice:
63
+
64
+ ```bash
65
+ npx rushchatbot init ./chatbot
66
+ ```
67
+
68
+ This creates three files:
69
+
70
+ ```
71
+ chatbot/
72
+ ├── chatbot.config.json ← branding, n8n, chat settings
73
+ ├── questions.json ← English FAQ tree
74
+ └── questions.tl.json ← Tagalog FAQ tree (optional)
75
+ ```
76
+
77
+ ---
78
+
79
+ ## 4. Configure the Chatbot
80
+
81
+ Edit `chatbot.config.json` with your settings:
82
+
83
+ ```json
84
+ {
85
+ "branding": {
86
+ "title": "My Support Bot",
87
+ "subtitle": "How can we help you today?",
88
+ "theme": {
89
+ "primaryColor": "#4F46E5",
90
+ "backgroundColor": "#FFFFFF",
91
+ "userBubbleColor": "#4F46E5",
92
+ "botBubbleColor": "#F3F4F6",
93
+ "textColor": "#111827",
94
+ "fontFamily": "Inter, sans-serif"
95
+ }
96
+ },
97
+ "n8n": {
98
+ "webhookUrl": "https://your-n8n.com/webhook/your-webhook-id",
99
+ "timeoutMs": 55000
100
+ },
101
+ "chat": {
102
+ "welcomeMessage": "Hi! Choose a question below or type your own.",
103
+ "fallbackMessage": "Let me look that up for you...",
104
+ "matchThreshold": 0.4,
105
+ "showPreQuestionsOnStart": true,
106
+ "language": "en"
107
+ }
108
+ }
109
+ ```
110
+
111
+ ### Config field reference
112
+
113
+ | Field | Type | Default | Description |
114
+ |---|---|---|---|
115
+ | `branding.title` | string | — | Chat header title |
116
+ | `branding.subtitle` | string | — | Chat header subtitle |
117
+ | `branding.theme.primaryColor` | string | `#4F46E5` | Header, buttons, user bubble color |
118
+ | `branding.theme.backgroundColor` | string | `#FFFFFF` | Chat window background |
119
+ | `branding.theme.userBubbleColor` | string | `#4F46E5` | User message bubble color |
120
+ | `branding.theme.botBubbleColor` | string | `#F3F4F6` | Bot message bubble color |
121
+ | `branding.theme.textColor` | string | `#111827` | Main text color |
122
+ | `branding.theme.fontFamily` | string | `Inter, sans-serif` | Font stack |
123
+ | `n8n.webhookUrl` | string | — | Your n8n POST webhook URL |
124
+ | `n8n.timeoutMs` | number | `55000` | n8n request timeout in milliseconds |
125
+ | `chat.welcomeMessage` | string | — | First message shown when chat opens |
126
+ | `chat.fallbackMessage` | string | — | Shown when an error occurs |
127
+ | `chat.matchThreshold` | number | `0.4` | Fuzzy match sensitivity (0–1). Lower = stricter |
128
+ | `chat.showPreQuestionsOnStart` | boolean | `true` | Show FAQ buttons when chat opens |
129
+ | `chat.language` | `"en"` \| `"tl"` | `"en"` | Language for displaying FAQ questions |
130
+
131
+ ---
132
+
133
+ ## 6. Build the FAQ Tree
134
+
135
+ Edit `questions.json` to define your FAQ categories and answers. The structure supports two levels: main questions and subquestions.
136
+
137
+ ```json
138
+ [
139
+ {
140
+ "id": "q1",
141
+ "question": "About Our Company",
142
+ "answer": "We are a company that...",
143
+ "subquestions": [
144
+ {
145
+ "id": "q1a",
146
+ "question": "When was the company founded?",
147
+ "answer": "We were founded in 2010.",
148
+ "subquestions": []
149
+ },
150
+ {
151
+ "id": "q1b",
152
+ "question": "What is your mission?",
153
+ "answer": "Our mission is to...",
154
+ "subquestions": []
155
+ }
156
+ ]
157
+ },
158
+ {
159
+ "id": "q2",
160
+ "question": "Contact Information",
161
+ "answer": "You can reach us at support@example.com.",
162
+ "subquestions": []
163
+ }
164
+ ]
165
+ ```
166
+
167
+ ### Rules
168
+
169
+ - Every question must have a unique `id`
170
+ - `subquestions` must be an array (use `[]` if none)
171
+ - `answer` is shown when the question is clicked directly or matched via text search
172
+ - For Tagalog support, mirror the same structure in `questions.tl.json` with translated text — keep the same `id` values
173
+
174
+ ---
175
+
176
+ ## 6. Start the Server
177
+
178
+ Create a server entry file (e.g. `server.js` or `server.ts`):
179
+
180
+ ```ts
181
+ import { createServer } from 'rushchatbot/server'
182
+ import path from 'path'
183
+
184
+ createServer({
185
+ configPath: path.resolve('./chatbot/chatbot.config.json'),
186
+ questionsPath: path.resolve('./chatbot/questions.json'),
187
+ questionsTagalogPath: path.resolve('./chatbot/questions.tl.json'), // optional
188
+ port: 3001,
189
+ corsOrigin: 'https://your-frontend-domain.com', // or '*' for development
190
+ }).listen()
191
+ ```
192
+
193
+ ### Server options
194
+
195
+ | Option | Type | Default | Description |
196
+ |---|---|---|---|
197
+ | `configPath` | string | — | **Required.** Absolute path to `chatbot.config.json` |
198
+ | `questionsPath` | string | — | **Required.** Absolute path to `questions.json` |
199
+ | `questionsTagalogPath` | string | — | Optional. Absolute path to `questions.tl.json` |
200
+ | `port` | number | `3001` | Port to listen on |
201
+ | `corsOrigin` | string \| string[] | `*` | Allowed CORS origin(s) |
202
+
203
+ Start the server:
204
+
205
+ ```bash
206
+ node server.js
207
+ ```
208
+
209
+ On successful startup you will see:
210
+
211
+ ```
212
+ [RushChatbot] Server running on http://localhost:3001
213
+ ```
214
+
215
+ ---
216
+
217
+ ## 7. Embed the Widget
218
+
219
+ RushChatbot ships four separate widget builds. Use the one that matches your frontend stack.
220
+
221
+ ---
222
+
223
+ ### React
224
+
225
+ Install peer dependencies if not already present:
226
+
227
+ ```bash
228
+ npm install react react-dom marked
229
+ ```
230
+
231
+ Import and render the widget:
232
+
233
+ ```tsx
234
+ import { ChatWidget } from 'rushchatbot/client'
235
+
236
+ export default function App() {
237
+ return (
238
+ <div>
239
+ <ChatWidget apiBase="http://localhost:3001/api/chat" />
240
+ </div>
241
+ )
242
+ }
243
+ ```
244
+
245
+ The widget renders as a **floating draggable button** fixed to the bottom-right of the screen. Clicking it opens the chat box above the button.
246
+
247
+ #### React widget props
248
+
249
+ | Prop | Type | Default | Description |
250
+ |---|---|---|---|
251
+ | `apiBase` | string | `http://localhost:3001/api/chat` | Base URL of the RushChatbot server |
252
+ | `width` | number | `380` | Chat box width in pixels |
253
+ | `height` | number | `580` | Chat box height in pixels |
254
+
255
+ ---
256
+
257
+ ### Vue 2
258
+
259
+ Install peer dependency if not already present:
260
+
261
+ ```bash
262
+ npm install vue@2
263
+ ```
264
+
265
+ Register and use the component:
266
+
267
+ ```vue
268
+ <script>
269
+ import ChatWidget from 'rushchatbot/vue2'
270
+
271
+ export default {
272
+ components: { ChatWidget }
273
+ }
274
+ </script>
275
+
276
+ <template>
277
+ <ChatWidget api-base="http://localhost:3001/api/chat" />
278
+ </template>
279
+ ```
280
+
281
+ Or register it globally in `main.js`:
282
+
283
+ ```js
284
+ import Vue from 'vue'
285
+ import App from './App.vue'
286
+ import ChatWidget from 'rushchatbot/vue2'
287
+
288
+ Vue.component('RushChatbot', ChatWidget)
289
+ new Vue({ render: h => h(App) }).$mount('#app')
290
+ ```
291
+
292
+ Then use it anywhere:
293
+
294
+ ```vue
295
+ <template>
296
+ <RushChatbot api-base="http://localhost:3001/api/chat" />
297
+ </template>
298
+ ```
299
+
300
+ #### Vue 2 widget props
301
+
302
+ | Prop | Type | Default | Description |
303
+ |---|---|---|---|
304
+ | `api-base` | string | `http://localhost:3001/api/chat` | Base URL of the RushChatbot server |
305
+ | `width` | number | — | Chat box width in pixels (omit for fluid) |
306
+ | `height` | number | — | Chat box height in pixels (omit for fluid) |
307
+ | `primary-color` | string | from config | Override primary/accent color |
308
+ | `bg-color` | string | from config | Override background color |
309
+ | `border-radius` | number | `16` | Container corner radius in pixels |
310
+ | `show-shadow` | boolean | `true` | Show/hide box shadow |
311
+ | `placeholder` | string | `Type a message...` | Input placeholder text |
312
+ | `send-label` | string | `Send` | Send button label |
313
+ | `hide-input` | boolean | `false` | Hide the text input bar |
314
+ | `hide-end-chat` | boolean | `false` | Hide the "I'm done" end chat button |
315
+
316
+ ---
317
+
318
+ ### Vue 3
319
+
320
+ Install peer dependency if not already present:
321
+
322
+ ```bash
323
+ npm install vue
324
+ ```
325
+
326
+ Register and use the component:
327
+
328
+ ```vue
329
+ <script setup>
330
+ import ChatWidget from 'rushchatbot/vue'
331
+ </script>
332
+
333
+ <template>
334
+ <ChatWidget api-base="http://localhost:3001/api/chat" />
335
+ </template>
336
+ ```
337
+
338
+ Or register it globally in `main.ts`:
339
+
340
+ ```ts
341
+ import { createApp } from 'vue'
342
+ import App from './App.vue'
343
+ import ChatWidget from 'rushchatbot/vue'
344
+
345
+ const app = createApp(App)
346
+ app.component('RushChatbot', ChatWidget)
347
+ app.mount('#app')
348
+ ```
349
+
350
+ Then use it anywhere:
351
+
352
+ ```vue
353
+ <template>
354
+ <RushChatbot api-base="http://localhost:3001/api/chat" />
355
+ </template>
356
+ ```
357
+
358
+ #### Vue widget props
359
+
360
+ | Prop | Type | Default | Description |
361
+ |---|---|---|---|
362
+ | `api-base` | string | `http://localhost:3001/api/chat` | Base URL of the RushChatbot server |
363
+ | `width` | number | — | Chat box width in pixels (omit for fluid) |
364
+ | `height` | number | — | Chat box height in pixels (omit for fluid) |
365
+ | `primary-color` | string | from config | Override primary/accent color |
366
+ | `bg-color` | string | from config | Override background color |
367
+ | `border-radius` | number | `16` | Container corner radius in pixels |
368
+ | `show-shadow` | boolean | `true` | Show/hide box shadow |
369
+ | `placeholder` | string | `Type a message...` | Input placeholder text |
370
+ | `send-label` | string | `Send` | Send button label |
371
+ | `hide-input` | boolean | `false` | Hide the text input bar |
372
+ | `hide-end-chat` | boolean | `false` | Hide the "I'm done" end chat button |
373
+
374
+ ---
375
+
376
+ ### Vanilla JS (Web Component)
377
+
378
+ No framework required. The Vanilla build registers a `<rush-chatbot>` custom element using the Web Components API with Shadow DOM.
379
+
380
+ #### Via npm
381
+
382
+ ```ts
383
+ import 'rushchatbot/vanilla'
384
+ ```
385
+
386
+ Then add the element anywhere in your HTML:
387
+
388
+ ```html
389
+ <rush-chatbot api-base="http://localhost:3001/api/chat"></rush-chatbot>
390
+ ```
391
+
392
+ #### Via CDN / script tag
393
+
394
+ ```html
395
+ <script type="module" src="/path/to/rushchatbot/dist/vanilla.es.js"></script>
396
+ <!-- or IIFE build for non-module environments -->
397
+ <script src="/path/to/rushchatbot/dist/vanilla.iife.js"></script>
398
+
399
+ <rush-chatbot api-base="http://localhost:3001/api/chat"></rush-chatbot>
400
+ ```
401
+
402
+ #### Web Component attributes
403
+
404
+ | Attribute | Type | Default | Description |
405
+ |---|---|---|---|
406
+ | `api-base` | string | `http://localhost:3001/api/chat` | Base URL of the RushChatbot server |
407
+ | `width` | number | — | Chat box width in pixels (omit for fluid) |
408
+ | `height` | number | — | Chat box height in pixels (omit for fluid) |
409
+ | `primary-color` | string | from config | Override primary/accent color |
410
+ | `bg-color` | string | from config | Override background color |
411
+ | `border-radius` | number | `16` | Container corner radius in pixels |
412
+ | `show-shadow` | boolean | `true` | Show/hide box shadow |
413
+ | `placeholder` | string | `Type a message...` | Input placeholder text |
414
+ | `send-label` | string | `Send` | Send button label |
415
+ | `hide-input` | boolean | `false` | Hide the text input bar |
416
+ | `hide-end-chat` | boolean | `false` | Hide the "I'm done" end chat button |
417
+ | `auto-open` | boolean | `false` | Auto-open chat on load |
418
+ | `position` | `bottom-right\|bottom-left` | `bottom-right` | Floating button position |
419
+
420
+ Attributes can be updated at runtime and the widget will reflect the changes:
421
+
422
+ ```js
423
+ document.querySelector('rush-chatbot').setAttribute('api-base', 'https://my-server.com/api/chat')
424
+ ```
425
+
426
+ ---
427
+
428
+ ## 8. Floating Button Behavior
429
+
430
+ The chat button is draggable across the entire screen:
431
+
432
+ - **Drag** — click and hold, then move to reposition the button anywhere on screen
433
+ - **Click** (no drag) — toggles the chat box open or closed
434
+ - **Chat box position** — always appears directly above the button, clamped to the viewport so it never goes off-screen
435
+ - **Close** — click the ✕ button inside the chat header, or click the floating button again
436
+ - Works on both desktop (mouse) and mobile (touch)
437
+
438
+ ---
439
+
440
+ ## 9. n8n Webhook Setup
441
+
442
+ When a user types a query that doesn't match any FAQ answer, RushChatbot forwards it to your n8n webhook.
443
+
444
+ ### What RushChatbot sends to n8n
445
+
446
+ ```json
447
+ {
448
+ "query": "the user's message",
449
+ "sessionId": "sess_abc123"
450
+ }
451
+ ```
452
+
453
+ Headers sent:
454
+
455
+ ```
456
+ Content-Type: application/json
457
+ x-session-id: sess_abc123
458
+ ```
459
+
460
+ ### Setting up the webhook in n8n
461
+
462
+ 1. Create a new workflow in n8n
463
+ 2. Add a **Webhook** trigger node — set method to `POST`
464
+ 3. Copy the webhook URL into `chatbot.config.json` under `n8n.webhookUrl`
465
+ 4. Add your AI/logic nodes after the webhook trigger
466
+ 5. End with a **Respond to Webhook** node returning one of the supported response formats (see section 11)
467
+ 6. Activate the workflow
468
+
469
+ ### Session continuity
470
+
471
+ The `sessionId` is generated per browser tab (`sess_` + timestamp + random suffix). Pass it through your n8n workflow to maintain conversation context with your AI agent.
472
+
473
+ ---
474
+
475
+ ## 10. n8n Response Formats
476
+
477
+ RushChatbot automatically parses all of the following response shapes from n8n:
478
+
479
+ ### Single answer
480
+
481
+ ```json
482
+ [{ "output": "Your answer text here" }]
483
+ ```
484
+
485
+ ```json
486
+ [{ "answer": "Your answer text here" }]
487
+ ```
488
+
489
+ ```json
490
+ [{ "text": "Your answer text here" }]
491
+ ```
492
+
493
+ ### Multiple bubbles (paragraphs)
494
+
495
+ Return a `paragraphs` array to render each item as a **separate chat bubble** with a short delay between them:
496
+
497
+ ```json
498
+ [{
499
+ "paragraphs": [
500
+ "First part of the response.",
501
+ "Second part with **bold** and lists.",
502
+ "Third bubble with a follow-up question."
503
+ ]
504
+ }]
505
+ ```
506
+
507
+ ### Markdown support
508
+
509
+ All responses are rendered as Markdown. Supported formatting:
510
+
511
+ | Syntax | Renders as |
512
+ |---|---|
513
+ | `**bold**` | **bold** |
514
+ | `# Heading` | Large heading |
515
+ | `- item` | Bullet list |
516
+ | `1. item` | Numbered list |
517
+ | `[link](url)` | Hyperlink |
518
+ | `\n` (newline) | Line break |
519
+
520
+ ---
521
+
522
+ ## 11. Environment Variables
523
+
524
+ | Variable | Required | Description |
525
+ |---|---|---|
526
+ | `PORT` | No | Override the server port (default: `3001`) |
527
+
528
+ ### Setting the port
529
+
530
+ ```bash
531
+ PORT=4000 node server.js
532
+ ```
533
+
534
+ ---
535
+
536
+ ## 12. API Reference
537
+
538
+ All endpoints are mounted under `/api/chat`.
539
+
540
+ ### `GET /api/chat/config`
541
+
542
+ Returns branding and chat settings. Safe to call from the frontend — never exposes n8n credentials or license key.
543
+
544
+ **Response:**
545
+ ```json
546
+ {
547
+ "branding": { "title": "...", "subtitle": "...", "theme": { } },
548
+ "chat": { "welcomeMessage": "...", "language": "en" }
549
+ }
550
+ ```
551
+
552
+ ---
553
+
554
+ ### `GET /api/chat/questions`
555
+
556
+ Returns the FAQ question tree in the configured language.
557
+
558
+ **Response:**
559
+ ```json
560
+ [
561
+ {
562
+ "id": "q1",
563
+ "question": "About Our Company",
564
+ "answer": "...",
565
+ "subquestions": []
566
+ }
567
+ ]
568
+ ```
569
+
570
+ ---
571
+
572
+ ### `GET /api/chat/query?query=your+question&sessionId=sess_abc`
573
+
574
+ Forwards the query **directly to n8n**, bypassing FAQ matching. Useful for testing your n8n workflow from the browser.
575
+
576
+ **Query params:**
577
+
578
+ | Param | Required | Description |
579
+ |---|---|---|
580
+ | `query` | Yes | The user's question |
581
+ | `sessionId` | No | Session identifier |
582
+
583
+ **Response:**
584
+ ```json
585
+ { "answer": "...", "source": "n8n" }
586
+ ```
587
+ or
588
+ ```json
589
+ { "paragraphs": ["...", "..."], "source": "n8n" }
590
+ ```
591
+
592
+ ---
593
+
594
+ ### `POST /api/chat/query`
595
+
596
+ Main query endpoint. Runs the full pipeline: input validation → guardrails → FAQ matching → n8n fallback.
597
+
598
+ **Request body:**
599
+ ```json
600
+ {
601
+ "query": "How do I apply for membership?",
602
+ "sessionId": "sess_abc123"
603
+ }
604
+ ```
605
+
606
+ **Response (FAQ match):**
607
+ ```json
608
+ {
609
+ "answer": "You can apply by...",
610
+ "source": "config",
611
+ "matchedQuestion": "How do I apply for membership?",
612
+ "matchedKeywords": ["apply", "membership"],
613
+ "score": 87
614
+ }
615
+ ```
616
+
617
+ **Response (n8n fallback):**
618
+ ```json
619
+ { "answer": "...", "source": "n8n" }
620
+ ```
621
+
622
+ **Response (validation/guardrail blocked):**
623
+ ```json
624
+ { "answer": "Please rephrase your question...", "source": "validation" }
625
+ ```
626
+
627
+ ---
628
+
629
+ ### `POST /api/chat/click`
630
+
631
+ Tracks when a user clicks a pre-built FAQ question.
632
+
633
+ **Request body:**
634
+ ```json
635
+ {
636
+ "questionId": "q1a",
637
+ "sessionId": "sess_abc123"
638
+ }
639
+ ```
640
+
641
+ **Response:**
642
+ ```json
643
+ { "ok": true }
644
+ ```
645
+
646
+ ---
647
+
648
+ ### `GET /api/chat/analytics`
649
+
650
+ Returns the full analytics log.
651
+
652
+ **Response:**
653
+ ```json
654
+ [
655
+ {
656
+ "sessionId": "sess_abc123",
657
+ "questionId": "q1a",
658
+ "timestamp": "2025-01-01T10:00:00.000Z",
659
+ "type": "click"
660
+ }
661
+ ]
662
+ ```
663
+
664
+ **Analytics types:**
665
+
666
+ | Type | Description |
667
+ |---|---|
668
+ | `click` | User clicked a pre-built FAQ question |
669
+ | `match` | User query matched a FAQ answer |
670
+ | `n8n` | Query was forwarded to n8n |
671
+ | `error` | Validation, guardrail, or server error |
672
+
673
+ ---
674
+
675
+ ## 13. Analytics
676
+
677
+ Analytics are written to `analytics.json` in the same directory as your `chatbot.config.json`. Each entry records:
678
+
679
+ - `sessionId` — browser session (resets on new tab)
680
+ - `questionId` — the matched question ID, or `n8n` / `error` / `guardrail`
681
+ - `timestamp` — ISO 8601 UTC
682
+ - `type` — `click`, `match`, `n8n`, or `error`
683
+
684
+ You can query the log at any time via `GET /api/chat/analytics` or read the file directly.
685
+
686
+ ---
687
+
688
+ ## 14. Troubleshooting
689
+
690
+ ### `[RushChatbot] configPath not found`
691
+
692
+ - Use `path.resolve()` to ensure the path is absolute
693
+ - Verify the file exists at the specified location
694
+
695
+ ### Chat widget shows nothing / blank
696
+
697
+ - Check the browser console for CORS errors
698
+ - Ensure `corsOrigin` in `createServer()` includes your frontend's origin
699
+ - Confirm the server is running and reachable at the `apiBase` URL
700
+
701
+ ### n8n not responding / timeout
702
+
703
+ - Increase `n8n.timeoutMs` in `chatbot.config.json` (default is 55000ms)
704
+ - Test the webhook directly: `GET http://localhost:3001/api/chat/query?query=hello`
705
+ - Check your n8n workflow is activated (not just saved)
706
+
707
+ ### Port already in use
708
+
709
+ ```bash
710
+ kill $(lsof -ti :3001)
711
+ ```
712
+
713
+ ### Queries always fall through to n8n (no FAQ matches)
714
+
715
+ - Lower `chat.matchThreshold` in config (e.g. `0.3`)
716
+ - Ensure your `questions.json` answers contain keywords that appear in user queries
717
+ - Check that question `id` values are unique across the entire tree