# 设计文档

## 概述

知识库系统是一个基于 Laravel Filament 3.X 构建的文档管理平台。系统采用 Laravel 的 MVC 架构模式，利用 Filament 的管理面板功能提供直观的中文用户界面。核心功能包括文档上传、分类管理、基于分组的权限控制、文档格式转换和全文搜索。

系统使用 Laravel 的 Eloquent ORM 进行数据库操作，利用 Filament 的资源（Resources）和表单构建器创建管理界面，通过策略（Policies）和作用域（Scopes）实现细粒度的权限控制。文档上传后自动转换为 Markdown 格式，并通过 Meilisearch 搜索引擎实现快速的全文搜索功能。用户可以在线预览 Markdown 渲染内容，也可以下载原始 Word 文档。

## 架构

### 技术栈
- **后端框架**: Laravel 10.x/11.x
- **管理面板**: Filament 3.X
- **数据库**: MySQL 8.0+ / PostgreSQL 13+
- **文件存储**: Laravel Storage (支持本地和云存储)
- **认证**: Laravel Breeze/Jetstream + Filament Auth
- **搜索引擎**: Meilisearch 1.5+
- **文档转换**: Pandoc 或 PHPWord
- **Markdown 渲染**: CommonMark PHP 或 Laravel Markdown
- **队列系统**: Redis Queue (用于异步文档转换)

### 架构模式
系统采用分层架构：

```
┌─────────────────────────────────────┐
│   Filament UI Layer (视图层)        │
│   - Resources                       │
│   - Forms & Tables                  │
│   - Actions & Filters               │
└─────────────────────────────────────┘
              ↓
┌─────────────────────────────────────┐
│   Application Layer (应用层)        │
│   - Controllers                     │
│   - Policies                        │
│   - Form Requests                   │
└─────────────────────────────────────┘
              ↓
┌─────────────────────────────────────┐
│   Domain Layer (领域层)             │
│   - Models                          │
│   - Services                        │
│   - Repositories (可选)             │
└─────────────────────────────────────┘
              ↓
┌─────────────────────────────────────┐
│   Infrastructure Layer (基础设施层)  │
│   - Database                        │
│   - File Storage                    │
│   - Cache                           │
└─────────────────────────────────────┘
```

## 组件和接口

### 核心模型

#### User (用户模型)
```php
class User extends Authenticatable
{
    // 关联关系
    public function groups(): BelongsToMany;
    public function uploadedDocuments(): HasMany;
    public function downloadLogs(): HasMany;
}
```

#### Group (分组模型)
```php
class Group extends Model
{
    // 关联关系
    public function users(): BelongsToMany;
    public function documents(): HasMany;
}
```

#### Document (文档模型)
```php
class Document extends Model
{
    use Searchable; // Laravel Scout trait for Meilisearch
    
    // 属性
    protected $fillable = [
        'title',
        'file_path',
        'file_name',
        'file_size',
        'mime_type',
        'type', // 'global' 或 'dedicated'
        'group_id',
        'uploaded_by',
        'description',
        'markdown_path', // Markdown 文件路径
        'markdown_preview', // Markdown 内容摘要
        'conversion_status' // 'pending', 'processing', 'completed', 'failed'
    ];
    
    // 关联关系
    public function group(): BelongsTo;
    public function uploader(): BelongsTo;
    public function downloadLogs(): HasMany;
    
    // 作用域
    public function scopeAccessibleBy(Builder $query, User $user): Builder;
    public function scopeGlobal(Builder $query): Builder;
    public function scopeDedicated(Builder $query): Builder;
    
    // Meilisearch 配置
    public function toSearchableArray(): array;
    public function shouldBeSearchable(): bool;
    
    // 辅助方法
    public function getMarkdownContent(): ?string; // 从文件读取完整 Markdown 内容
    public function hasMarkdown(): bool; // 检查是否已转换
}
```

#### DownloadLog (下载日志模型)
```php
class DownloadLog extends Model
{
    protected $fillable = [
        'document_id',
        'user_id',
        'downloaded_at',
        'ip_address'
    ];
    
    public function document(): BelongsTo;
    public function user(): BelongsTo;
}
```

### Filament 资源

