380 lines
18 KiB
Markdown
380 lines
18 KiB
Markdown
# ShareServer 技术设计
|
||
|
||
## 文档信息
|
||
|
||
| 项目 | 内容 |
|
||
| --- | --- |
|
||
| 状态 | 设计中 |
|
||
| 版本 | 0.3 |
|
||
| 日期 | 2026-09-09 |
|
||
| 关联 PRD | [ShareServer PRD](./prd.md) |
|
||
| 功能逻辑 | [功能逻辑设计](./logic-design.md) |
|
||
| 共享协议 | [共享网络总体设计](../../../../goodbuddy/docs/architecture/share-network-architecture.md) |
|
||
|
||
## 1. 仓库与运行边界
|
||
|
||
ShareServer 在独立的 `goodbuddy-shareserver` 仓库根目录维护。当前可运行结构为:
|
||
|
||
```text
|
||
goodbuddy-shareserver/
|
||
README.md
|
||
package.json
|
||
server/ # Hono API 与同源静态资源服务
|
||
shared/ # 原型 fixture 与类型
|
||
src/ # React Web 控制台
|
||
docs/features/share-server/
|
||
Dockerfile
|
||
```
|
||
|
||
以下是后续生产实现的建议模块结构,尚未创建,不代表已实现:
|
||
|
||
```text
|
||
goodbuddy-shareserver/
|
||
README.md
|
||
package.json
|
||
src/
|
||
api/
|
||
auth/
|
||
organizations/
|
||
devices/
|
||
capabilities/
|
||
policies/
|
||
approvals/
|
||
tasks/
|
||
relay/
|
||
packages/
|
||
office/
|
||
federation/
|
||
audit/
|
||
web/
|
||
migrations/
|
||
deploy/
|
||
tests/
|
||
```
|
||
|
||
仓库根目录是可独立运行的全控制台交互原型。原型使用 Hono 提供健康、就绪、
|
||
界面快照和无持久化操作确认 API,并同源托管 React/Vite Web 控制台;它不依赖 Electron 的
|
||
`src/shared`。当前尚未建立生产数据库、认证、设备连接和共享协议,因此也不提前创建空的
|
||
`packages/share-protocol`。进入真实 Desktop 协议实现时,服务端和 Desktop 共同依赖
|
||
独立发布的 `share-protocol` 协议包,具体归属在真实协议实现时确定;
|
||
ShareServer 仍不得导入 Electron 的 `src/shared`,也不得依赖相邻桌面仓库构建。
|
||
|
||
## 2. 技术选型约束
|
||
|
||
- 使用与仓库一致的 TypeScript/Node.js 工具链,具体 HTTP 框架在实现前根据维护性选择。
|
||
- PostgreSQL 是组织、策略、任务元数据和审计的权威数据库。
|
||
- Package、可选中继暂存和 Office 工作副本使用 S3 兼容对象存储;不开启对应功能时不要求
|
||
对象存储,启用 Office 时对象存储是必需依赖。
|
||
- Web 控制台与 API 同源部署,采用严格 CSP,不在浏览器保存设备凭据。
|
||
- 单实例部署可完整工作;水平扩展时再引入共享事件/连接路由组件,不为未验证规模预设复杂
|
||
分布式协议。
|
||
|
||
## 3. 服务模块
|
||
|
||
| 模块 | 职责 |
|
||
| --- | --- |
|
||
| `auth` | 本地身份、OIDC、Web session、服务和设备凭据 |
|
||
| `organizations` | 组织、成员、组、角色和范围解析 |
|
||
| `devices` | 注册挑战、设备记录、出站连接和在线状态 |
|
||
| `capabilities` | manifest、数字人 profile、provider、Publication 和目录投影 |
|
||
| `policies` | Grant、强制策略和确定性授权计算 |
|
||
| `approvals` | 内容绑定申请、决定、过期和通知 |
|
||
| `tasks` | task/attempt、provider 路由、状态和取消 |
|
||
| `relay` | 可选有界数据中继,不解释能力正文 |
|
||
| `packages` | 不可变对象、签名目录、通道和撤销 |
|
||
| `office` | 编辑会话、工作副本、ONLYOFFICE 配置、callback、checkpoint、保留和健康 |
|
||
| `federation` | 网关身份、offer、双边策略和跨组织映射 |
|
||
| `audit` | 事务内审计写入、查询、保留和导出 |
|
||
|
||
模块通过服务接口调用,API handler 不直接拼接跨组织 SQL 或自行计算权限。
|
||
|
||
## 4. API 边界
|
||
|
||
建议分为六类 audience:
|
||
|
||
```text
|
||
/api/v1/web/* 管理控制台与成员自助 API
|
||
/api/v1/device/* 设备注册、目录和任务控制 API
|
||
/api/v1/office/* Desktop Office 会话、文件和事件 API
|
||
/api/v1/federation/* ShareServer 间 API
|
||
/api/v1/public/* 服务描述、健康与登录入口
|
||
/internal/office/* ONLYOFFICE 文件读取和 callback API
|
||
```
|
||
|
||
设备使用 WebSocket `/api/v1/device/connect` 建立出站控制通道。包下载使用短期、绑定主体和对象
|
||
摘要的 URL。联邦 API 使用网关身份,不接受普通用户 session。每类 token 使用不同 issuer/
|
||
audience/scope,不能互换。Office 启动 code、文件 token 和 callback token 也使用互不相同的
|
||
audience,并绑定单个 `DocumentEditSession`。
|
||
|
||
所有请求经 schema、认证、organization scope、授权、速率和大小边界。列表使用游标分页和固定
|
||
最大页;错误返回 request ID、稳定 code 和有界参数。
|
||
|
||
## 5. 数据模型
|
||
|
||
核心表建议为:
|
||
|
||
```text
|
||
instances
|
||
identity_providers
|
||
users
|
||
organizations
|
||
memberships
|
||
groups
|
||
group_members
|
||
role_bindings
|
||
registered_devices
|
||
device_credentials
|
||
device_connections
|
||
capabilities
|
||
capability_versions
|
||
agent_profiles
|
||
providers
|
||
publications
|
||
grants
|
||
policies
|
||
approval_requests
|
||
approval_decisions
|
||
tasks
|
||
task_attempts
|
||
task_events
|
||
package_objects
|
||
package_releases
|
||
release_channels
|
||
update_policies
|
||
document_edit_sessions
|
||
document_checkpoints
|
||
federation_trusts
|
||
federation_capability_exports
|
||
audit_events
|
||
revocations
|
||
```
|
||
|
||
要求:
|
||
|
||
- 所有组织数据表包含不可为空的 `organization_id`,并由 repository 层强制作用域。
|
||
- 唯一约束同时包含 organization,避免跨组织名称冲突泄漏。
|
||
- 密钥保存为单向摘要或经外部主密钥加密的密文;数据库不保存明文 token。
|
||
- 在线连接和短期 nonce 主要在内存;表中只保存恢复所需元数据,不把 socket 当持久对象。
|
||
- task event 只存控制状态和有界统计;正文流不进入普通关系表。
|
||
- `agent_profiles` 只保存组织内唯一 handle、显示元数据和其能力版本引用。数字人复用
|
||
Publication、Grant、Approval 和 Task,不创建第二套授权或路由模型;本地 Agent 记忆条目、
|
||
分区目录和来源正文不进入 ShareServer 数据库。
|
||
- 数字人 Publication revision 保存有界 `memory_source_policy`,只允许 `agent`、`global`、
|
||
`project` 和 `automation` 种类及 Provider 验证后的本地关联 ID 摘要。Provider 执行时按该
|
||
revision 在本地重新解析分区并检索;服务端不接收记忆文本、来源正文、Embedding 或检索
|
||
结果。新增来源是权限扩大,移除来源是单向收紧。
|
||
- `document_edit_sessions` 只保存组织、用户、设备、公开来源 ID、显示名、格式、对象键、摘要、
|
||
访问模式、策略 revision、状态和保留期限,不保存 Desktop 绝对路径。
|
||
- `document_checkpoints` 以 session 内单调 revision 保存对象键、大小、SHA-256、callback 幂等键
|
||
和时间;`source_commit_confirmed` 只表示 Desktop 回报结果,不由 callback 自动填写。
|
||
|
||
## 6. 事务与一致性
|
||
|
||
- 业务变更与对应审计事件在同一 PostgreSQL 事务提交。
|
||
- Publication/Grant/Policy 使用 revision 做乐观并发,Web 草稿不能覆盖他人更新。
|
||
- 授权决定创建 task 时再次读取当前 revision,并将命中策略摘要冻结到 task。
|
||
- 设备在线状态允许短暂最终一致;身份、撤销、授权和任务接受必须走权威存储。
|
||
- 重复注册挑战、联邦 offer 和 task create 使用唯一幂等键。
|
||
- 无法确认 provider 副作用时只更新 `outcome_unknown`,不靠消息队列自动重放。
|
||
- Office callback 的临时对象、checkpoint 行和审计事件在同一提交边界发布。数据库提交失败时
|
||
临时对象保持不可下载并由清理任务删除;重复 callback 依赖会话内幂等键返回已有 revision。
|
||
|
||
## 7. 设备连接与任务
|
||
|
||
连接建立后完成设备 credential、organization、客户端协议和当前 registration 校验。服务端为
|
||
每个连接设置心跳、空闲、帧、发送队列和并发上限。
|
||
|
||
任务流程:
|
||
|
||
```text
|
||
authorize -> create task -> resolve exact provider connection
|
||
-> send declaration -> provider accepts/rejects
|
||
-> establish direct or relay route -> stream progress
|
||
-> provider terminal result -> caller delivery -> audit terminal state
|
||
```
|
||
|
||
同一设备重复连接时使用 connection generation;新连接接管未来任务,旧连接仍只允许完成或
|
||
查询已归属 task,随后有界关闭。不能把新任务随机发到身份相同但 generation 过期的 socket。
|
||
|
||
## 8. 中继
|
||
|
||
中继是可选模块:
|
||
|
||
- 控制面与中继可部署在不同进程,但共享 task 授权验证。
|
||
- 每个 relay ticket 绑定 task、调用方、provider、方向、期限和最大字节。
|
||
- 实现背压和全局/组织/设备并发及带宽上限。
|
||
- 不解析能力正文,不写普通日志;需要临时落盘时使用加密 GoodBuddy-owned 暂存并按 task 清理。
|
||
- 中继关闭、过载或策略禁止时返回准确路由错误,不静默转到其他节点。
|
||
|
||
## 9. Package 存储
|
||
|
||
上传先进入不可公开暂存:流式计算大小和 SHA-256,验证签名、manifest、版本、平台和权限后,
|
||
以 digest 发布为不可变对象。相同 digest 可去重,但组织授权和 Release 分别保存。
|
||
|
||
Release catalog 使用独立签名域。服务器不能重打包已签名 payload;镜像目标必须保持相同字节、
|
||
大小和 SHA-256。撤销更新目录和授权,不覆盖或原地删除仍受审计保留的对象。
|
||
|
||
## 10. Office 编辑服务
|
||
|
||
### 10.1 部署边界
|
||
|
||
ShareServer 集成 ONLYOFFICE Docs Developer Edition,但不把 Document Server 代码并入 Hono
|
||
进程。生产部署使用独立容器和内部网络:
|
||
|
||
```text
|
||
GoodBuddy Desktop -> TLS reverse proxy -> ShareServer Office API
|
||
|-> S3 compatible object storage
|
||
|-> ONLYOFFICE Document Server
|
||
`-> Office callback worker
|
||
```
|
||
|
||
Desktop 只知道 ShareServer 公开 origin。Document Server 内部地址、JWT 密钥、对象存储凭据和
|
||
callback 内部地址只存在于部署配置或密钥管理系统。正式采用前必须完成许可证和桌面分发审核。
|
||
|
||
### 10.2 Desktop API
|
||
|
||
```text
|
||
POST /api/v1/office/sessions
|
||
PUT /api/v1/office/sessions/{id}/source
|
||
POST /api/v1/office/sessions/{id}/launch
|
||
GET /api/v1/office/sessions/{id}
|
||
GET /api/v1/office/sessions/{id}/events
|
||
GET /api/v1/office/sessions/{id}/checkpoints/{revision}
|
||
POST /api/v1/office/sessions/{id}/source-commit
|
||
DELETE /api/v1/office/sessions/{id}
|
||
|
||
GET /internal/office/files/{objectToken}
|
||
POST /internal/office/callback/{callbackToken}
|
||
```
|
||
|
||
Desktop 使用设备凭据创建会话,只提交公开来源 ID、显示名、MIME、声明大小和 SHA-256。上传按
|
||
流读取并校验真实格式,不接受 Desktop 指定对象键。`launch` 返回一次性 code;编辑页面交换为
|
||
HttpOnly、Secure、SameSite Cookie 后 code 立即失效。
|
||
|
||
ONLYOFFICE 文件 URL 和 callback URL 由 ShareServer 生成固定 origin,token 绑定 session、
|
||
revision、动作、大小和期限。接口不接受调用方提供的任意 callback URL。
|
||
|
||
### 10.3 保存检查点
|
||
|
||
callback 输出先写入随机临时对象,完成大小、摘要、格式和普通对象检查后发布不可变 checkpoint。
|
||
ShareServer 随后通过设备事件通道通知 Desktop。只有 Desktop 下载复核并回报
|
||
`source_commit_confirmed` 后,服务端审计才记录源文件已回写;冲突、超时和未知结果使用独立
|
||
状态,不能把“编辑器保存成功”翻译为“本地文件已保存”。
|
||
|
||
### 10.4 编辑器插件和 AI
|
||
|
||
ShareServer 托管固定版本的 GoodBuddy ONLYOFFICE 插件,并在会话配置中精确启用。插件只交换
|
||
有界选区描述、文档 revision、白名单编辑操作和非正文状态事件。它不能接收 JavaScript、宏、
|
||
任意 ONLYOFFICE 方法名或 ShareServer 管理 token。
|
||
|
||
AI 请求仍由 GoodBuddy Desktop 的 Conversation 和 Runtime 执行。Ask 只能生成建议;Execute
|
||
成功取得绑定 session、revision 和选区的短期 Grant 后,插件才可在单个撤销上下文中应用修改。
|
||
ShareServer 负责中继有界事件,不持久化选区正文、Prompt 或模型输出。
|
||
|
||
### 10.5 生命周期和清理
|
||
|
||
- 会话、工作副本、checkpoint、启动 Cookie 和对象 token 分别设置明确期限。
|
||
- 关闭、撤销或到期立即拒绝新读取、保存和 AI 操作。
|
||
- 清理使用对象标签和数据库状态,重复执行保持幂等,不根据用户文件名构造删除前缀。
|
||
- 法定保留只能延长明确匹配的工作副本、checkpoint 或审计元数据,不能恢复访问授权。
|
||
- 备份恢复不恢复编辑 Cookie、启动 code、文件 token、callback token 或活动编辑连接。
|
||
|
||
## 11. 联邦协议
|
||
|
||
- 每个实例生成网关身份和可轮换证书,私钥不进入数据库备份明文。
|
||
- offer 包含双方可人工核对的组织名、端点、指纹、协议和 nonce。
|
||
- 双方确认后交换有界 capability projection 和本地映射 ID。
|
||
- 跨组织 task 带双方关联 ID 和短期签名声明;每端独立授权并各写审计。
|
||
- 不接受调用方提供的任意回调 URL、第三方 hop 或内部主体 ID。
|
||
- 证书轮换需要旧身份签名或双方重新确认;身份突变直接暂停关系。
|
||
|
||
## 12. Web 安全
|
||
|
||
- 使用 HttpOnly、Secure、SameSite cookie 和 CSRF 防护管理 Web session。
|
||
- OIDC 使用 state、nonce、PKCE 和固定回调地址。
|
||
- 富文本字段按纯文本显示;manifest/schema 使用安全代码查看器,不执行 HTML。
|
||
- 权限隐藏仅改善界面,所有 API 在服务端重新校验。
|
||
- 登录、设备注册、目录、审批、导出和联邦接口分别限速。
|
||
- 密钥字段只能替换、轮换和测试,永不回显。
|
||
- 编辑页面使用独立 CSP 和 Cookie scope;ONLYOFFICE origin 不能访问管理控制台 session。
|
||
- Document Server 默认禁止任意出站网络、宏和未批准插件。编辑文件视为不可信内容。
|
||
|
||
## 13. 部署与配置
|
||
|
||
最小生产部署:
|
||
|
||
```text
|
||
TLS reverse proxy/load balancer
|
||
ShareServer API + Web
|
||
PostgreSQL
|
||
可选:S3 compatible object storage
|
||
可选:Relay worker
|
||
可选套件:ONLYOFFICE Document Server + Office callback worker(需要对象存储)
|
||
```
|
||
|
||
部署配置通过环境变量或挂载文件提供数据库、主密钥、公开 URL、OIDC、邮件、对象存储和限制。
|
||
普通 Web 管理员不能修改基础设施秘密。提供数据库迁移命令、不可变镜像、非 root 容器、健康
|
||
与就绪端点、优雅停止和部署示例。
|
||
|
||
Office 配置包括启用状态、Document Server 内部地址、公开编辑 origin、JWT 密钥引用、对象
|
||
存储 bucket、允许格式、文件大小、组织/用户并发、会话期限和 checkpoint 保留。管理界面不能
|
||
回显密钥。Office readiness 必须完成最小文档创建、编辑器加载、callback 和输出摘要验证,不能
|
||
只检查 Document Server HTTP 端口。
|
||
|
||
## 14. 可观测性与备份
|
||
|
||
- 结构化日志只包含 request/task/organization 关联 ID、稳定事件和错误码。
|
||
- 指标覆盖请求、WebSocket、授权结果、任务状态、中继、Package、Office 会话/callback 和联邦,
|
||
不包含能力正文、文档正文或选区。
|
||
- tracing 跨内部服务传播关联 ID,跨联邦只传播双方同意的关联标识。
|
||
- 备份 PostgreSQL、Package 对象、策略要求保留的 Office checkpoint 和网关身份;不备份缓存、
|
||
Web session、nonce、Office 短期 token 或中继暂存。
|
||
- 恢复后撤销列表、组织 ID、签名目录和审计序列保持有效,所有设备重新连接。
|
||
|
||
## 15. 测试策略
|
||
|
||
### 15.1 自动化
|
||
|
||
- schema、认证 audience、CSRF、OIDC 和设备挑战。
|
||
- 每个 repository/API 的跨组织隔离与枚举防护。
|
||
- 拒绝优先授权、审批内容绑定、预算和并发。
|
||
- device generation、离线、撤销、重连和 provider 冻结。
|
||
- task 幂等、取消、结果未知和不自动重放。
|
||
- Package 流式校验、不可变性、权限 diff 和撤销。
|
||
- 联邦双方确认、策略交集、暂停、证书变化和禁止第三 hop。
|
||
- 审计事务、过滤、分页、导出和正文缺失。
|
||
- Office token audience、上传格式/摘要、callback 幂等、checkpoint 不可变、保留和清理。
|
||
- Ask 拒绝编辑写入,Execute Grant 绑定 session、revision 和选区且不能跨文档复用。
|
||
|
||
### 15.2 集成与部署
|
||
|
||
- Desktop 与真实 ShareServer 完成注册、目录、调用、文件和取消。
|
||
- 两个隔离组织验证搜索、计数、错误、对象和审计不泄漏。
|
||
- 两个 ShareServer 完成联邦建立、跨组织调用和单方撤销。
|
||
- 中继关闭与开启、容量耗尽、连接中断和大文件背压。
|
||
- 数据库备份恢复、版本升级、滚动停止和设备重连。
|
||
- 生产 TLS、OIDC 和对象存储组合的端到端验证。
|
||
- Windows、macOS、Linux Desktop 与同一 ShareServer 打开、编辑和保存 DOCX、XLSX、PPTX。
|
||
- 多文档会话隔离、同一源文件多开只读、源文件冲突、断线恢复、callback 失败和过期清理。
|
||
- ONLYOFFICE 真实版本、许可证允许的并发矩阵、浏览器兼容、CPU/内存和大文件边界。
|
||
|
||
设计完成不代表服务已实现;只有独立部署和真实 Desktop 端到端路径通过后才能更新实施状态。
|
||
|
||
## 16. 当前原型实现
|
||
|
||
2026-09-05 建立的交互原型固定以下技术基线:
|
||
|
||
- API:Hono + `@hono/node-server`,保留 `/api/v1/public/*` 与
|
||
`/api/v1/web/*` audience 路径。
|
||
- Web:React、Vite、TypeScript、Tailwind CSS 和 Radix primitives,按 shadcn/ui 组件模式
|
||
维护本地可修改组件。
|
||
- 路由与范围:管理员和成员自助使用不同可见导航;当前组织持续显示。
|
||
- 部署:生产构建由同源 Hono 服务托管,并提供非 root 多阶段 Docker 镜像。
|
||
|
||
`/api/v1/public/ready` 返回 `mode=interactive-prototype` 和
|
||
`productionReady=false`。原型 fixture、角色切换和操作确认只用于评审信息架构,不得被
|
||
Desktop 或部署脚本当作真实身份、策略、任务或审计 API。下一实施阶段必须从 FR-1
|
||
初始化、本地身份、PostgreSQL 组织作用域和事务审计开始,不在 fixture 上叠加生产状态。
|
||
当前原型没有 Office 导航、配置、会话 API、对象存储、ONLYOFFICE、callback 或 Desktop 文档
|
||
Tab 集成;上述章节仅定义目标设计。
|