merge: 吸收 PikaOA 开源方案调研

This commit is contained in:
Codex
2026-07-13 20:57:37 +02:00
@@ -0,0 +1,508 @@
# PikaOA R1.1 开源办公系统与组件调研报告
## 1. 任务信息
| 字段 | 内容 |
| --- | --- |
| MDTODO | [R1.1](../../pikaoa-enterprise-platform.md) |
| 执行 issue | [pikasTech/unidesk#1953](https://github.com/pikasTech/unidesk/issues/1953) |
| 上层规格 | [PJ2026-03](../../../../project-management/PJ2026-03/specs/PJ2026-03-pikaoa.md) |
| 调研日期 | 2026-07-13 |
| 交付性质 | 隔离选型文档,不包含业务代码、运行面、Secret 或 CI/CD 变更 |
本报告只为 PikaOA 后续实现提供证据和建议,不改变 PJ2026-03 已冻结的模块化单体、CLI-first、
HWLAB v0.3 同族前端和 YAML-first 方向。
## 2. 决策摘要
### 2.1 总体结论
- 不直接采用 ERPNext、Odoo、Twenty、EspoCRM、Dolibarr 或 OpenProject 作为 PikaOA 底座:
- 这些系统的领域边界、扩展模型、技术栈和升级路径会反向约束 PJ2026-03;
- 多数完整系统使用 GPL 或 AGPL,闭源可能性未知时不应复制源码或形成紧耦合派生实现;
- PikaOA 首期需要的是稳定平台内核与合同、发票事实,而不是迁移完整 ERP/CRM 产品。
- 直接采用宽松许可证的 Go、Vue 和可观测性基础组件:
- HTTP`chi`
- PostgreSQL`pgx``sqlc`
- 数据库迁移:`goose`
- CLI`Cobra`
- 授权:首期 `Casbin`,保留以后提取到 `OpenFGA` 的边界;
- 事务消息:PostgreSQL outbox 与 `Watermill`
- 前端:Vue 3、Vite、TypeScript、Vue Router、Pinia、Tailwind
- 可观测性:OpenTelemetry Go、OTLP Collector、Prometheus Go client 和结构化日志关联。
- 仅参考成熟系统的业务建模,不复制实现:
- ERPNext/Frappe 的单据提交、取消、修订和审计思路;
- Odoo 的发票冲销、贷项通知单与会计事实保留思路;
- CRM 的统一伙伴、联系人、标签与上下文角色模型;
- Paperless-ngx 的文档归档、检索、标签和权限思路;
- Documenso 的签署流程与签署证据思路。
- 首期不采用 `OpenFGA``Asynq``Atlas`
- `OpenFGA` 增加独立服务和授权模型运维成本,当前 RBAC 可由 `Casbin` 满足;
- `Asynq` 依赖 Redis,首期已有 PostgreSQL outbox 即可提供可审计异步处理;
- `Atlas``goose` 职责重叠,首期应保持单一迁移真相。
### 2.2 推荐分类
- 直接采用:
- `chi``pgx``sqlc``goose``Cobra``Casbin``Watermill`
- Vue 3、Vue Router、Pinia 和 Tailwind
- OpenTelemetry Go、Prometheus Go client 和 OTLP Collector。
- 组件复用:
- HWLAB v0.3 的前端布局语言、路由守卫和 API 错误呈现;
- HWLAB v0.3 的响应式工作台模式;
- 现有 UniDesk OTel、Tempo 和 Prometheus 运行能力。
- 仅参考:
- ERPNext/Frappe、Odoo、Twenty、EspoCRM 和 Dolibarr
- OpenProject、Documenso 和 Paperless-ngx
- OpenFGA 和 Asynq。
- 不采用:
- 完整 OA、ERP 或 CRM 产品作为 PikaOA 底座;
- GPL 或 AGPL 源码复制;
- 首期微服务拆分;
- 同时使用多套 HTTP、迁移或异步任务框架。
## 3. 调研方法与活跃度口径
- 来源优先级:
- 项目官方 GitHub 仓库及其许可证文件;
- 项目官方文档;
- GitHub Releases 和仓库最近推送时间。
- 活跃度判定:
- `高`:调研日附近仍有提交,并在近数月内发布版本;
- `中`:持续维护,但发布节奏较慢或主要以稳定维护为主;
- 活跃度只说明维护状态,不等于适合 PikaOA。
- 表中版本和活跃度是 2026-07-13 的采样证据:
- 最终依赖版本必须由实现任务根据锁文件、安全公告和兼容性验证选择;
- 不把本报告中的版本固化为部署策略。
## 4. 完整办公、ERP、CRM 与文档系统
### 4.1 ERPNext 与 Frappe
- 来源:
- [ERPNext](https://github.com/frappe/erpnext)
- [Frappe](https://github.com/frappe/frappe)。
- 活跃度与技术栈:
- 高;Python、JavaScript 和元数据驱动框架;
- ERPNext 于调研日仍有发布。
- 许可证:
- ERPNext 为 GPL-3.0
- Frappe 框架和附属组件需按锁定版本逐项复核。
- 可复用层次:
- 单据状态、提交后修改限制、取消与修订;
- 审计时间线和模块元数据思路。
- 成本与风险:
- 领域和框架绑定深;
- 采用整套系统会替换 Go 与既定模块边界;
- GPL 代码复制风险高。
- 结论:仅参考业务语义,不采用产品或源码。
### 4.2 Odoo
- 来源:[Odoo](https://github.com/odoo/odoo)。
- 活跃度与技术栈:高;Python、JavaScript 和模块化 ERP。
- 许可证:
- Community 核心通常为 LGPL-3.0
- Enterprise 和单独模块另有许可,必须逐项核验。
- 可复用层次:
- 发票、贷项通知单和冲销;
- 伙伴、模块注册和工作流。
- 成本与风险:
- 社区版与企业版边界复杂;
- 直接采用会偏离 Go 和 CLI-first。
- 结论:仅参考会计与伙伴模型。
### 4.3 Twenty
- 来源:[Twenty](https://github.com/twentyhq/twenty)。
- 活跃度与技术栈:高;TypeScript、React、NestJS 和 PostgreSQL。
- 许可证:仓库包含开源与商业边界,采用前必须逐文件核对。
- 可复用层次:
- 现代 CRM 交互;
- 统一对象、筛选、视图和活动时间线。
- 成本与风险:
- 技术栈与 HWLAB Vue 不同;
- 许可证与企业功能边界增加合规审查。
- 结论:仅参考产品交互和对象模型。
### 4.4 EspoCRM
- 来源:[EspoCRM](https://github.com/espocrm/espocrm)。
- 活跃度与技术栈:高;PHP 和 JavaScript。
- 许可证:AGPL-3.0。
- 可复用层次:CRM 实体、角色、团队、关系和审计思路。
- 成本与风险:AGPL 网络服务义务,且 PHP 技术栈不匹配。
- 结论:仅参考,不复制源码。
### 4.5 Dolibarr
- 来源:[Dolibarr](https://github.com/Dolibarr/dolibarr)。
- 活跃度与技术栈:高;PHP。
- 许可证:GPL-3.0。
- 可复用层次:
- 轻量 ERP 和 CRM 模块边界;
- 第三方与发票关联。
- 成本与风险:领域覆盖广但架构迁移成本较高,且存在 GPL 风险。
- 结论:仅参考模块目录和业务关系。
### 4.6 OpenProject
- 来源:[OpenProject](https://github.com/opf/openproject)。
- 活跃度与技术栈:高;Ruby 和 TypeScript。
- 许可证:GPL-3.0。
- 可复用层次:项目、工作包、活动记录和权限矩阵。
- 成本与风险:面向项目管理而非企业平台内核,技术栈与许可证不匹配。
- 结论:不作为底座,仅参考工作项审计。
### 4.7 Documenso
- 来源:[Documenso](https://github.com/documenso/documenso)。
- 活跃度与技术栈:高;TypeScript。
- 许可证:AGPL-3.0。
- 可复用层次:文档签署状态、参与者、签署证据和模板体验。
- 成本与风险:
- 电子签名涉及合规、身份与证据链;
- 存在 AGPL 风险。
- 结论:首期仅预留集成边界,不内嵌源码。
### 4.8 Paperless-ngx
- 来源:[Paperless-ngx](https://github.com/paperless-ngx/paperless-ngx)。
- 活跃度与技术栈:高;Python 和 Django。
- 许可证:GPL-3.0。
- 可复用层次:
- 文档归档、标签和对应方;
- 全文检索、权限和消费管线。
- 成本与风险:
- 适合作为独立文档系统,但不是合同事实主库;
- 存在 GPL 风险。
- 结论:参考归档模型,未来可评估松耦合集成。
### 4.9 完整系统不直接采用的根因
- 产品边界不一致:
- ERPNext、Odoo 和 Dolibarr 以 ERP 全域为中心;
- Twenty 和 EspoCRM 以 CRM 为中心;
- OpenProject 以项目协作为中心;
- Documenso 和 Paperless-ngx 只覆盖文档生命周期的一部分。
- 架构代价大于复用收益:
- 直接采用意味着把权限、扩展、数据迁移、前端和运维入口交给上游框架;
- PikaOA 仍需额外实现 CLI-first、YAML-first、UniDesk 交付和既定审计契约。
- 许可证不确定性:
- GPL/AGPL 项目可合法研究、部署和集成,但复制、修改、分发或通过网络提供修改版时存在义务;
- PikaOA 的最终分发模式尚未确定,因此本阶段只提炼思想和公开接口,不复制实现。
## 5. 关键业务语义建议
### 5.1 合同不可变多版本
推荐把“合同身份”和“合同版本”分离:
- `contract`
- 保存稳定编号、业务伙伴、负责人、当前有效版本指针和总体状态;
- 不直接承载会被修订覆盖的条款正文。
- `contract_version`
- 保存版本号、结构化条款、金额、币种、日期、附件摘要、创建人和创建时间;
- `draft` 可编辑;一旦进入 `approved``signed``effective``superseded`,内容不可原地修改;
- 修订必须创建新版本,并记录 `previous_version_id`、修订原因和操作者。
- 证据:
- 附件保存内容摘要、对象存储定位和媒体类型;
- 审批、签署、启用、终止和版本切换进入 append-only 审计记录;
- 查询必须能重建任一时点的有效版本。
该模型吸收 Frappe 的提交、取消、修订理念,但不复刻其 DocType 或框架实现。
### 5.2 发票作废而非物理删除
推荐状态至少区分:
- `draft`:尚未形成对外事实,可按权限编辑或删除;
- `issued`:已开具,不允许物理删除或覆盖关键字段;
- `voided`:保留原编号、金额、关联合同与附件,并记录作废原因、时间和操作者;
- `credited`:未来需要会计冲销时,通过独立贷项记录关联原发票,不改写原事实。
约束:
- 合同与发票使用稳定外键关联,同时保存开具时必要快照,避免伙伴名称后续变更破坏历史显示;
- `issued` 之后的任何纠正都产生新事实;
- 搜索默认可隐藏作废项,但审计、CLI 和明确过滤必须可查询;
- 数据保留策略不得把业务作废等同于数据库删除。
### 5.3 伙伴与甲方分类
采用统一 `business_partner`,不要为甲方、供应商、客户分别复制主表:
- 稳定字段包括法定名称、统一标识、归档状态、联系人和地址;
- `partner_category` 支持层级、标签和有效期;
- “甲方”“供应商”“客户”是上下文角色或分类,可同时存在;
- 合同保存签约时的伙伴快照和角色,伙伴主数据后续变更不覆盖历史合同;
- 分类变更必须审计,归档代替物理删除。
### 5.4 员工、身份与权限
- 身份与员工档案分离:
- 身份负责登录、会话和外部身份提供方映射;
- 员工负责组织、岗位、在职状态和业务归属。
- 首期采用 RBAC
- 资源与动作使用稳定 capability
- 角色只聚合 capability
- 数据范围通过明确条件实现,不把前端路由可见性当作后端授权。
- `Casbin` 适合首期进程内策略判定;
- 当出现跨服务关系授权、对象级共享或多租户关系图时,再评估 `OpenFGA`
### 5.5 审计与 outbox
- 业务写入、审计事件和 outbox 记录必须在同一 PostgreSQL 事务提交;
- outbox 记录包含稳定事件类型、聚合 ID、聚合版本、发生时间和脱敏载荷;
- worker 以至少一次语义处理,消费者通过事件 ID 或业务幂等键去重;
- `Watermill` 负责消息抽象和处理管线,不替代数据库事务真相;
- 审计记录和集成事件分开:
- 审计面向人和合规追溯;
- outbox 面向系统集成和未来服务提取。
### 5.6 模块扩展与未来微服务提取
首期保持模块化单体:
- 每个模块拥有自己的 handler、use case、repository、迁移和事件定义;
- 跨模块写入只能通过应用服务或已声明接口,不允许直接修改他模块表;
- 共享内核只保留身份、伙伴、附件、审计、分页、错误和幂等契约;
- 只有满足以下事实后才提取微服务:
- 独立扩缩容或故障隔离需求持续存在;
- 数据所有权和事件契约稳定;
- 跨模块同步事务已消除;
- 独立部署收益高于网络、可观测性和运维成本。
## 6. Go 后端组件评估
### 6.1 直接采用
- HTTP
- [chi](https://github.com/go-chi/chi)MIT
- 轻量、标准库兼容、路由组合自然,适合模块化单体。
- PostgreSQL
- [pgx](https://github.com/jackc/pgx)MIT
- PostgreSQL 原生能力完整,适配事务、批量和通知。
- SQL 代码生成:
- [sqlc](https://github.com/sqlc-dev/sqlc)MIT
- SQL-first、静态类型,便于审查真实查询。
- 数据库迁移:
- [goose](https://github.com/pressly/goose)MIT
- 简单、Go 生态成熟,适合显式 SQL 迁移。
- CLI
- [Cobra](https://github.com/spf13/cobra)Apache-2.0
- 子命令和 help 生态成熟,输出契约仍遵循 PikaOA CLI 规格。
- RBAC
- [Casbin](https://github.com/casbin/casbin)Apache-2.0
- 进程内、模型灵活,首期运维成本低。
- 事件:
- [Watermill](https://github.com/ThreeDotsLabs/watermill)MIT
- 消息处理抽象成熟,可与事务 outbox 结合。
### 6.2 仅比较或预留
- [Echo](https://github.com/labstack/echo)MIT
- 功能完整但约定较多;
- 不与 chi 并用,仅在发现明确缺口时重新评估。
- [Gin](https://github.com/gin-gonic/gin)MIT
- 生态和认知度高,但自有 Context 侵入更明显;
- 不采用,避免无收益的框架抽象。
- [Atlas](https://github.com/ariga/atlas)Apache-2.0
- 部分能力与商业产品边界需核验;
- 声明式 schema 与检查能力强,但会引入第二套迁移模型;
- 首期不采用。
- [OpenFGA](https://github.com/openfga/openfga)Apache-2.0
- 适合复杂对象关系授权;
- 会增加独立服务和模型治理;
- 预留边界,首期不采用。
- [Asynq](https://github.com/hibiken/asynq)MIT
- Redis 队列成熟;
- 会增加首期基础设施和第二事实源;
- 首期不采用。
### 6.3 推荐最小组合
```text
Cobra CLI / Vue Web
|
chi HTTP
|
应用服务与模块边界
|
sqlc + pgx + PostgreSQL
|
业务表 + audit_log + outbox
|
Watermill worker / 外部集成
```
组合原则:
- 不引入 ORM 作为默认数据访问层;
- 不同时维护 `goose``Atlas` 两套迁移真相;
- 不为异步任务额外引入 Redis,除非后续有独立证据;
- CLI 和 Web 必须调用同一 HTTP API 与业务用例,不形成旁路管理逻辑。
## 7. Vue 3 与 HWLAB v0.3 复用边界
### 7.1 直接采用
| 组件 | 许可证 | 用途 |
| --- | --- | --- |
| [Vue 3](https://github.com/vuejs/core) | MIT | 组件与响应式基础 |
| [Vue Router](https://github.com/vuejs/router) | MIT | 路由、模块入口和守卫 |
| [Pinia](https://github.com/vuejs/pinia) | MIT | 会话、访问摘要和跨页面客户端状态 |
| [Tailwind CSS](https://github.com/tailwindlabs/tailwindcss) | MIT | 设计令牌与响应式布局 |
### 7.2 复用 HWLAB v0.3 的内容
- 复用同族技术栈、设计语言和已验证的响应式布局方法;
- 复用以下模式,而不是复制 HWLAB 业务模块:
- 应用壳、侧边导航、顶栏、内容区和移动端折叠逻辑;
- 登录态、路由守卫、403/404 和 API 错误呈现;
- 表格筛选、分页、详情抽屉、时间线和状态徽标;
- 可访问性、加载态、空态和失败可见性;
- 与 CLI 同源的 capability 驱动导航。
### 7.3 禁止复用
- 不复制 Workbench、AgentRun、Code Queue 等领域组件和状态投影;
- 不把 HWLAB 的 session、run、event 模型引入合同或发票领域;
- 不让前端 Pinia store 成为业务事实真相;
- 不在 CLI 后端契约完成前先冻结 Web 私有接口。
## 8. 可观测性方案
| 组件 | 许可证 | 结论 |
| --- | --- | --- |
| [OpenTelemetry Go](https://github.com/open-telemetry/opentelemetry-go) | Apache-2.0 | 直接采用,负责 trace、metric 和 context 传播 |
| [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) | Apache-2.0 | 直接采用现有平台能力,应用只发 OTLP |
| [Prometheus Go client](https://github.com/prometheus/client_golang) | Apache-2.0 | 直接采用,暴露低基数业务与运行指标 |
| [Tempo](https://github.com/grafana/tempo) | AGPL-3.0 | 复用 UniDesk 独立运行服务,不把源码或服务端实现嵌入 PikaOA |
### 8.1 关联方式
- HTTP、CLI 请求和 worker 消费均传播 `trace_id``span_id`
- 结构化日志至少包含:
- 时间、级别、服务、模块、事件名;
- `trace_id``span_id`、request ID
- 脱敏后的 actor、聚合类型和聚合 ID;
- 稳定错误码,不记录 Secret、令牌或合同敏感正文。
- 指标保持低基数:
- 请求量、错误量、延迟;
- outbox backlog、处理成功和失败;
- 合同与发票状态变化计数;
- 禁止把员工 ID、合同 ID、发票号作为 metric label。
- Collector、采样、保留和导出参数继续由 owning YAML 控制,本报告不固化数值。
## 9. 许可证边界
本节是工程风险提示,不替代法律意见。
- MIT、Apache-2.0
- 可作为首选依赖;
- 仍需保留许可证和版权通知,并维护依赖清单。
- LGPL-3.0
- 动态链接、修改库和分发场景有不同义务;
- Odoo 必须按核心、社区模块、企业模块逐项确认,不以仓库总体印象替代检查。
- GPL-3.0
- ERPNext、Dolibarr、OpenProject 和 Paperless-ngx 等项目只提炼公开业务思想;
- 禁止复制源码、迁移脚本、模板或前端组件进入闭源可能性未知的仓库。
- AGPL-3.0
- EspoCRM、Documenso 和 Tempo 等网络服务软件需要特别审查修改版网络提供义务;
- 优先采用进程外、协议级集成,并保留独立部署和许可证材料;
- 任何修改、再分发或嵌入决定必须先完成法律与架构审查。
- 上游可能调整许可证或采用多许可证:
- 实现任务必须锁定 commit/tag
- 对锁定版本重新读取 `LICENSE``NOTICE`、依赖清单和商业功能说明;
- 自动生成软件物料清单并在发布前执行许可证扫描。
## 10. 实施建议
### 10.1 首期基线
- 建立 Go 模块化单体与单一 PostgreSQL 数据库;
- 用 chi、sqlc、pgx、goose、Cobra 建立最小 API/CLI 骨架;
- 先实现员工/RBAC、伙伴、合同版本、发票作废、审计和 outbox;
- 用 Casbin 做 capability 判定,策略存储与业务事务边界明确分离;
- 用 Watermill worker 消费 PostgreSQL outbox
- 接入 OpenTelemetry Go、OTLP 和 Prometheus 指标;
- CLI 验收通过后再实现 Vue 3 Web。
### 10.2 需要保留的替换边界
- HTTP 框架只暴露在 transport 层,应用用例不依赖 chi 类型;
- Casbin 通过授权接口接入,未来可替换或桥接 OpenFGA;
- Watermill 通过事件发布与消费接口接入,未来可迁移 Kafka 等 broker
- 对 Documenso、Paperless-ngx 等系统只定义外部连接器,不共享业务数据库;
- Tempo 作为 OTel 后端,不让业务代码依赖 Tempo 私有 API。
### 10.3 后续任务门槛
- R1.2 建仓前:
- 确认最终 Go module、Node package 和许可证清单;
- 明确依赖锁定和 SBOM 生成入口。
- R1.3 实现前:
- 先把合同版本、发票作废、伙伴角色、授权和 outbox 写成 API/CLI 验收契约;
- 禁止从完整开源系统复制 schema 或代码。
- R1.4 Web 开发前:
- CLI 后端主路径通过;
- 明确 HWLAB 可复用的布局、基础组件和设计令牌清单;
- Web 不得创建后端没有的隐式状态。
- 评估微服务前:
- 收集独立扩缩容、故障隔离、团队所有权和数据边界证据;
- 没有证据时继续保持模块化单体。
## 11. 来源索引
### 11.1 业务系统
- ERPNext 仓库:<https://github.com/frappe/erpnext>
- Frappe 仓库:<https://github.com/frappe/frappe>
- Frappe 单据状态文档:<https://docs.frappe.io/framework/doctypes/docstatus>
- ERPNext 不可变账本说明:<https://docs.frappe.io/erpnext/user/manual/en/immutable-ledger-in-erpnext>
- Odoo 仓库:<https://github.com/odoo/odoo>
- Odoo 许可证说明:<https://www.odoo.com/documentation/19.0/legal/licenses.html>
- Odoo 贷项与退款文档:<https://www.odoo.com/documentation/19.0/applications/finance/accounting/customer_invoices/credit_notes.html>
- Twenty 仓库:<https://github.com/twentyhq/twenty>
- EspoCRM 仓库:<https://github.com/espocrm/espocrm>
- Dolibarr 仓库:<https://github.com/Dolibarr/dolibarr>
- OpenProject 仓库:<https://github.com/opf/openproject>
- Documenso 仓库:<https://github.com/documenso/documenso>
- Paperless-ngx 仓库:<https://github.com/paperless-ngx/paperless-ngx>
- Paperless-ngx 权限文档:<https://docs.paperless-ngx.com/advanced_usage/#permissions>
### 11.2 Go 组件
- chi<https://github.com/go-chi/chi>
- Echo<https://github.com/labstack/echo>
- Gin<https://github.com/gin-gonic/gin>
- pgx<https://github.com/jackc/pgx>
- sqlc<https://github.com/sqlc-dev/sqlc>
- goose<https://github.com/pressly/goose>
- Atlas<https://github.com/ariga/atlas>
- Cobra<https://github.com/spf13/cobra>
- Casbin<https://github.com/casbin/casbin>
- OpenFGA<https://github.com/openfga/openfga>
- Watermill<https://github.com/ThreeDotsLabs/watermill>
- Asynq<https://github.com/hibiken/asynq>
### 11.3 前端与可观测性
- Vue 3<https://github.com/vuejs/core>
- Vue Router<https://github.com/vuejs/router>
- Pinia<https://github.com/vuejs/pinia>
- Tailwind CSS<https://github.com/tailwindlabs/tailwindcss>
- OpenTelemetry Go<https://github.com/open-telemetry/opentelemetry-go>
- OpenTelemetry Collector<https://github.com/open-telemetry/opentelemetry-collector>
- Prometheus Go client<https://github.com/prometheus/client_golang>
- Tempo<https://github.com/grafana/tempo>
## 12. 风险与未决项
- Odoo、Twenty、Atlas 等项目存在模块级、目录级或商业能力边界,不能只看仓库首页许可证;
- 电子签名、发票与会计凭证的法律效力依赖适用地区,后续需求需单独合规确认;
- Casbin 足以覆盖首期 RBAC,但对象级共享和关系授权增长后可能需要 OpenFGA;
- PostgreSQL outbox 可满足首期,但高吞吐、多消费者和跨区域需求出现后可能需要 Kafka 等 broker
- HWLAB v0.3 的具体组件可复用清单应在 R1.4 基于当时源码逐项确认;
- 本报告没有发现阻塞 PJ2026-03 继续执行的问题。