#### DocumentResource
负责文档的 CRUD 操作界面：
- 列表页：显示文档列表，支持搜索和筛选
- 创建页：上传文档并设置分类
- 编辑页：修改文档信息和分类
- 查看页：查看文档详情和下载

#### GroupResource
负责分组管理界面：
- 列表页：显示所有分组
- 创建页：创建新分组
- 编辑页：编辑分组信息和成员
- 关系管理器：管理分组成员和文档

#### UserResource
负责用户管理界面：
- 列表页：显示所有用户
- 编辑页：编辑用户信息和分组归属
- 关系管理器：管理用户的分组关系

### 服务类

#### DocumentService
```php
class DocumentService
{
    public function uploadDocument(
        UploadedFile $file,
        string $title,
        string $type,
        ?int $groupId,
        int $uploaderId
    ): Document;
    
    public function validateDocumentAccess(Document $document, User $user): bool;
    
    public function downloadDocument(Document $document, User $user): StreamedResponse;
    
    public function logDownload(Document $document, User $user): void;
}
```

#### DocumentConversionService
```php
class DocumentConversionService
{
    public function convertToMarkdown(Document $document): string;
    
    public function queueConversion(Document $document): void;
    
    public function saveMarkdownToFile(Document $document, string $markdown): string; // 返回文件路径
    
    public function updateDocumentMarkdown(Document $document, string $markdownPath): void;
    
    public function handleConversionFailure(Document $document, Exception $e): void;
    
    public function getMarkdownPreview(string $markdown, int $length = 500): string;
}
```

#### DocumentSearchService
```php
class DocumentSearchService
{
    public function search(string $query, User $user, array $filters = []): Collection;
    
    public function indexDocument(Document $document): void; // 读取 Markdown 文件并索引
    
    public function updateDocumentIndex(Document $document): void;
    
    public function removeDocumentFromIndex(Document $document): void;
    
    public function filterByUserPermissions(Collection $results, User $user): Collection;
    
    public function prepareSearchableData(Document $document): array; // 准备索引数据，包含完整 Markdown 内容
}
```

#### MarkdownRenderService
```php
class MarkdownRenderService
{
    public function render(string $markdown): string;
    
    public function sanitize(string $html): string;
    
    public function extractPreview(string $markdown, int $length = 200): string;
}
```

### 策略类

#### DocumentPolicy
```php
class DocumentPolicy
{
    public function viewAny(User $user): bool;
    public function view(User $user, Document $document): bool;
    public function create(User $user): bool;
    public function update(User $user, Document $document): bool;
    public function delete(User $user, Document $document): bool;
    public function download(User $user, Document $document): bool;
}
```

## 数据模型

### 数据库表结构

#### users 表
```sql
- id: bigint (主键)
- name: varchar(255)
- email: varchar(255) (唯一)
- password: varchar(255)
- created_at: timestamp
- updated_at: timestamp
```

#### groups 表
```sql
- id: bigint (主键)
- name: varchar(255)
- description: text (可空)
- created_at: timestamp
- updated_at: timestamp
```

#### group_user 表 (多对多中间表)
```sql
- id: bigint (主键)
- group_id: bigint (外键)
- user_id: bigint (外键)
- created_at: timestamp
- updated_at: timestamp
- 唯一索引: (group_id, user_id)
```

#### documents 表
```sql
- id: bigint (主键)
- title: varchar(255)
- description: text (可空)
- file_path: varchar(500) -- 原始 Word 文档路径
- file_name: varchar(255)
- file_size: bigint
- mime_type: varchar(100)
- type: enum('global', 'dedicated')
- group_id: bigint (外键, 可空)
- uploaded_by: bigint (外键)
- markdown_path: varchar(500) (可空) -- Markdown 文件存储路径
- markdown_preview: text (可空) -- Markdown 内容摘要（前 500 字符），用于快速预览
- conversion_status: enum('pending', 'processing', 'completed', 'failed') -- 转换状态
- conversion_error: text (可空) -- 转换失败时的错误信息
- created_at: timestamp
- updated_at: timestamp
- 索引: type, group_id, uploaded_by, conversion_status
```

**存储策略说明**：
- 原始 Word 文档存储在 `storage/app/private/documents/` 目录
- 转换后的 Markdown 文件存储在 `storage/app/private/markdown/` 目录
- 数据库中只保存文件路径和内容摘要
- Meilisearch 索引包含完整的 Markdown 内容用于搜索
- 这种设计减少数据库体积，同时保持搜索性能

