Skip to content

feat: generalized chat quiz generator with PDF and Word downloads#495

Open
nandani-singh15 wants to merge 2 commits into
FireFistisDead:masterfrom
nandani-singh15:feature/chat-quiz-generator
Open

feat: generalized chat quiz generator with PDF and Word downloads#495
nandani-singh15 wants to merge 2 commits into
FireFistisDead:masterfrom
nandani-singh15:feature/chat-quiz-generator

Conversation

@nandani-singh15

@nandani-singh15 nandani-singh15 commented Jun 8, 2026

Copy link
Copy Markdown

Summary

Enhanced the existing PDF QA bot into a more generalized LLM-driven assistant where quiz generation is triggered naturally through user intent rather than a dedicated quiz button.

Now, when a user explicitly asks for a quiz within the conversation, the LLM automatically generates a quiz using the available context from the chat/PDF. This makes the system more intelligent and flexible, rather than being limited to a fixed UI action.

Additionally, the generated quiz can be exported and downloaded in both PDF and Word formats, allowing users to save structured quiz outputs easily.

This improves the system from a tool-based flow to an intent-based intelligent assistant.

Related issue

Closes: 101

Testing

  • I ran the relevant checks locally
  • I verified the app still starts
  • I tested the affected flow end-to-end
  • I confirmed quiz generation triggers via user prompt (no button required)
  • I tested PDF export functionality
  • I tested Word export functionality

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas

Screenshots / recordings

  • Quiz is generated automatically when user requests it in chat
  • Generated quiz is context-aware (based on conversation/PDF content)
  • Export works for:
    • PDF format
    • Word format
  • Message rendering updated in chat UI

Notes

  • This feature removes dependency on a dedicated quiz button
  • Quiz generation is now fully driven by LLM intent detection
  • Ensure backend RAG service and frontend utils remain synchronized
  • Verify quizExporter.js is correctly handling both export formats

Security

  • No sensitive data included

Summary by CodeRabbit

  • New Features
    • Quiz generation: A new quiz mode is available to generate structured 5-question multiple-choice quizzes with marked correct answers, clear explanations, and contextual material integrated for effective self-assessment and learning.
    • Quiz export: Download generated quizzes as PDF or Word documents using convenient export buttons included in quiz response messages for offline access and studying.

@vercel

vercel Bot commented Jun 8, 2026

Copy link
Copy Markdown

@nandani-singh15 is attempting to deploy a commit to the firefistisdead's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@nandani-singh15, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 51 minutes and 32 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c107e771-cc55-4072-abbb-a856885700ae

📥 Commits

Reviewing files that changed from the base of the PR and between 17807b5 and fe1900b.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • frontend/package.json
  • frontend/src/components/ChatPanel/MessageBubble.jsx
  • rag-service/main.py
  • src/data/users.json
  • validators/schemas.js
📝 Walkthrough

Walkthrough

This PR adds a "quiz" generation mode across the full stack. The backend detects quiz-related queries, generates 5-question multiple-choice quizzes in markdown format with correct answers marked, and disables extractive answers for quiz requests. The frontend adds PDF and Word export functionality with markdown-to-HTML parsing and styled document generation, plus UI buttons to download generated quizzes from chat messages.

Changes

Quiz Mode Feature – Full Stack

