PRD:采购文件搜索服务
目录
项目概述
采购同事希望在 OpenClaw 中通过自然语言对话,快速从群晖文件服务器中找到对应文件,并通过钉钉等渠道发送给用户。
本项目提供一个采购文件搜索服务:在 Linux 或 macOS 环境中挂载群晖 SMB 共享目录,扫描文件名和文件夹名并建立 OpenClaw 服务器本地 SQLite/FTS 索引。用户搜索时,OpenClaw 查询本地索引,而不是依赖群晖搜索。用户确认后,系统根据 file_id 生成可访问下载链接,或通过钉钉 webhook 发送链接。
目标与范围
目标
- 支持采购人员通过对话搜索采购文件。
- 支持根据文件夹名称和文件名称快速检索。
- 支持 Linux 生产部署和 macOS 本地调试。
- 支持自动识别系统并执行对应 SMB 挂载逻辑。
- 支持 macOS 复用 Finder 已挂载 SMB 共享。
- 搜索阶段查询 OpenClaw 服务器本地索引,不依赖群晖搜索。
- 支持生成可配置有效期的下载链接。
- 支持搜索结果数量和搜索模式可配置。
- 支持每天低频全量同步,可配置时间,默认 23:23。
- 支持管理员手动全量同步。
- 支持 HTTP API 供 OpenClaw 调用。
范围内
- Linux/macOS 系统识别。
- 群晖 SMB 共享目录挂载检查与挂载。
- 挂载共享目录后扫描指定子目录。
- 文件名、文件夹名、路径、扩展名、大小、修改时间索引。
- SQLite/FTS 本地搜索。
- 智能搜索、左包含、右包含、全包含、精准匹配。
- 下载 token。
- 下载链接有效期配置,
0表示永不过期。 - 每日定时全量同步。
- 手动全量同步。
- OpenClaw HTTP 工具接口。
- 钉钉 webhook 发送链接骨架。
- 基础审计日志。
- 失败运行日志。
- Docker 部署文件。
范围外
- 暂不做后台增量同步。
- 第一阶段不做文件正文解析。
- 第一阶段不依赖群晖 Universal Search 或 File Station 搜索。
- 第一阶段不直接实现企业级权限系统,只保留权限校验接口位置。
- 第一阶段不直接实现钉钉内部应用文件上传。
用户与角色
| 角色 | 说明 | 权限 |
|---|---|---|
| 采购用户 | 通过 OpenClaw/钉钉搜索和接收文件 | 搜索授权目录内文件,确认后接收链接 |
| 管理员 | 配置群晖连接、索引任务和服务部署 | 管理配置、启动服务、查看日志、手动同步 |
| OpenClaw Agent | 解析用户意图并调用工具 | 调用搜索工具和发送工具 |
| 文件搜索服务 | 执行挂载、索引、搜索、发送前校验 | 读取群晖挂载目录和本地索引 |
业务流程
搜索流程
flowchart TD
A["用户提出文件搜索需求"] --> B["OpenClaw 解析关键词"]
B --> C["调用 search_purchase_file"]
C --> D["查询本地 SQLite/FTS 索引"]
D --> E["返回候选文件"]
E --> F{"是否唯一且高置信"}
F -->|是| G["请求用户确认发送"]
F -->|否| H["展示列表并要求用户选择序号"]发送流程
flowchart TD
A["用户确认文件"] --> B["调用 send_purchase_file"]
B --> C["按 file_id 查询索引记录"]
C --> D["校验路径白名单和文件存在性"]
D --> E["生成下载 token"]
E --> F["返回下载链接或通过钉钉发送"]
F --> G["记录审计日志"]同步流程
flowchart TD
A["每天指定时间或管理员手动执行"] --> B["ensure_mounted()"]
B --> C["扫描配置目录"]
C --> D["更新 files 和 files_fts"]
D --> E["清理已不存在文件的旧索引"]功能需求
FR-001 系统识别
系统必须使用 platform.system() 判断当前操作系统:
Linux:使用 Linux CIFS/SMB 挂载逻辑。Darwin:使用 macOSmount_smbfs挂载逻辑,且支持复用 Finder 已挂载共享。- 其他系统:提示不支持。
FR-002 群晖挂载
系统必须提供 ensure_mounted() 语义:
- 已挂载时直接返回挂载目录。
- macOS 下如果 Finder 已经挂载同一个 SMB 共享,程序应复用现有挂载路径。
- 未挂载时才执行挂载。
- 用户每次搜索时不得重复执行挂载。
FR-003 子目录扫描
系统必须支持挂载 SMB 共享后,只扫描其中指定子目录。
FR-004 本地索引
系统必须扫描挂载目录并写入本地 SQLite 索引。
第一阶段索引字段:
- 文件名。
- 文件夹路径。
- 完整路径。
- 扩展名。
- 文件大小。
- 修改时间。
索引任务必须清理已经不存在的旧文件记录。
FR-005 索引同步
暂行同步策略:
- 每天低频全量同步一次,默认
23:23。 - 全量同步时间必须可配置。
- 是否启用每日全量同步必须可配置。
- 服务启动后是否立即全量同步必须可配置。
- 必须支持管理员手动全量同步。
- 删除后台增量同步。
配置示例:
"index": {
"auto_full_sync_enabled": true,
"full_sync_time": "23:23",
"full_sync_on_startup": false
}背景依据:当前 92,108 个文件实测,全量同步约 289 秒,无变化目录级增量同步约 291 秒。瓶颈主要是 SMB 目录遍历/扫描,因此暂不做后台增量同步。
FR-006 文件搜索
系统必须支持关键词搜索:
- 多关键词搜索。
- 文件名搜索。
- 文件夹名搜索。
- 中文连续文本的基础模糊匹配。
搜索时只查询本地索引,不实时遍历群晖目录。
搜索结果数量必须可配置:
max_results > 0表示默认最多返回 N 条。max_results = 0表示默认返回所有符合条件的搜索结果。- 接口参数
limit可覆盖默认值,且limit = 0表示返回全部。
搜索模式必须可配置:
| 模式 | 中文别名 | 含义 |
|---|---|---|
smart | 智能 | 智能搜索,兼容原有 FTS/LIKE/中文切片搜索 |
left_contains | 左包含 | 文件名或目录以关键词开头 |
right_contains | 右包含 | 文件名或目录以关键词结尾 |
contains | 全包含 | 文件名或目录包含关键词 |
exact | 精准匹配 / 精确匹配 | 文件名或目录完全等于关键词 |
FR-007 候选确认
系统应在发送前要求用户确认,尤其是命中多个结果时。
FR-008 下载链接
系统必须支持根据 file_id 生成下载链接。
有效期规则:
token_ttl_minutes > 0:N 分钟后过期。token_ttl_minutes = 0:永不过期。
下载链接不得使用 127.0.0.1 发给用户,必须使用可配置的对外 IP、域名和端口。
FR-009 审计日志与失败运行日志
系统应记录基础审计日志:搜索、生成链接、下载行为。
系统运行日志只记录失败事件,包括挂载失败、同步失败、API 失败、下载失败和未处理异常。失败日志路径必须可配置。
FR-010 HTTP API 服务
系统应提供:
GET /healthPOST /search_purchase_filePOST /send_purchase_fileGET /download/{token}
FR-011 钉钉发送
第一阶段支持钉钉 webhook Markdown 消息发送链接。后续可扩展钉钉内部应用文件上传和单聊发送。
页面与交互
本项目第一阶段无独立前端页面,主要交互发生在 OpenClaw/钉钉对话中。
数据模型
核心数据表为:
files:文件元数据表。files_fts:SQLite FTS5 全文索引虚拟表。audit_logs:审计日志表。download_tokens:下载 token 表。
详细字段见 DatabaseSchema.md。
接口定义
search_purchase_file
{
"query": "DCC1039S.pdf",
"search_mode": "exact",
"limit": 0,
"user_id": "test-user"
}send_purchase_file
{
"file_id": 21559,
"recipient": "用户ID或群ID",
"channel": "link",
"user_id": "test-user"
}业务规则
- 搜索阶段只查询本地索引。
- 发送阶段才访问群晖真实文件。
- 用户每次搜索时不得重新挂载或扫描群晖。
- 群晖挂载必须优先只读。
- 不向普通用户暴露服务器真实绝对路径。
- 发送前必须校验文件路径是否位于白名单目录内。
- 文件不存在或已移动时,要求用户重新搜索或等待同步。
- 多结果命中时必须让用户二次确认。
- 下载链接有效期必须可配置。
token_ttl_minutes = 0表示下载链接永不过期。- 下载链接不得使用
127.0.0.1发给用户。 - 密码和密钥不得提交到代码仓库。
- 后台只保留每日全量同步,不做增量同步。
非功能要求
| 类型 | 要求 |
|---|---|
| 性能 | 常见关键词搜索应在 1 秒内返回 |
| 可用性 | 群晖短暂断开时,每日同步任务应能在下次重试 |
| 安全性 | 只读挂载、路径白名单、下载 token、审计日志 |
| 可维护性 | 服务器、共享名、挂载路径、索引路径、搜索模式、端口、全量同步时间均配置化 |
| 可部署性 | 至少支持 LinuxOS 部署,macOS 支持开发调试 |
| 可扩展性 | 后续可扩展正文搜索、更多发送渠道、权限系统、群晖 API 搜索 |
验收标准
- 可识别 Linux/macOS。
- 可复用 macOS Finder 已挂载 SMB 路径。
- 可扫描 SMB 共享下指定子目录。
- 可手动全量同步索引。
- 可配置每日全量同步时间,默认
23:23。 - 服务启动日志能显示每日全量同步配置。
- 可搜索文件并返回结果。
- 支持
limit = 0返回全部结果。 - 支持五种搜索模式。
- 可生成下载链接。
- 可配置下载链接有效期,
0表示永不过期。 - 文档明确说明不做后台增量同步。
技术与实现约束
- 使用 Python 实现 MVP。
- MVP 尽量使用 Python 标准库。
- 本地索引使用 SQLite/FTS5。
- Linux 挂载使用 CIFS/SMB。
- macOS 挂载使用
mount_smbfs或复用 Finder 挂载。 - 配置项不得写死在代码中。
- 文档统一放在
docs/目录。 - 提供 Dockerfile 和 docker-compose.yml。