#### download_logs 表
```sql
- id: bigint (主键)
- document_id: bigint (外键)
- user_id: bigint (外键)
- ip_address: varchar(45)
- downloaded_at: timestamp
- 索引: document_id, user_id, downloaded_at
```

### 实体关系图

```mermaid
erDiagram
    User ||--o{ Document : uploads
    User }o--o{ Group : belongs_to
    Group ||--o{ Document : owns
    Document ||--o{ DownloadLog : has
    User ||--o{ DownloadLog : creates
    
    User {
        bigint id PK
        string name
        string email UK
        string password
        timestamp created_at
        timestamp updated_at
    }
    
    Group {
        bigint id PK
        string name
        text description
        timestamp created_at
        timestamp updated_at
    }
    
    Document {
        bigint id PK
        string title
        text description
        string file_path
        string file_name
        bigint file_size
        string mime_type
        enum type
        bigint group_id FK
        bigint uploaded_by FK
        timestamp created_at
        timestamp updated_at
    }
    
    DownloadLog {
        bigint id PK
        bigint document_id FK
        bigint user_id FK
        string ip_address
        timestamp downloaded_at
    }
```

## 正确性属性


*属性是指在系统的所有有效执行中都应该成立的特征或行为——本质上是关于系统应该做什么的正式声明。属性作为人类可读规范和机器可验证正确性保证之间的桥梁。*

基于需求文档中的验收标准，我们识别出以下可测试的正确性属性：

### 属性 1：文件格式验证
*对于任何*上传的文件，系统应该正确识别其是否为有效的 Word 文档格式（.doc 或 .docx），并且只接受有效格式的文件
**验证需求：1.1, 1.4**

### 属性 2：文档存储完整性
*对于任何*成功上传的文档，系统应该将文件存储到指定位置，并在数据库中记录完整的元数据（标题、文件路径、文件大小、MIME 类型、上传者等）
**验证需求：1.2**

### 属性 3：上传事务一致性
*对于任何*文档上传操作，如果过程中发生错误，系统应该回滚所有更改，确保数据库记录和文件系统保持一致状态
**验证需求：1.5**

### 属性 4：专用文档必须关联分组
*对于任何*类型为"专用知识库"的文档，系统应该要求并验证其关联了有效的分组 ID
**验证需求：2.2**

### 属性 5：全局文档对所有用户可见
*对于任何*全局知识库文档和任何已认证用户，该用户应该能够查看和访问该文档
**验证需求：2.3**

### 属性 6：文档分类持久化
*对于任何*文档，当其分类信息（类型和分组）被保存后，从数据库查询应该返回相同的分类信息
**验证需求：2.4**

### 属性 7：用户文档列表权限过滤
*对于任何*用户，当查询其可访问的文档列表时，返回的结果应该只包含：(1) 所有全局知识库文档，以及 (2) 该用户所属分组的专用知识库文档
**验证需求：3.1, 3.2, 3.3**

### 属性 8：其他分组文档隔离
*对于任何*用户和任何不属于该用户分组的专用知识库文档，该文档不应该出现在用户的可访问文档列表中
**验证需求：3.4**

### 属性 9：有权限文档可下载
*对于任何*用户和该用户有权限访问的文档，系统应该允许用户成功下载该文档
**验证需求：4.1**

### 属性 10：无权限文档访问拒绝
*对于任何*用户和该用户无权限访问的文档（其他分组的专用文档），系统应该拒绝访问请求
**验证需求：4.2**

### 属性 11：下载日志记录
*对于任何*文档下载操作，系统应该在 download_logs 表中创建一条记录，包含文档 ID、用户 ID、下载时间和 IP 地址
**验证需求：4.3**

### 属性 12：文档下载往返一致性
*对于任何*上传的文档，下载后的文件内容应该与原始上传的文件内容完全一致
**验证需求：4.4**

### 属性 13：分组数据持久化
*对于任何*新创建的分组，系统应该在数据库中保存分组名称和描述信息，并且查询应该返回相同的数据
**验证需求：5.1**

### 属性 14：用户分组关联
*对于任何*用户和分组，当用户被分配到该分组时，系统应该在 group_user 表中创建关联记录
**验证需求：5.2**

