feat: 初始化知识库系统项目

- 实现基于 Laravel 11 和 Filament 3.X 的文档管理系统
- 添加用户认证和分组管理功能
- 实现文档上传、分类和权限控制
- 集成 Word 文档自动转换为 Markdown
- 集成 Meilisearch 全文搜索引擎
- 实现文档在线预览功能
- 添加安全日志和审计功能
- 完整的简体中文界面
- 包含完整的项目文档和部署指南

技术栈:
- Laravel 11.x
- Filament 3.X
- Meilisearch 1.5+
- Pandoc 文档转换
- Redis 队列系统
- Pest PHP 测试框架
This commit is contained in:
Knowledge Base System
2025-12-05 14:44:44 +08:00
commit acf549c43c
165 changed files with 32838 additions and 0 deletions

View File

@@ -0,0 +1,192 @@
# 文档搜索功能指南
## 概述
文档搜索功能使用 Laravel Scout 和 Meilisearch 提供强大的全文搜索能力。系统会自动将转换完成的文档索引到 Meilisearch用户可以通过关键词快速检索文档内容。
## 核心组件
### DocumentSearchService
文档搜索服务类,提供以下功能:
1. **search()** - 执行全文搜索
- 搜索文档标题、描述和 Markdown 内容
- 支持额外的筛选条件(类型、分组、上传者)
- 自动应用用户权限过滤
2. **filterByUserPermissions()** - 权限过滤
- 确保用户只能看到有权限访问的文档
- 全局文档对所有用户可见
- 专用文档只对所属分组的用户可见
3. **prepareSearchableData()** - 准备索引数据
- 包含完整的 Markdown 内容用于搜索
- 包含文档元数据(标题、描述、类型、分组等)
4. **indexDocument()** - 索引文档
- 将文档添加到 Meilisearch 索引
- 只索引转换完成的文档
5. **updateDocumentIndex()** - 更新索引
- 更新已索引文档的信息
- 如果文档不应被索引,则移除索引
6. **removeDocumentFromIndex()** - 移除索引
- 从 Meilisearch 中删除文档索引
### DocumentObserver
文档观察者,自动管理文档的搜索索引:
- **created** - 文档创建时不立即索引(等待转换完成)
- **updated** - 文档更新时检查转换状态并更新索引
- 当 conversion_status 变为 'completed' 时自动索引
- 当其他重要字段更新时也更新索引
- **deleted** - 文档删除时移除索引
- **restored** - 文档恢复时重新索引
- **forceDeleted** - 强制删除时移除索引
## 工作流程
### 文档索引流程
1. 用户上传 Word 文档
2. 文档保存到数据库conversion_status 设置为 'pending'
3. 转换任务加入队列
4. 转换完成后updateDocumentMarkdown() 将 conversion_status 更新为 'completed'
5. DocumentObserver 监听到 updated 事件
6. 自动调用 DocumentSearchService::indexDocument() 创建索引
7. 文档可以被搜索
### 搜索流程
1. 用户输入搜索关键词
2. 调用 DocumentSearchService::search()
3. 使用 Scout 在 Meilisearch 中搜索
4. 应用额外的筛选条件
5. 使用 filterByUserPermissions() 过滤结果
6. 返回用户有权限访问的文档列表
## 配置
### Meilisearch 配置
`config/scout.php` 中配置:
```php
'meilisearch' => [
'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'),
'key' => env('MEILISEARCH_KEY'),
'index-settings' => [
'documents' => [
'filterableAttributes' => ['type', 'group_id', 'uploaded_by', 'conversion_status'],
'sortableAttributes' => ['created_at', 'title', 'updated_at'],
'searchableAttributes' => ['title', 'description', 'markdown_content'],
],
],
],
```
### 环境变量
`.env` 文件中配置:
```env
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=your-master-key
```
## 使用示例
### 基本搜索
```php
use App\Services\DocumentSearchService;
$searchService = app(DocumentSearchService::class);
$user = auth()->user();
// 搜索关键词
$results = $searchService->search('Laravel', $user);
// 带筛选条件的搜索
$results = $searchService->search('Laravel', $user, [
'type' => 'global',
'group_id' => 1,
]);
```
### 手动索引管理
```php
use App\Services\DocumentSearchService;
use App\Models\Document;
$searchService = app(DocumentSearchService::class);
$document = Document::find(1);
// 索引文档
$searchService->indexDocument($document);
// 更新索引
$searchService->updateDocumentIndex($document);
// 移除索引
$searchService->removeDocumentFromIndex($document);
```
### 批量重建索引
```php
// 重建所有文档的索引
php artisan scout:import "App\Models\Document"
// 清空索引
php artisan scout:flush "App\Models\Document"
```
## 错误处理
所有索引操作都包含错误处理:
- 索引失败不会影响文档的正常保存和使用
- 所有错误都会记录到日志中
- 搜索失败时返回空集合
## 性能考虑
1. **异步索引** - 文档转换和索引都在队列中异步处理
2. **权限过滤** - 在应用层过滤搜索结果,确保数据安全
3. **缓存策略** - 可以缓存热门搜索结果(待实现)
4. **分页** - 搜索结果应该分页显示(在前端实现)
## 故障排查
### 文档无法被搜索
1. 检查 conversion_status 是否为 'completed'
2. 检查 Meilisearch 服务是否运行
3. 检查文档是否已索引:`php artisan scout:import "App\Models\Document"`
4. 查看日志文件中的错误信息
### Meilisearch 连接失败
1. 确认 Meilisearch 服务正在运行
2. 检查 .env 中的 MEILISEARCH_HOST 和 MEILISEARCH_KEY
3. 测试连接:`curl http://localhost:7700/health`
### 搜索结果为空
1. 确认文档已完成转换
2. 确认用户有权限访问文档
3. 检查搜索关键词是否正确
4. 查看 Meilisearch 日志
## 下一步
- 实现搜索页面 UI任务 25
- 添加搜索结果高亮显示
- 实现搜索建议和自动补全
- 添加高级搜索语法支持