Layer / File(s) Summary
Quiz mode validation schema
validators/schemas.js, rag-service/main.py
modeSchema now accepts "quiz" as a valid mode; VALID_MODES includes "quiz" for API validation.
Backend quiz detection and generation
rag-service/main.py
detect_question_intent returns "quiz" for quiz-phrasing queries; build_answer_from_documents returns None to skip extractive path; /ask and /ask/stream conditionally build quiz prompts requesting 5-question multiple-choice quizzes in markdown and increase max_new_tokens to 512.
Quiz export utilities (PDF, Word) and dependency
frontend/package.json, frontend/src/utils/quizExporter.js
Added jspdf dependency; parseMarkdownToHtml converts markdown quiz structure to HTML; exportQuizToWord generates Word-compatible HTML with inline styling and downloads via saveAs; exportQuizToPdf uses jsPDF to generate styled, paginated PDFs with per-line-type formatting and text wrapping.
MessageBubble quiz UI buttons
frontend/src/components/ChatPanel/MessageBubble.jsx
Added "quiz" badge to MODE_BADGE; conditional rendering of "Download PDF" and "Download Word" buttons for non-streaming bot messages matching quiz mode or containing quiz markers; buttons call export functions and respect dark mode styling.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant AskEndpoint as /ask endpoint
  participant IntentDetection as detect_question_intent
  participant ExtractionBuilder as build_answer_from_documents
  participant GenerationBuilder as build generation prompt
  participant LLM
  
  Client->>AskEndpoint: POST with question/mode
  AskEndpoint->>IntentDetection: Analyze question text
  IntentDetection-->>AskEndpoint: Returns "quiz" if quiz-related phrasing detected
  AskEndpoint->>ExtractionBuilder: Check if extractive path applies
  ExtractionBuilder-->>AskEndpoint: Returns None for quiz intent (skip extractive)
  AskEndpoint->>GenerationBuilder: Build prompt (mode/intent="quiz")
  GenerationBuilder-->>AskEndpoint: Returns quiz prompt: "Generate 5-question multiple-choice quiz..."
  AskEndpoint->>LLM: Generate with max_new_tokens=512
  LLM-->>Client: Markdown quiz with correct answers
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • FireFistisDead/pdf-qa-bot#202: Extends the same mode pipeline infrastructure (rag-service VALID_MODES + frontend mode rendering) with the new quiz mode built on top of existing reading-mode support.

Suggested labels

feature, enhancement, frontend, backend, rag-service, type:testing, quality:clean

Suggested reviewers

  • FireFistisDead

Poem

A quiz in PDF form takes flight,
Markdown becomes a download tonight,
Five questions dance on every page,
With answers marked—the final stage,
From prompt to button, features align,
A feature so whimsical and fine! 🐰📄

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: adding quiz generation triggered by user intent with PDF and Word export capabilities.
Description check ✅ Passed The description is comprehensive, covering summary, related issue, detailed testing (7 items checked), full checklist completion, screenshots/recordings context, notes on synchronization needs, and security confirmation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added backend Express or API gateway work docs Documentation only enhancement New feature or request feature A new feature or improvement fix A targeted fix or cleanup frontend Frontend-related work level:advanced rag-service FastAPI / model service work type:security type:testing question Further information is requested labels Jun 8, 2026
@nandani-singh15

Copy link
Copy Markdown
Author