### 属性 15：分组分配授予权限
*对于任何*用户，当该用户被分配到某个分组后，该用户应该能够访问该分组的所有专用知识库文档
**验证需求：5.3**

### 属性 16：分组移除撤销权限
*对于任何*用户，当该用户从某个分组中移除后，该用户应该无法再访问该分组的专用知识库文档
**验证需求：5.4**

### 属性 17：分组删除级联处理
*对于任何*分组，当该分组被删除时，系统应该正确处理该分组的专用文档（设置为孤立状态或重新分配）
**验证需求：5.5**

### 属性 18：关键词搜索匹配
*对于任何*搜索关键词，系统返回的文档列表应该只包含标题或描述中包含该关键词的文档
**验证需求：6.1**

### 属性 19：分类筛选准确性
*对于任何*选定的文档分类（全局或专用），系统返回的文档列表应该只包含该分类的文档
**验证需求：6.2**

### 属性 20：分组筛选准确性
*对于任何*选定的分组，系统返回的文档列表应该只包含属于该分组的专用文档
**验证需求：6.3**

### 属性 21：组合筛选交集
*对于任何*多个筛选条件的组合（如分类 + 分组 + 关键词），系统返回的文档应该同时满足所有筛选条件
**验证需求：6.5**

### 属性 22：权限检查验证用户和分组
*对于任何*文档访问请求，系统应该验证请求用户的身份和该用户的分组归属
**验证需求：7.1**

### 属性 23：数据返回前权限验证
*对于任何*文档查询操作，系统应该在返回数据前执行权限检查，确保用户有权访问
**验证需求：7.2**

### 属性 24：未授权访问日志记录
*对于任何*权限验证失败的访问尝试，系统应该在安全日志中记录该事件
**验证需求：7.3**

### 属性 25：查询结果数据隔离
*对于任何*用户的文档查询，返回的结果集应该只包含该用户有权访问的文档，不包含其他用户的私有数据
**验证需求：7.4**

### 属性 26：错误消息中文化
*对于任何*系统操作产生的错误或成功消息，消息文本应该使用简体中文
**验证需求：8.3**

### 属性 27：日期格式中文化
*对于任何*需要显示的日期时间值，系统应该使用中文日期格式进行格式化
**验证需求：8.5**

### 属性 28：文档上传触发转换
*对于任何*成功上传的 Word 文档，系统应该自动触发 Markdown 转换流程
**验证需求：9.1**

### 属性 29：Markdown 内容持久化
*对于任何*转换完成的文档，系统应该将 Markdown 内容正确存储到文件系统，并在数据库中记录文件路径和内容摘要，读取文件应该返回相同的内容
**验证需求：9.2**

### 属性 30：转换失败不影响文档可用性
*对于任何*转换失败的文档，系统应该记录错误信息，但文档记录应该保持有效状态，用户仍然可以下载原始文件
**验证需求：9.3**

### 属性 31：原始文档保留
*对于任何*转换成功的文档，原始 Word 文件应该仍然存在于文件系统中，并且可以被下载
**验证需求：9.4**

### 属性 32：文档更新重新转换
*对于任何*已存在的文档，当其被更新或重新上传时，系统应该重新执行转换流程，并且新的 Markdown 内容应该替换旧内容
**验证需求：9.5**

### 属性 33：搜索匹配 Markdown 内容
*对于任何*包含特定关键词的文档 Markdown 内容，使用该关键词搜索应该返回该文档（假设用户有权限）
**验证需求：10.1**

### 属性 34：搜索覆盖多个字段
*对于任何*关键词，如果该关键词出现在文档的标题、描述或 Markdown 内容中的任何一个字段，搜索应该返回该文档
**验证需求：10.2**

### 属性 35：搜索结果权限过滤
*对于任何*搜索查询和用户，返回的搜索结果应该只包含该用户有权限访问的文档（全局文档和用户分组的专用文档）
**验证需求：10.3**

### 属性 36：搜索结果包含必需信息
*对于任何*搜索结果项，应该包含文档标题、内容片段、文档类型和上传时间等信息
**验证需求：10.4**

### 属性 37：有权限文档可预览
*对于任何*用户有权限访问的文档，该用户应该能够获取该文档的 Markdown 渲染后的 HTML 内容
**验证需求：11.1**

### 属性 38：Markdown 渲染正确性
*对于任何*包含标准 Markdown 元素（标题、列表、表格等）的 Markdown 内容，渲染后的 HTML 应该正确表示这些元素
**验证需求：11.2**

### 属性 39：无权限文档预览拒绝
*对于任何*用户无权限访问的文档，该用户尝试预览时应该被拒绝访问
**验证需求：11.3**

### 属性 40：转换完成触发索引
*对于任何*Markdown 转换完成的文档，系统应该自动将该文档索引到 Meilisearch
**验证需求：12.1**

### 属性 41：索引数据完整性
*对于任何*索引到 Meilisearch 的文档，索引数据应该包含文档 ID、标题、描述、Markdown 内容、类型和分组 ID
**验证需求：12.2**

### 属性 42：文档更新同步索引
*对于任何*已索引的文档，当文档被更新时，Meilisearch 中的索引数据应该同步更新
**验证需求：12.3**

### 属性 43：文档删除移除索引
*对于任何*已索引的文档，当文档被删除时，该文档应该从 Meilisearch 索引中移除
**验证需求：12.4**

### 属性 44：索引失败不影响文档保存
*对于任何*文档，即使 Meilisearch 索引操作失败，文档仍应该成功保存到数据库，并且可以正常使用
**验证需求：12.5**

## 错误处理

### 文件上传错误
- **无效文件格式**: 返回 422 状态码，提示"文件格式不支持，请上传 Word 文档（.doc 或 .docx）"
- **文件过大**: 返回 413 状态码，提示"文件大小超过限制（最大 XX MB）"
- **存储失败**: 返回 500 状态码，提示"文件上传失败，请稍后重试"，并回滚数据库操作

### 权限错误
- **未认证访问**: 返回 401 状态码，重定向到登录页面
- **无权限访问**: 返回 403 状态码，提示"您没有权限访问此文档"
- **文档不存在**: 返回 404 状态码，提示"文档不存在或已被删除"

### 数据验证错误
- **必填字段缺失**: 返回 422 状态码，提示具体缺失的字段
- **专用文档未指定分组**: 返回 422 状态码，提示"专用知识库文档必须指定所属分组"
- **无效的分组 ID**: 返回 422 状态码，提示"指定的分组不存在"

### 数据库错误
- **外键约束失败**: 返回 500 状态码，记录错误日志，提示"操作失败，请联系管理员"
- **唯一约束冲突**: 返回 422 状态码，提示"该记录已存在"
- **连接超时**: 返回 503 状态码，提示"服务暂时不可用，请稍后重试"

### 文档转换错误
- **转换工具不可用**: 返回 500 状态码，记录错误日志，文档状态设置为 'failed'
- **Word 文档损坏**: 返回 422 状态码，提示"文档文件损坏，无法转换"
- **转换超时**: 记录错误日志，文档状态设置为 'failed'，提示"文档转换超时，请稍后重试"
- **Markdown 内容过大**: 记录警告日志，截断内容或使用外部存储

### 搜索相关错误
- **Meilisearch 服务不可用**: 返回 503 状态码，提示"搜索服务暂时不可用，请稍后重试"
- **搜索查询语法错误**: 返回 400 状态码，提示"搜索关键词格式不正确"
- **索引操作失败**: 记录错误日志，不影响文档的正常保存和使用
- **搜索超时**: 返回 504 状态码，提示"搜索请求超时，请简化搜索条件"

### 预览相关错误
- **Markdown 内容为空**: 返回 200 状态码，显示提示信息和下载按钮
- **Markdown 渲染失败**: 返回 500 状态码，提示"内容渲染失败，请下载原始文档"
- **预览权限不足**: 返回 403 状态码，提示"您没有权限预览此文档"

### 错误处理策略
1. **用户友好的错误消息**: 所有错误消息使用简体中文，避免技术术语
2. **详细的日志记录**: 在服务器端记录完整的错误堆栈和上下文信息
3. **事务回滚**: 对于涉及多个操作的流程，确保失败时完全回滚
4. **安全考虑**: 不在错误消息中暴露敏感信息（如数据库结构、文件路径等）
5. **优雅降级**: 转换或搜索功能失败时，不影响文档的基本上传和下载功能
6. **异步重试**: 对于转换和索引失败的文档，支持后台重试机制

