Files
aurak/docs/system-overview.html
Developer 0a9588abb7 feat: implement QuestionBank CRUD with pagination and template query
- Add pagination support to findAll (page, limit query params)
- Add findByTemplateId method to service
- Add GET /by-template/:templateId endpoint to controller
- Service already includes CRUD for QuestionBank and QuestionBankItem
2026-04-23 17:19:11 +08:00

782 lines
27 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple Knowledge Base - System Overview</title>
<style>
:root {
--primary: #6366f1;
--primary-light: #818cf8;
--primary-dark: #4f46e5;
--bg: #0f172a;
--bg-card: #1e293b;
--bg-code: #0d1117;
--text: #e2e8f0;
--text-muted: #94a3b8;
--border: #334155;
--accent-green: #34d399;
--accent-blue: #38bdf8;
--accent-orange: #fb923c;
--accent-pink: #f472b6;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans SC', sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.7;
}
.hero {
background: linear-gradient(135deg, #1e1b4b 0%, #312e81 30%, #0f172a 70%, #0c0a09 100%);
padding: 80px 20px 60px;
text-align: center;
position: relative;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle at 30% 50%, rgba(99, 102, 241, 0.15) 0%, transparent 50%),
radial-gradient(circle at 70% 50%, rgba(56, 189, 248, 0.1) 0%, transparent 50%);
animation: pulse 8s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 0.6; }
50% { opacity: 1; }
}
.hero h1 {
font-size: 2.8rem;
font-weight: 800;
background: linear-gradient(135deg, #c7d2fe, #818cf8, #38bdf8);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
position: relative;
margin-bottom: 12px;
}
.hero .subtitle {
font-size: 1.15rem;
color: var(--text-muted);
position: relative;
max-width: 700px;
margin: 0 auto;
}
.badge-row {
display: flex;
gap: 10px;
justify-content: center;
flex-wrap: wrap;
margin-top: 24px;
position: relative;
}
.badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 5px 14px;
border-radius: 999px;
font-size: 0.82rem;
font-weight: 600;
border: 1px solid;
}
.badge.react { color: #61dafb; border-color: #61dafb33; background: #61dafb10; }
.badge.nest { color: #e0234e; border-color: #e0234e33; background: #e0234e10; }
.badge.rag { color: var(--accent-green); border-color: #34d39933; background: #34d39910; }
.badge.ts { color: #3178c6; border-color: #3178c633; background: #3178c610; }
.container {
max-width: 1100px;
margin: 0 auto;
padding: 0 20px;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin: -40px auto 60px;
position: relative;
z-index: 1;
}
.feature-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 16px;
padding: 28px;
transition: transform 0.2s, border-color 0.2s;
}
.feature-card:hover {
transform: translateY(-3px);
border-color: var(--primary);
}
.feature-card .icon {
width: 44px;
height: 44px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.3rem;
margin-bottom: 16px;
}
.feature-card h3 {
font-size: 1.05rem;
margin-bottom: 8px;
color: #f1f5f9;
}
.feature-card p {
font-size: 0.9rem;
color: var(--text-muted);
}
.icon-blue { background: #38bdf818; }
.icon-green { background: #34d39918; }
.icon-orange { background: #fb923c18; }
.icon-pink { background: #f472b618; }
.icon-purple { background: #a78bfa18; }
.icon-yellow { background: #fbbf2418; }
section {
margin-bottom: 56px;
}
.section-title {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 24px;
padding-bottom: 12px;
border-bottom: 2px solid var(--border);
display: flex;
align-items: center;
gap: 10px;
}
.section-title .num {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border-radius: 8px;
background: var(--primary);
font-size: 0.85rem;
font-weight: 700;
flex-shrink: 0;
}
/* Architecture Diagram */
.arch-diagram {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 16px;
padding: 32px;
overflow-x: auto;
}
.arch-row {
display: flex;
justify-content: center;
gap: 16px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.arch-box {
padding: 14px 22px;
border-radius: 10px;
font-size: 0.85rem;
font-weight: 600;
text-align: center;
min-width: 140px;
border: 1px solid;
}
.arch-box.frontend { background: #61dafb12; border-color: #61dafb33; color: #61dafb; }
.arch-box.backend { background: #e0234e12; border-color: #e0234e33; color: #e0234e; }
.arch-box.infra { background: #34d39912; border-color: #34d39933; color: #34d399; }
.arch-box.ai { background: #a78bfa12; border-color: #a78bfa33; color: #a78bfa; }
.arch-box.data { background: #fb923c12; border-color: #fb923c33; color: #fb923c; }
.arch-arrow {
text-align: center;
color: var(--text-muted);
font-size: 1.2rem;
margin-bottom: 16px;
}
.arch-label {
text-align: center;
font-size: 0.78rem;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 1.5px;
margin-bottom: 10px;
}
/* File Tree */
.file-tree {
background: var(--bg-code);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px 28px;
font-family: 'Cascadia Code', 'Fira Code', monospace;
font-size: 0.85rem;
line-height: 1.9;
overflow-x: auto;
}
.file-tree .dir { color: var(--accent-blue); font-weight: 600; }
.file-tree .comment { color: #64748b; font-style: italic; }
.file-tree .file { color: var(--text); }
/* Pipeline */
.pipeline {
display: flex;
align-items: center;
gap: 0;
flex-wrap: wrap;
justify-content: center;
margin: 20px 0;
}
.pipeline-step {
padding: 12px 20px;
border-radius: 10px;
font-size: 0.85rem;
font-weight: 600;
text-align: center;
border: 1px solid var(--border);
background: var(--bg-card);
}
.pipeline-arrow {
color: var(--text-muted);
font-size: 1.1rem;
padding: 0 6px;
}
.pipeline-step.active {
border-color: var(--primary);
background: #6366f118;
color: var(--primary-light);
}
/* Tables */
.info-table {
width: 100%;
border-collapse: collapse;
margin: 12px 0;
}
.info-table th, .info-table td {
padding: 10px 16px;
text-align: left;
border-bottom: 1px solid var(--border);
font-size: 0.9rem;
}
.info-table th {
color: var(--text-muted);
font-weight: 600;
font-size: 0.82rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.info-table .port {
font-family: 'Cascadia Code', monospace;
color: var(--accent-orange);
font-weight: 600;
}
.info-table .env-key {
font-family: 'Cascadia Code', monospace;
color: var(--accent-green);
font-size: 0.83rem;
}
/* Code Block */
.code-block {
background: var(--bg-code);
border: 1px solid var(--border);
border-radius: 10px;
padding: 18px 22px;
font-family: 'Cascadia Code', 'Fira Code', monospace;
font-size: 0.83rem;
line-height: 1.8;
overflow-x: auto;
margin: 12px 0;
}
.code-block .cmd { color: var(--accent-green); }
.code-block .comment { color: #64748b; }
/* Two Column Layout */
.two-col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
}
@media (max-width: 768px) {
.two-col { grid-template-columns: 1fr; }
.hero h1 { font-size: 2rem; }
.features-grid { grid-template-columns: 1fr; }
}
.card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 14px;
padding: 24px;
}
.card h4 {
font-size: 1rem;
margin-bottom: 14px;
color: #f1f5f9;
}
.card ul {
list-style: none;
padding: 0;
}
.card ul li {
padding: 6px 0;
font-size: 0.88rem;
color: var(--text-muted);
display: flex;
align-items: flex-start;
gap: 8px;
}
.card ul li::before {
content: '';
color: var(--primary-light);
font-weight: 700;
flex-shrink: 0;
}
.step-list {
list-style: none;
padding: 0;
counter-reset: step;
}
.step-list li {
counter-increment: step;
padding: 8px 0;
font-size: 0.88rem;
color: var(--text-muted);
display: flex;
align-items: flex-start;
gap: 10px;
}
.step-list li::before {
content: counter(step);
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
border-radius: 6px;
background: var(--primary);
color: white;
font-size: 0.72rem;
font-weight: 700;
flex-shrink: 0;
}
.troubleshoot-item {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 10px;
padding: 16px 20px;
margin-bottom: 10px;
}
.troubleshoot-item strong {
color: #f1f5f9;
font-size: 0.92rem;
}
.troubleshoot-item p {
color: var(--text-muted);
font-size: 0.85rem;
margin-top: 4px;
}
footer {
text-align: center;
padding: 40px 20px;
color: var(--text-muted);
font-size: 0.82rem;
border-top: 1px solid var(--border);
}
</style>
</head>
<body>
<!-- Hero -->
<div class="hero">
<h1>Simple Knowledge Base</h1>
<p class="subtitle">Full-stack RAG Q&A System &mdash; Retrieval-Augmented Generation powered by React 19 + NestJS</p>
<div class="badge-row">
<span class="badge react">React 19</span>
<span class="badge nest">NestJS</span>
<span class="badge rag">RAG System</span>
<span class="badge ts">TypeScript</span>
</div>
</div>
<div class="container">
<!-- Key Features -->
<div class="features-grid">
<div class="feature-card">
<div class="icon icon-purple"> </div>
<h3>Multi-Model Support</h3>
<p>OpenAI-compatible APIs (OpenAI, DeepSeek, Claude) + Google Gemini native SDK with configurable LLM, Embedding, and Rerank models.</p>
</div>
<div class="feature-card">
<div class="icon icon-blue"></div>
<h3>Dual Processing Modes</h3>
<p>Fast Mode via Apache Tika for text extraction, and High-Precision Mode via Vision Pipeline for mixed image/text documents.</p>
</div>
<div class="feature-card">
<div class="icon icon-green"> </div>
<h3>Hybrid Search</h3>
<p>Vector + keyword search with Elasticsearch, source citation, similarity scoring, and configurable chunk size &amp; overlap.</p>
</div>
<div class="feature-card">
<div class="icon icon-orange"> </div>
<h3>User Isolation</h3>
<p>JWT authentication with per-user knowledge bases. Each user has isolated data and configurations.</p>
</div>
<div class="feature-card">
<div class="icon icon-pink"> </div>
<h3>Streaming Responses</h3>
<p>Real-time streaming via Server-Sent Events (SSE) for smooth, low-latency chat interactions.</p>
</div>
<div class="feature-card">
<div class="icon icon-yellow"> </div>
<h3>Multi-Language</h3>
<p>Interface supports Japanese, Chinese, and English with full internationalization for error and API response messages.</p>
</div>
</div>
<!-- Architecture -->
<section>
<h2 class="section-title"><span class="num">1</span> Architecture Overview</h2>
<div class="arch-diagram">
<div class="arch-label">Frontend Layer</div>
<div class="arch-row">
<div class="arch-box frontend">React 19 + Vite<br><small style="opacity:0.7">Port 13001 (dev) / 80 (prod)</small></div>
</div>
<div class="arch-arrow"></div>
<div class="arch-label">Backend Layer</div>
<div class="arch-row">
<div class="arch-box backend">NestJS API<br><small style="opacity:0.7">Port 3001</small></div>
<div class="arch-box backend">JWT Auth</div>
<div class="arch-box backend">Chat / RAG</div>
<div class="arch-box backend">Vision Pipeline</div>
</div>
<div class="arch-arrow"></div>
<div class="arch-label">AI &amp; Data Layer</div>
<div class="arch-row">
<div class="arch-box ai">OpenAI / Gemini<br><small style="opacity:0.7">LLM + Embedding</small></div>
<div class="arch-box infra">Elasticsearch<br><small style="opacity:0.7">Port 9200</small></div>
<div class="arch-box infra">Apache Tika<br><small style="opacity:0.7">Port 9998</small></div>
<div class="arch-box infra">LibreOffice<br><small style="opacity:0.7">Port 8100</small></div>
<div class="arch-box data">SQLite<br><small style="opacity:0.7">Metadata</small></div>
</div>
</div>
<!-- Processing Pipeline -->
<h4 style="margin-top:28px; margin-bottom:14px; color:#f1f5f9;">Dual Processing Pipeline</h4>
<div class="two-col">
<div class="card">
<h4>Fast Mode (Tika)</h4>
<div class="pipeline">
<div class="pipeline-step active">Upload</div>
<span class="pipeline-arrow"></span>
<div class="pipeline-step active">Tika Extract</div>
<span class="pipeline-arrow"></span>
<div class="pipeline-step active">Embed</div>
<span class="pipeline-arrow"></span>
<div class="pipeline-step active">Store</div>
</div>
<p style="font-size:0.85rem; color:var(--text-muted); text-align:center;">Quick text extraction, no API cost</p>
</div>
<div class="card">
<h4>High-Precision Mode (Vision)</h4>
<div class="pipeline">
<div class="pipeline-step active">Upload</div>
<span class="pipeline-arrow"></span>
<div class="pipeline-step">LibreOffice</div>
<span class="pipeline-arrow"></span>
<div class="pipeline-step">PDF→Image</div>
<span class="pipeline-arrow"></span>
<div class="pipeline-step">Vision Model</div>
</div>
<p style="font-size:0.85rem; color:var(--text-muted); text-align:center;">Preserves layout, charts, and images</p>
</div>
</div>
</section>
<!-- Project Structure -->
<section>
<h2 class="section-title"><span class="num">2</span> Project Structure</h2>
<div class="file-tree">
<span class="dir">simple-kb/</span><br>
├── <span class="dir">web/</span> <span class="comment"># React frontend (Vite)</span><br>
│ ├── <span class="dir">components/</span> <span class="comment"># UI components (ChatInterface, ConfigPanel, etc.)</span><br>
│ ├── <span class="dir">contexts/</span> <span class="comment"># React Context providers</span><br>
│ ├── <span class="dir">services/</span> <span class="comment"># API client services</span><br>
│ └── <span class="dir">utils/</span> <span class="comment"># Utility functions</span><br>
├── <span class="dir">server/</span> <span class="comment"># NestJS backend</span><br>
│ ├── <span class="dir">src/</span><br>
│ │ ├── <span class="dir">ai/</span> <span class="comment"># AI services (embedding, etc.)</span><br>
│ │ ├── <span class="dir">api/</span> <span class="comment"># API module</span><br>
│ │ ├── <span class="dir">auth/</span> <span class="comment"># JWT authentication</span><br>
│ │ ├── <span class="dir">chat/</span> <span class="comment"># Chat / RAG module</span><br>
│ │ ├── <span class="dir">elasticsearch/</span> <span class="comment"># Elasticsearch integration</span><br>
│ │ ├── <span class="dir">import-task/</span> <span class="comment"># Import task management</span><br>
│ │ ├── <span class="dir">knowledge-base/</span> <span class="comment"># Knowledge base management</span><br>
│ │ ├── <span class="dir">libreoffice/</span> <span class="comment"># LibreOffice integration</span><br>
│ │ ├── <span class="dir">model-config/</span> <span class="comment"># Model configuration management</span><br>
│ │ ├── <span class="dir">vision/</span> <span class="comment"># Vision model integration</span><br>
│ │ └── <span class="dir">vision-pipeline/</span> <span class="comment"># Vision pipeline orchestration</span><br>
│ ├── <span class="dir">data/</span> <span class="comment"># SQLite database storage</span><br>
│ ├── <span class="dir">uploads/</span> <span class="comment"># Uploaded files storage</span><br>
│ └── <span class="dir">temp/</span> <span class="comment"># Temporary files</span><br>
├── <span class="dir">docs/</span> <span class="comment"># Documentation (Japanese/Chinese)</span><br>
├── <span class="dir">nginx/</span> <span class="comment"># Nginx configuration</span><br>
├── <span class="dir">libreoffice-server/</span> <span class="comment"># LibreOffice conversion service (Python/FastAPI)</span><br>
└── <span class="file">docker-compose.yml</span> <span class="comment"># Docker orchestration</span>
</div>
</section>
<!-- Development Setup -->
<section>
<h2 class="section-title"><span class="num">3</span> Development Setup</h2>
<h4 style="margin-bottom:10px; color:#f1f5f9;">Prerequisites</h4>
<div class="card" style="margin-bottom:20px;">
<ul>
<li>Node.js 18+</li>
<li>Yarn package manager</li>
<li>Docker &amp; Docker Compose</li>
</ul>
</div>
<h4 style="margin-bottom:10px; color:#f1f5f9;">Quick Start</h4>
<div class="code-block">
<span class="comment"># Install dependencies</span><br>
<span class="cmd">yarn install</span><br><br>
<span class="comment"># Start infrastructure services</span><br>
<span class="cmd">docker-compose up -d elasticsearch tika libreoffice</span><br><br>
<span class="comment"># Configure environment</span><br>
<span class="cmd">cp server/.env.sample server/.env</span><br><br>
<span class="comment"># Start both frontend and backend</span><br>
<span class="cmd">yarn dev</span>
</div>
<h4 style="margin:20px 0 10px; color:#f1f5f9;">Development Commands</h4>
<div class="code-block">
<span class="comment"># Frontend only (port 13001)</span><br>
<span class="cmd">cd web && yarn dev</span><br><br>
<span class="comment"># Backend only (port 3001)</span><br>
<span class="cmd">cd server && yarn start:dev</span><br><br>
<span class="comment"># Run tests</span><br>
<span class="cmd">cd server && yarn test</span><br>
<span class="cmd">cd server && yarn test:e2e</span><br><br>
<span class="comment"># Lint and format</span><br>
<span class="cmd">cd server && yarn lint</span><br>
<span class="cmd">cd server && yarn format</span>
</div>
</section>
<!-- Docker Services -->
<section>
<h2 class="section-title"><span class="num">4</span> Docker Services &amp; Ports</h2>
<div class="card">
<table class="info-table">
<thead>
<tr><th>Service</th><th>Port</th><th>Purpose</th></tr>
</thead>
<tbody>
<tr><td>Elasticsearch</td><td class="port">9200</td><td>Vector storage &amp; hybrid search</td></tr>
<tr><td>Apache Tika</td><td class="port">9998</td><td>Document text extraction</td></tr>
<tr><td>LibreOffice Server</td><td class="port">8100</td><td>Document format conversion</td></tr>
<tr><td>Backend API</td><td class="port">3001</td><td>NestJS REST API</td></tr>
<tr><td>Frontend (dev)</td><td class="port">13001</td><td>Vite dev server</td></tr>
<tr><td>Frontend (prod)</td><td class="port">80 / 443</td><td>Nginx reverse proxy</td></tr>
</tbody>
</table>
</div>
</section>
<!-- Environment Configuration -->
<section>
<h2 class="section-title"><span class="num">5</span> Environment Configuration</h2>
<div class="card">
<p style="font-size:0.88rem; color:var(--text-muted); margin-bottom:14px;">Key environment variables in <code style="color:var(--accent-green); background:#0d1117; padding:2px 8px; border-radius:4px; font-size:0.83rem;">server/.env</code></p>
<table class="info-table">
<thead>
<tr><th>Variable</th><th>Default</th><th>Description</th></tr>
</thead>
<tbody>
<tr><td class="env-key">OPENAI_API_KEY</td><td>&mdash;</td><td>OpenAI-compatible API key</td></tr>
<tr><td class="env-key">GEMINI_API_KEY</td><td>&mdash;</td><td>Google Gemini API key</td></tr>
<tr><td class="env-key">ELASTICSEARCH_HOST</td><td>http://localhost:9200</td><td>Elasticsearch URL</td></tr>
<tr><td class="env-key">TIKA_HOST</td><td>http://localhost:9998</td><td>Apache Tika URL</td></tr>
<tr><td class="env-key">LIBREOFFICE_URL</td><td>http://localhost:8100</td><td>LibreOffice server URL</td></tr>
<tr><td class="env-key">JWT_SECRET</td><td>&mdash;</td><td>JWT signing secret</td></tr>
</tbody>
</table>
</div>
</section>
<!-- Code Standards -->
<section>
<h2 class="section-title"><span class="num">6</span> Code Standards</h2>
<div class="two-col">
<div class="card">
<h4>Language Requirements</h4>
<ul>
<li>Code comments must be in English</li>
<li>Log messages must be in English</li>
<li>Error messages must support internationalization</li>
<li>API response messages must support i18n</li>
<li>Interface supports Japanese, Chinese, and English</li>
</ul>
</div>
<div class="card">
<h4>Code Quality</h4>
<ul>
<li>Backend uses Jest for unit and e2e tests</li>
<li>ESLint and Prettier configured for backend</li>
<li>Format: <code style="color:var(--accent-green);">cd server && yarn format</code></li>
<li>Lint: <code style="color:var(--accent-green);">cd server && yarn lint</code></li>
</ul>
</div>
</div>
</section>
<!-- Common Tasks -->
<section>
<h2 class="section-title"><span class="num">7</span> Common Development Tasks</h2>
<div class="two-col">
<div class="card">
<h4>Adding a New API Endpoint</h4>
<ol class="step-list">
<li>Create controller in appropriate module under <code style="color:var(--accent-blue);">server/src/</code></li>
<li>Add service methods with English comments</li>
<li>Update DTOs and validation</li>
<li>Add tests in <code style="color:var(--accent-blue);">*.spec.ts</code> files</li>
</ol>
</div>
<div class="card">
<h4>Adding a New Frontend Component</h4>
<ol class="step-list">
<li>Create component in <code style="color:var(--accent-blue);">web/components/</code></li>
<li>Add TypeScript interfaces in <code style="color:var(--accent-blue);">web/types.ts</code></li>
<li>Use Tailwind CSS for styling</li>
<li>Connect to backend services in <code style="color:var(--accent-blue);">web/services/</code></li>
</ol>
</div>
</div>
</section>
<!-- Deployment -->
<section>
<h2 class="section-title"><span class="num">8</span> Deployment</h2>
<div class="two-col">
<div class="card">
<h4>Development</h4>
<div class="code-block">
<span class="cmd">docker-compose up -d elasticsearch tika libreoffice</span><br>
<span class="cmd">yarn dev</span>
</div>
</div>
<div class="card">
<h4>Production</h4>
<div class="code-block">
<span class="comment"># Build and start all services</span><br>
<span class="cmd">docker-compose up -d</span>
</div>
</div>
</div>
</section>
<!-- Troubleshooting -->
<section>
<h2 class="section-title"><span class="num">9</span> Troubleshooting</h2>
<div class="troubleshoot-item">
<strong>Elasticsearch not starting</strong>
<p>Check memory limits in docker-compose.yml</p>
</div>
<div class="troubleshoot-item">
<strong>File upload failures</strong>
<p>Ensure <code style="color:var(--accent-green);">uploads/</code> and <code style="color:var(--accent-green);">temp/</code> directories exist with proper permissions</p>
</div>
<div class="troubleshoot-item">
<strong>Vision pipeline errors</strong>
<p>Verify LibreOffice server is running and accessible at port 8100</p>
</div>
<div class="troubleshoot-item">
<strong>API key errors</strong>
<p>Check environment variables in <code style="color:var(--accent-green);">server/.env</code></p>
</div>
<div class="troubleshoot-item">
<strong>Database reset</strong>
<p>Delete <code style="color:var(--accent-green);">server/data/metadata.db</code> and Elasticsearch data volume</p>
</div>
</section>
<!-- Debugging -->
<section>
<h2 class="section-title"><span class="num">10</span> Debugging &amp; Health Checks</h2>
<div class="code-block">
<span class="comment"># Check Elasticsearch</span><br>
<span class="cmd">curl http://localhost:9200/_cat/indices</span><br><br>
<span class="comment"># Check Tika</span><br>
<span class="cmd">curl http://localhost:9998/tika</span><br><br>
<span class="comment"># Check LibreOffice</span><br>
<span class="cmd">curl http://localhost:8100/health</span>
</div>
</section>
</div>
<footer>
Simple Knowledge Base &mdash; Full-stack RAG Q&A System &mdash; React 19 + NestJS + Elasticsearch
</footer>
</body>
</html>