@FireFistisDead kindly reveiw suggest and merge

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/components/ChatPanel/MessageBubble.jsx`:
- Around line 114-150: The predicate that decides whether to render the
quiz-export buttons calls msg.text.includes and msg.text.toLowerCase() which
will throw if msg.text is null or not a string; update the conditional in
MessageBubble.jsx to guard msg.text by checking typeof msg.text === "string"
(e.g. typeof msg.text === "string" && (msg.mode === "quiz" ||
msg.text.includes("# Quiz") || msg.text.toLowerCase().includes("quiz:"))), so
the exportQuizToPdf/exportQuizToWord handlers are only shown when msg.text is a
string.

In `@frontend/src/utils/quizExporter.js`:
- Around line 7-45: The parser injects unescaped quiz text into HTML
(parseMarkdownToHtml), allowing HTML injection; create and use an escapeHtml
helper that replaces &, <, >, ", and ' with their entities and call it on each
input line (or the whole markdown) before any tag insertion, then perform
markdown-specific replacements (e.g., converting **bold** to <strong>) on the
escaped text so only safe HTML is emitted; update parseMarkdownToHtml to call
escapeHtml where lines are trimmed/processed and also apply the same escapeHtml
usage at the other export spot referenced around lines 84-85 to ensure all
exported content is escaped before building the .doc markup.

In `@rag-service/main.py`:
- Around line 993-994: The current quiz-detection if statement uses simple
substring checks on normalized_question which causes false positives; replace it
with regex/phrase-based matching that checks whole-word boundaries and explicit
intent phrases (e.g., patterns like "\bcreate (a )?quiz\b", "\bgive me (a
)?quiz\b", "\bgenerate (a )?quiz\b", "\bcreate (a )?test\b", "\bquiz me\b") and
only return "quiz" when one of these intent patterns matches
normalized_question; update the detection logic around the existing
normalized_question usage to use compiled regexes or an allowlist of explicit
phrases instead of bare substring checks.

In `@src/data/users.json`:
- Around line 1-10: Remove the committed user credential entries from the
runtime credential store file (src/data/users.json) so that the app's
signup/login flow in src/controllers/authController.js does not seed real
accounts; replace the committed objects with an empty array (or move these test
fixtures to a non-runtime test fixture file) and ensure any tests or local dev
scripts that relied on these sample users point to the new fixture path or
create users at runtime via the signup flow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 52666651-8f6f-4eda-91df-5a6fb8851977

📥 Commits

Reviewing files that changed from the base of the PR and between 6e39eb5 and 17807b5.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • frontend/package.json
  • frontend/src/components/ChatPanel/MessageBubble.jsx
  • frontend/src/utils/quizExporter.js
  • rag-service/main.py
  • src/data/users.json
  • validators/schemas.js

Comment on lines +114 to 150
{msg.role === "bot" && !msg.streaming && (msg.mode === "quiz" || msg.text.includes("# Quiz") || msg.text.toLowerCase().includes("quiz:")) && (
<div style={{ marginTop: "14px", display: "flex", gap: "10px" }}>
<button
onClick={() => exportQuizToPdf(msg.text, "quiz")}
style={{
padding: "6px 14px",
borderRadius: "10px",
border: "none",
background: "linear-gradient(135deg, #8B5CF6 0%, #6366F1 100%)",
color: "white",
fontWeight: 600,
color: darkMode ? "#E5E7EB" : "#1F2937",
marginBottom: "10px",
fontSize: "14px"
}}>
{followup.question}
</div>
)}
<div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
{followup.options.map((opt, idx) => (
<button
key={idx}
onClick={() => onOptionClick?.(opt)}
style={{
textAlign: "left",
padding: "8px 12px",
borderRadius: "8px",
background: darkMode ? "rgba(255,255,255,0.05)" : "#FFFFFF",
border: darkMode ? "1px solid rgba(255,255,255,0.1)" : "1px solid rgba(0,0,0,0.08)",
color: darkMode ? "#D1D5DB" : "#4B5563",
fontSize: "13px",
cursor: "pointer",
transition: "all 0.2s ease"
}}
onMouseOver={(e) => {
e.currentTarget.style.background = darkMode ? "rgba(139, 92, 246, 0.2)" : "rgba(139, 92, 246, 0.1)";
e.currentTarget.style.borderColor = "#8B5CF6";
e.currentTarget.style.color = darkMode ? "#FFF" : "#111";
}}
onMouseOut={(e) => {
e.currentTarget.style.background = darkMode ? "rgba(255,255,255,0.05)" : "#FFFFFF";
e.currentTarget.style.borderColor = darkMode ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.08)";
e.currentTarget.style.color = darkMode ? "#D1D5DB" : "#4B5563";
}}
>
{opt}
</button>
))}
</div>
fontSize: "12px",
cursor: "pointer",
boxShadow: "0 4px 10px rgba(139, 92, 246, 0.2)",
transition: "all 0.2s ease"
}}
>
📄 Download PDF
</button>
<button
onClick={() => exportQuizToWord(msg.text, "quiz")}
style={{
padding: "6px 14px",
borderRadius: "10px",
border: darkMode ? "1px solid rgba(255,255,255,0.15)" : "1px solid rgba(0,0,0,0.15)",
background: "transparent",
color: darkMode ? "#D1D5DB" : "#4B5563",
fontWeight: 600,
fontSize: "12px",
cursor: "pointer",
transition: "all 0.2s ease"
}}
>
📝 Download Word
</button>
</div>
)}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard quiz-export predicate against non-string msg.text.

Line [114] calls .includes and .toLowerCase() directly on msg.text; a null/non-string payload will throw during render and break the chat view.

Proposed fix
 const MessageBubble = ({ msg, darkMode, onOpenSource }) => {
+  const messageText = typeof msg.text === "string" ? msg.text : "";
+  const isQuizMessage =
+    msg.role === "bot" &&
+    !msg.streaming &&
+    (msg.mode === "quiz" ||
+      messageText.includes("# Quiz") ||
+      messageText.toLowerCase().includes("quiz:"));

   const getSourceLabel = (source) => source.document || "Source Document";
   const hasOpenablePage = (source) => Boolean(source.page && source.document);
@@
-            <ReactMarkdown rehypePlugins={[[rehypeSanitize, MARKDOWN_SANITIZE_SCHEMA]]}>{msg.text}</ReactMarkdown>
+            <ReactMarkdown rehypePlugins={[[rehypeSanitize, MARKDOWN_SANITIZE_SCHEMA]]}>{messageText}</ReactMarkdown>
@@
-        {msg.role === "bot" && !msg.streaming && (msg.mode === "quiz" || msg.text.includes("# Quiz") || msg.text.toLowerCase().includes("quiz:")) && (
+        {isQuizMessage && (
           <div style={{ marginTop: "14px", display: "flex", gap: "10px" }}>
             <button
-              onClick={() => exportQuizToPdf(msg.text, "quiz")}
+              onClick={() => exportQuizToPdf(messageText, "quiz")}
@@
             <button
-              onClick={() => exportQuizToWord(msg.text, "quiz")}
+              onClick={() => exportQuizToWord(messageText, "quiz")}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/ChatPanel/MessageBubble.jsx` around lines 114 - 150,
The predicate that decides whether to render the quiz-export buttons calls
msg.text.includes and msg.text.toLowerCase() which will throw if msg.text is
null or not a string; update the conditional in MessageBubble.jsx to guard
msg.text by checking typeof msg.text === "string" (e.g. typeof msg.text ===
"string" && (msg.mode === "quiz" || msg.text.includes("# Quiz") ||
msg.text.toLowerCase().includes("quiz:"))), so the
exportQuizToPdf/exportQuizToWord handlers are only shown when msg.text is a
string.