## 测试策略

### 单元测试
使用 PHPUnit 进行单元测试，覆盖以下组件：

1. **模型测试**
   - 测试模型关联关系是否正确定义
   - 测试作用域（Scopes）逻辑
   - 测试模型验证规则

2. **服务类测试**
   - 测试 DocumentService 的文档上传逻辑
   - 测试权限验证逻辑
   - 测试文件存储和检索

3. **策略测试**
   - 测试 DocumentPolicy 的各种权限判断
   - 测试边缘情况（如文档无分组、用户无分组等）

4. **表单请求测试**
   - 测试验证规则是否正确
   - 测试自定义验证逻辑

### 属性基础测试（Property-Based Testing）
使用 **Pest PHP** 的属性测试功能进行属性基础测试。每个属性测试应该：

- 配置为运行至少 **100 次迭代**
- 使用注释明确标注对应的设计文档中的正确性属性
- 标注格式：`// Feature: knowledge-base-system, Property X: [属性描述]`
- 每个正确性属性对应一个独立的属性测试

属性测试覆盖范围：
1. **文件格式验证属性**（属性 1）
2. **文档存储完整性属性**（属性 2）
3. **事务一致性属性**（属性 3）
4. **权限过滤属性**（属性 7, 8）
5. **往返一致性属性**（属性 12）
6. **权限授予和撤销属性**（属性 15, 16）
7. **搜索和筛选属性**（属性 18-21）
8. **数据隔离属性**（属性 25）
9. **文档转换属性**（属性 28-32）
10. **全文搜索属性**（属性 33-36）
11. **Markdown 预览属性**（属性 37-39）
12. **Meilisearch 索引属性**（属性 40-44）

### 功能测试
使用 Laravel 的功能测试框架测试完整的用户流程：

1. **文档上传流程**
   - 管理员上传全局文档
   - 管理员上传专用文档并指定分组
   - 上传无效格式文件被拒绝

2. **权限控制流程**
   - 用户查看自己分组的专用文档
   - 用户无法查看其他分组的专用文档
   - 用户可以查看所有全局文档

3. **分组管理流程**
   - 创建分组并分配用户
   - 用户从分组移除后失去权限
   - 删除分组后文档状态正确处理

4. **搜索和筛选流程**
   - 按关键词搜索文档
   - 按分类筛选文档
   - 组合多个筛选条件

5. **文档转换流程**
   - 上传 Word 文档后自动触发转换
   - 转换完成后 Markdown 内容正确存储
   - 转换失败时文档仍然可用
   - 更新文档时重新转换

6. **全文搜索流程**
   - 搜索 Markdown 内容中的关键词
   - 搜索结果遵循权限控制
   - 搜索结果包含内容片段
   - 空搜索关键词的处理

7. **文档预览流程**
   - 有权限用户可以预览 Markdown 内容
   - 无权限用户无法预览
   - Markdown 正确渲染为 HTML
   - 预览页面提供下载按钮

8. **Meilisearch 索引流程**
   - 文档转换后自动索引
   - 文档更新时同步索引
   - 文档删除时移除索引
   - 索引失败不影响文档保存

### 测试数据生成
使用 Laravel Factories 生成测试数据：

```php
// UserFactory - 生成随机用户
// GroupFactory - 生成随机分组
// DocumentFactory - 生成随机文档（包括全局和专用）
// 使用 Faker 生成随机的中文文本
```

### 测试覆盖率目标
- 代码覆盖率：≥ 80%
- 关键业务逻辑覆盖率：≥ 95%
- 所有正确性属性都有对应的属性测试

### 持续集成
- 在 CI/CD 管道中自动运行所有测试
- 测试失败时阻止代码合并
- 生成测试覆盖率报告

## 性能考虑

### 数据库优化
1. **索引策略**
   - documents 表：在 type, group_id, uploaded_by 字段上创建索引
   - download_logs 表：在 document_id, user_id, downloaded_at 上创建索引
   - 在 group_user 表的 (group_id, user_id) 上创建唯一复合索引

2. **查询优化**
   - 使用 Eager Loading 避免 N+1 查询问题
   - 对文档列表查询使用分页
   - 使用数据库视图或查询作用域简化复杂权限查询

3. **缓存策略**
   - 缓存用户的分组信息（TTL: 1小时）
   - 缓存文档元数据（TTL: 30分钟）
   - 使用 Redis 存储会话和缓存数据

### 文件存储优化
1. **存储策略**
   - 使用 Laravel Storage 抽象层，支持本地和云存储切换
   - 按日期组织文件目录结构：`documents/YYYY/MM/DD/` 和 `markdown/YYYY/MM/DD/`
   - 使用 UUID 作为文件名避免冲突
   - Markdown 文件单独存储，便于管理和备份
   - 数据库中保存 Markdown 摘要（500 字符）用于快速预览

2. **大文件处理**
   - 配置合理的上传大小限制（建议 50MB）
   - 使用流式下载避免内存溢出
   - 使用队列异步处理文档转换
   - 大 Markdown 文件（> 1MB）分块读取和索引

3. **缓存策略**
   - 缓存已读取的 Markdown 内容（TTL: 1小时）
   - 缓存渲染后的 HTML（TTL: 30分钟）
   - 使用 Redis 存储热门文档的 Markdown 内容

### 并发控制
- 使用数据库事务确保数据一致性
- 对关键操作使用乐观锁或悲观锁
- 使用队列处理耗时操作（如文件处理、日志记录）

## 安全考虑

### 认证和授权
1. **认证机制**
   - 使用 Laravel Sanctum 或 Jetstream 提供认证
   - 实施会话超时机制
   - 支持记住我功能

2. **授权机制**
   - 使用 Laravel Policy 实现细粒度权限控制
   - 在控制器和 Filament 资源中强制执行策略
   - 使用 Gate 定义全局权限规则

### 数据安全
1. **文件安全**
   - 文件存储在非公开目录
   - 通过控制器验证权限后提供文件下载
   - 验证文件 MIME 类型，防止恶意文件上传

2. **SQL 注入防护**
   - 使用 Eloquent ORM 和参数化查询
   - 避免使用原始 SQL 查询
   - 对用户输入进行验证和清理

3. **XSS 防护**
   - 使用 Blade 模板引擎自动转义输出
   - 对富文本内容使用 HTML Purifier
   - 设置适当的 Content Security Policy

### 审计日志
1. **操作日志**
   - 记录所有文档的创建、修改、删除操作
   - 记录用户的登录、登出活动
   - 记录权限变更操作

2. **安全日志**
   - 记录所有权限验证失败的尝试
   - 记录异常的访问模式
   - 定期审查安全日志

## 部署和配置

### 环境要求
- PHP 8.1+
- MySQL 8.0+ 或 PostgreSQL 13+
- Redis 6.0+（用于缓存和队列）
- Composer 2.x
- Node.js 18+ 和 npm（用于前端资源编译）
- Meilisearch 1.5+（搜索引擎服务）
- Pandoc 2.x+（用于文档转换，可选）或 PHPWord 库

### Filament 配置
1. **中文化配置**
```php
// config/app.php
'locale' => 'zh_CN',
'fallback_locale' => 'zh_CN',

// 安装 Filament 中文语言包
composer require filament/filament-zh-cn
```

2. **面板配置**
```php
// app/Providers/Filament/AdminPanelProvider.php
public function panel(Panel $panel): Panel
{
    return $panel
        ->default()
        ->id('admin')
        ->path('admin')
        ->login()
        ->colors([
            'primary' => Color::Blue,
        ])
        ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
        ->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
        ->pages([])
        ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
        ->widgets([])
        ->middleware([
            EncryptCookies::class,
            AddQueuedCookiesToResponse::class,
            StartSession::class,
            AuthenticateSession::class,
            ShareErrorsFromSession::class,
            VerifyCsrfToken::class,
            SubstituteBindings::class,
            DisableBladeIconComponents::class,
            DispatchServingFilamentEvent::class,
        ])
        ->authMiddleware([
            Authenticate::class,
        ]);
}
```

### 文件存储配置
```php
// config/filesystems.php
'disks' => [
    'documents' => [
        'driver' => 'local',
        'root' => storage_path('app/private/documents'),
        'visibility' => 'private',
    ],
    'markdown' => [
        'driver' => 'local',
        'root' => storage_path('app/private/markdown'),
        'visibility' => 'private',
    ],
],
```

**文件组织结构**：
```
storage/app/private/
├── documents/           # 原始 Word 文档
│   └── YYYY/MM/DD/
│       └── {uuid}.docx
└── markdown/            # 转换后的 Markdown 文件
    └── YYYY/MM/DD/
        └── {uuid}.md
```

### 队列配置
```php
// .env
QUEUE_CONNECTION=redis

// 启动队列工作进程
php artisan queue:work --queue=default,documents
```

### Meilisearch 配置
```php
// .env
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=your-master-key
SCOUT_DRIVER=meilisearch

// config/scout.php
'meilisearch' => [
    'host' => env('MEILISEARCH_HOST', 'http://127.0.0.1:7700'),
    'key' => env('MEILISEARCH_KEY'),
    'index-settings' => [
        'documents' => [
            'filterableAttributes' => ['type', 'group_id', 'uploaded_by'],
            'sortableAttributes' => ['created_at', 'title'],
            'searchableAttributes' => ['title', 'description', 'markdown_content'],
        ],
    ],
],

// 启动 Meilisearch 服务
meilisearch --master-key="your-master-key"
```

### 文档转换配置
```php
// .env
DOCUMENT_CONVERSION_DRIVER=pandoc  // 或 phpword
PANDOC_PATH=/usr/local/bin/pandoc
CONVERSION_TIMEOUT=300  // 秒

// config/documents.php
return [
    'conversion' => [
        'driver' => env('DOCUMENT_CONVERSION_DRIVER', 'pandoc'),
        'pandoc_path' => env('PANDOC_PATH', '/usr/bin/pandoc'),
        'timeout' => env('CONVERSION_TIMEOUT', 300),
        'queue' => 'documents',
    ],
    'markdown' => [
        'renderer' => 'commonmark',  // 或 'parsedown'
        'sanitize' => true,
    ],
];
```

## 扩展性考虑

### 未来功能扩展
1. **文档版本控制**
   - 支持文档多版本管理
   - 版本比较和回滚功能
   - 保留每个版本的 Markdown 内容

2. **增强的文档转换**
   - 支持更多文档格式（PDF、Excel、PPT）
   - 保留文档中的图片和格式
   - 支持 OCR 识别扫描文档

3. **高级搜索功能**
   - 支持搜索语法（AND、OR、NOT）
   - 按日期范围筛选
   - 搜索结果高亮显示
   - 搜索建议和自动补全

4. **文档标签系统**
   - 为文档添加多个标签
   - 按标签筛选和搜索
   - 标签云展示

5. **文档评论和协作**
   - 用户可以对文档添加评论
   - 支持文档收藏和分享
   - 文档阅读统计

6. **AI 增强功能**
   - 文档内容摘要生成
   - 智能问答（基于文档内容）
   - 相关文档推荐

### 架构扩展性
1. **微服务化**
   - 文档存储服务可以独立部署
   - 使用消息队列解耦服务

2. **多租户支持**
   - 支持多个组织独立使用系统
   - 数据完全隔离

3. **API 接口**
   - 提供 RESTful API
   - 支持第三方系统集成

## 总结

本设计文档详细描述了基于 Laravel Filament 3.X 的知识库系统的架构、组件、数据模型和正确性属性。系统采用分层架构，通过 Eloquent ORM 和 Filament 资源实现数据管理，使用策略和作用域实现细粒度的权限控制。系统集成了文档格式转换和 Meilisearch 全文搜索功能，提供强大的文档管理和检索能力。

关键设计决策包括：
1. 使用枚举类型区分全局和专用知识库
2. 通过多对多关系管理用户和分组
3. 使用查询作用域实现权限过滤
4. 采用属性基础测试验证核心业务逻辑
5. 全面的中文化支持
6. 异步队列处理文档转换，避免阻塞用户操作
7. 使用 Meilisearch 实现快速全文搜索，搜索结果遵循权限控制
8. Markdown 格式存储支持在线预览和内容检索
9. 优雅降级策略，转换或搜索失败不影响核心功能

系统设计充分考虑了安全性、性能和可扩展性，为后续的实施提供了清晰的指导。文档转换和搜索功能的引入大大提升了知识库的可用性和检索效率。