Comment on lines +7 to +45
const parseMarkdownToHtml = (markdown) => {
return markdown
.split("\n")
.map((line) => {
const trimmed = line.trim();
if (!trimmed) {
return "<br/>";
}

// Headers
if (line.startsWith("# ")) {
return `<h1>${line.substring(2)}</h1>`;
}
if (line.startsWith("## ")) {
return `<h2>${line.substring(3)}</h2>`;
}

// Question line (e.g., "1. **Question:** What is...")
if (trimmed.match(/^\d+\./)) {
const formatted = trimmed.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>");
return `<p class="question" style="font-size: 14pt; font-weight: bold; margin-top: 18pt; margin-bottom: 6pt; color: #1e293b;">${formatted}</p>`;
}

// Option line (e.g., "- A) Option text")
if (trimmed.startsWith("- ") || trimmed.startsWith("* ")) {
const optionText = trimmed.substring(2);
return `<p class="option" style="font-size: 11pt; margin-left: 20pt; margin-top: 3pt; margin-bottom: 3pt; color: #4b5563;">${optionText}</p>`;
}

// Correct Answer line
if (trimmed.includes("Correct Answer:")) {
const formatted = trimmed.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>");
return `<p class="answer" style="font-size: 11pt; font-weight: bold; margin-left: 20pt; margin-top: 4pt; margin-bottom: 12pt; color: #10b981;">${formatted}</p>`;
}

// Default line formatting
const formatted = trimmed.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>");
return `<p style="font-size: 11pt; margin-top: 6pt; margin-bottom: 6pt; color: #1f2937;">${formatted}</p>`;
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Escape HTML before injecting quiz text into Word-export markup.

Line [7] onward builds HTML using raw quiz text; this allows HTML injection into the generated .doc (e.g., untrusted tags/attributes from model output or prompt-injected content). Escape text first, then apply markdown formatting.

Proposed fix
+const escapeHtml = (value = "") =>
+  value
+    .replace(/&/g, "&amp;")
+    .replace(/</g, "&lt;")
+    .replace(/>/g, "&gt;")
+    .replace(/"/g, "&quot;")
+    .replace(/'/g, "&`#39`;");
+
+const formatInline = (value = "") =>
+  escapeHtml(value).replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>");
+
 const parseMarkdownToHtml = (markdown) => {
-  return markdown
+  return String(markdown ?? "")
     .split("\n")
     .map((line) => {
       const trimmed = line.trim();
       if (!trimmed) {
         return "<br/>";
       }
@@
-      if (line.startsWith("# ")) {
-        return `<h1>${line.substring(2)}</h1>`;
+      if (line.startsWith("# ")) {
+        return `<h1>${formatInline(line.substring(2))}</h1>`;
       }
       if (line.startsWith("## ")) {
-        return `<h2>${line.substring(3)}</h2>`;
+        return `<h2>${formatInline(line.substring(3))}</h2>`;
       }
@@
-        const formatted = trimmed.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>");
+        const formatted = formatInline(trimmed);
         return `<p class="question" style="font-size: 14pt; font-weight: bold; margin-top: 18pt; margin-bottom: 6pt; color: `#1e293b`;">${formatted}</p>`;
       }
@@
-        const optionText = trimmed.substring(2);
+        const optionText = formatInline(trimmed.substring(2));
         return `<p class="option" style="font-size: 11pt; margin-left: 20pt; margin-top: 3pt; margin-bottom: 3pt; color: `#4b5563`;">${optionText}</p>`;
       }
@@
-        const formatted = trimmed.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>");
+        const formatted = formatInline(trimmed);
         return `<p class="answer" style="font-size: 11pt; font-weight: bold; margin-left: 20pt; margin-top: 4pt; margin-bottom: 12pt; color: `#10b981`;">${formatted}</p>`;
       }
@@
-      const formatted = trimmed.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>");
+      const formatted = formatInline(trimmed);
       return `<p style="font-size: 11pt; margin-top: 6pt; margin-bottom: 6pt; color: `#1f2937`;">${formatted}</p>`;
     })
     .join("\n");
 };

Also applies to: 84-85

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/utils/quizExporter.js` around lines 7 - 45, The parser injects
unescaped quiz text into HTML (parseMarkdownToHtml), allowing HTML injection;
create and use an escapeHtml helper that replaces &, <, >, ", and ' with their
entities and call it on each input line (or the whole markdown) before any tag
insertion, then perform markdown-specific replacements (e.g., converting
**bold** to <strong>) on the escaped text so only safe HTML is emitted; update
parseMarkdownToHtml to call escapeHtml where lines are trimmed/processed and
also apply the same escapeHtml usage at the other export spot referenced around
lines 84-85 to ensure all exported content is escaped before building the .doc
markup.

Comment thread rag-service/main.py
Comment on lines +993 to +994
if "quiz" in normalized_question or "test" in normalized_question or "questions" in normalized_question or "question paper" in normalized_question:
return "quiz"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Overly broad quiz detection triggers false positives.

The current detection uses simple substring matching that will incorrectly trigger quiz mode for legitimate questions containing "test", "questions", etc.

False positive examples:

  • "What questions does this document answer?" → contains "questions" → unwanted quiz
  • "Can you test my understanding?" → contains "test" → unwanted quiz
  • "The study questions the methodology" → contains "questions" → unwanted quiz

This degrades UX by generating quizzes when users expect a normal answer.

🔧 Suggested fix with word-boundary matching
-    if "quiz" in normalized_question or "test" in normalized_question or "questions" in normalized_question or "question paper" in normalized_question:
+    # Match quiz intent only when quiz-related terms appear as distinct words/phrases
+    if re.search(r'\b(quiz|quizzes)\b', normalized_question) or \
+       re.search(r'\b(generate|create|make|give me).*\b(test|exam)\b', normalized_question) or \
+       'question paper' in normalized_question:
         return "quiz"

This uses word boundaries and context patterns to reduce false positives while still catching genuine quiz requests like "generate a quiz", "create a test", "give me a quiz", etc.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rag-service/main.py` around lines 993 - 994, The current quiz-detection if
statement uses simple substring checks on normalized_question which causes false
positives; replace it with regex/phrase-based matching that checks whole-word
boundaries and explicit intent phrases (e.g., patterns like "\bcreate (a
)?quiz\b", "\bgive me (a )?quiz\b", "\bgenerate (a )?quiz\b", "\bcreate (a
)?test\b", "\bquiz me\b") and only return "quiz" when one of these intent
patterns matches normalized_question; update the detection logic around the
existing normalized_question usage to use compiled regexes or an allowlist of
explicit phrases instead of bare substring checks.

Comment thread src/data/users.json
Comment on lines 1 to 10
[
{
"email": "testuser-1780133113651@example.com",
"password": "$2b$10$VlcKirFc6zLReabLg97GeOslLoXzPF5WUigQ/JjPrQi5pMpwBuMMe"
"email": "testuser-1780934845930@example.com",
"password": "$2b$10$9AAsvzxfwNp9haLU2oKNMuMTeY3icNBzPYcPHTx3Wv4w78ZUVD7Ry"
},
{
"email": "testuser2-1780133113736@example.com",
"password": "$2b$10$JHamUog0/4MOtnc.la59ZuhhYZy/hxG5BSSVJjyVFW3.SYieaeHGu"
},
{
"email": "testuser-1780133179622@example.com",
"password": "$2b$10$C3zvUpwQMBS7YQhGnyO7TOq5Mo/9rrxgj2n/mN7PnfbSqcYfz0Lte"
},
{
"email": "testuser2-1780133179757@example.com",
"password": "$2b$10$Qae0TsUBvMMjZ0Ofog1B6uHp0GmV5hlbL1q6mVgFtUX6/STIJJliO"
"email": "testuser2-1780934846010@example.com",
"password": "$2b$10$6oXLfmhPAQzfCVLwS5iy/Oqoi5THfbxdKVMjxpWIB/29FwmLnPcTC"
}
]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove committed user records from the runtime credential store.

src/controllers/authController.js reads this file as the live signup/login backend, so checking in concrete { email, password } entries seeds real accounts into every deployed environment and stores credential material in source control. Keep src/data/users.json empty in git (or move test fixtures to a separate file/path) and let signup populate it at runtime instead.

Suggested change
-[
-  {
-    "email": "testuser-1780934845930@example.com",
-    "password": "$2b$10$9AAsvzxfwNp9haLU2oKNMuMTeY3icNBzPYcPHTx3Wv4w78ZUVD7Ry"
-  },
-  {
-    "email": "testuser2-1780934846010@example.com",
-    "password": "$2b$10$6oXLfmhPAQzfCVLwS5iy/Oqoi5THfbxdKVMjxpWIB/29FwmLnPcTC"
-  }
-]
+[]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
[
{
"email": "testuser-1780133113651@example.com",
"password": "$2b$10$VlcKirFc6zLReabLg97GeOslLoXzPF5WUigQ/JjPrQi5pMpwBuMMe"
"email": "testuser-1780934845930@example.com",
"password": "$2b$10$9AAsvzxfwNp9haLU2oKNMuMTeY3icNBzPYcPHTx3Wv4w78ZUVD7Ry"
},
{
"email": "testuser2-1780133113736@example.com",
"password": "$2b$10$JHamUog0/4MOtnc.la59ZuhhYZy/hxG5BSSVJjyVFW3.SYieaeHGu"
},
{
"email": "testuser-1780133179622@example.com",
"password": "$2b$10$C3zvUpwQMBS7YQhGnyO7TOq5Mo/9rrxgj2n/mN7PnfbSqcYfz0Lte"
},
{
"email": "testuser2-1780133179757@example.com",
"password": "$2b$10$Qae0TsUBvMMjZ0Ofog1B6uHp0GmV5hlbL1q6mVgFtUX6/STIJJliO"
"email": "testuser2-1780934846010@example.com",
"password": "$2b$10$6oXLfmhPAQzfCVLwS5iy/Oqoi5THfbxdKVMjxpWIB/29FwmLnPcTC"
}
]
[]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/data/users.json` around lines 1 - 10, Remove the committed user
credential entries from the runtime credential store file (src/data/users.json)
so that the app's signup/login flow in src/controllers/authController.js does
not seed real accounts; replace the committed objects with an empty array (or
move these test fixtures to a non-runtime test fixture file) and ensure any
tests or local dev scripts that relied on these sample users point to the new
fixture path or create users at runtime via the signup flow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Express or API gateway work docs Documentation only enhancement New feature or request feature A new feature or improvement fix A targeted fix or cleanup frontend Frontend-related work level:advanced question Further information is requested rag-service FastAPI / model service work type:security type:testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant