|
| 1 | +--- |
| 2 | +title: ApeRAG 企业版仓库迁移方案 |
| 3 | +description: 企业版主仓 + 开源版子集 + 双向同步链路 - 完整详细中文方案 |
| 4 | +--- |
| 5 | + |
| 6 | +# ApeRAG 企业版仓库迁移方案 |
| 7 | + |
| 8 | +> earayu2 directive (`#企业版` msg=c2c8d8f2 + msg=c0b009e2): 团队主开发要迁到企业版仓库, 但开源版要继续维护, 而且企业版必须是开源版的超集。10 lane 团队讨论收口后由总架构师起草完整中文方案。 |
| 9 | +
|
| 10 | +## 0. 这件事在做什么 |
| 11 | + |
| 12 | +简单说: 我们要把日常开发主仓库从现在的开源版 (`apecloud/ApeRAG`) 迁到一个新的企业版仓库 (`apecloud/aperag-enterprise`)。但我们不能丢掉开源版 — 开源版必须继续公开、继续接受社区贡献、必须是企业版功能的一个干净子集。 |
| 13 | + |
| 14 | +简单的事情可能不简单的地方: |
| 15 | +- **企业版必须是开源版的超集**: 企业版有的开源版可能没有, 但开源版有的企业版必须有 |
| 16 | +- **企业版功能可以双向流动**: 企业版做的某些通用改进, 应该能流回开源版给社区用 |
| 17 | +- **以后日常开发主战场在企业版**: 开发者每天 push 的是企业版仓库, 不是开源版 |
| 18 | + |
| 19 | +整个事情的核心矛盾: 怎么在「开发主仓只有一个」和「开源版仍然是活的公开仓」之间找平衡, 不让两边互相打架, 也不让企业代码意外泄漏到开源仓。 |
| 20 | + |
| 21 | +## 1. 为什么现在做 |
| 22 | + |
| 23 | +- earayu2 想让后续大量功能 (license / SSO / 企业 dashboard / 私有部署 connector / 客户定制等) 在企业版迭代, 不污染开源版的 scope |
| 24 | +- 现在还没开始迁, 越往后拖越难: 现在 `apecloud/ApeRAG` 还相对干净, 没有大量企业代码混在里面; 等企业代码开始铺开后再分就要做大手术 |
| 25 | +- 团队 10 lane 充分讨论 (Weston / dongdong / 符炫炜 / ziang / huangzhangshu / 不穷 / huangheng / 明书 / Bryce / Planetegg) 已经收口, 现在欠的就是 earayu2 拍板 + 启动时机 |
| 26 | + |
| 27 | +## 2. 整体方案 (一句话) |
| 28 | + |
| 29 | +**企业版仓库 (`apecloud/aperag-enterprise`) 作为日常开发主战场, 但保留 `apecloud/ApeRAG` 开源版的完整历史和社区 PR 流程, 通过 PR 标签 + 代码目录硬隔离 + 双向同步机制, 让两边自然协同, 不互相覆盖, 不泄漏企业代码到开源仓。** |
| 30 | + |
| 31 | +具体落实成 4 件事: |
| 32 | + |
| 33 | +1. **代码怎么组织**: 现有开源代码目录不动, 企业代码新增到独立目录 |
| 34 | +2. **PR 怎么写**: 每个 PR 必须打标签, 说清楚改动属于「开源可回流」还是「企业独占」还是「混合需要拆」 |
| 35 | +3. **企业改动怎么流到开源**: 标了「开源可回流」的 PR, 自动 cherry-pick 到开源仓开正常 PR, 走开源仓的 review + merge |
| 36 | +4. **开源改动怎么流到企业**: 每周一次自动把开源主分支 merge 进企业主分支, 保证企业版包含所有开源最新修复 |
| 37 | + |
| 38 | +## 3. 代码具体怎么组织 |
| 39 | + |
| 40 | +### 3.1 仓库关系 |
| 41 | + |
| 42 | +``` |
| 43 | +apecloud/aperag-enterprise (新建, 私有, 团队日常开发主战场) |
| 44 | + ↑ |
| 45 | + 日常 push, 主分支永远 = 开源全部 + 企业功能 |
| 46 | + |
| 47 | +apecloud/ApeRAG (维持现有, 公开, 社区入口) |
| 48 | + ↑ |
| 49 | + 保留完整历史 + 社区 PR + issue + fork |
| 50 | + 日常用 cherry-pick 接收企业仓里「开源可回流」的改动 |
| 51 | +``` |
| 52 | + |
| 53 | +### 3.2 目录结构 (非常重要 — 硬约束) |
| 54 | + |
| 55 | +企业版仓库内部: |
| 56 | + |
| 57 | +``` |
| 58 | +aperag-enterprise/ |
| 59 | +├── aperag/ ← 开源后端代码 (现有, 不动) |
| 60 | +├── web/ ← 开源前端代码 (现有, 不动) |
| 61 | +├── deploy/aperag/ ← 开源部署文件 (现有, 不动) |
| 62 | +├── docs/ ← 开源文档 (现有, 不动) |
| 63 | +├── tests/ ← 开源测试 (现有, 不动) |
| 64 | +│ |
| 65 | +├── enterprise/ ← 企业后端代码 (新加, 商业许可) |
| 66 | +│ ├── license/ ← 授权管理 |
| 67 | +│ ├── connectors/ ← 客户定制连接器 |
| 68 | +│ ├── modules/ ← 企业功能模块 |
| 69 | +│ └── migrations/ ← (可选) 企业表 migration |
| 70 | +├── web-enterprise/ ← 企业前端代码 (新加) |
| 71 | +├── deploy/enterprise/ ← 企业部署 overlay (新加) |
| 72 | +├── docs/enterprise/ ← 企业文档 (新加) |
| 73 | +└── tests/enterprise/ ← 企业测试 (新加) |
| 74 | +
|
| 75 | +└── docs/zh-CN/architecture/enterprise-sync-policy.md ← 同步策略文档 |
| 76 | +``` |
| 77 | + |
| 78 | +**核心约束 (用 CI 强制, 不靠人记)**: |
| 79 | + |
| 80 | +1. **方向单向**: 开源代码不能引用企业代码, 但企业代码可以引用开源代码 |
| 81 | + - 比如 `aperag/llm/embedding.py` 不能 `from enterprise.license import ...` |
| 82 | + - 反过来 `enterprise/connectors/customer_x.py` 可以 `from aperag.llm import EmbeddingService` (这是合法的, 企业功能基于开源核心扩展) |
| 83 | + - CI 用静态分析检查每个 import 语句, 违反就 build 红, 不允许合 PR |
| 84 | + |
| 85 | +2. **License header 标记**: 每个企业目录里的文件首行必须有商业许可注释, 比如: |
| 86 | + ```python |
| 87 | + # License: Commercial - apecloud (NOT Apache 2.0) |
| 88 | + ``` |
| 89 | + 开源目录里的文件保持原有 Apache 2.0 header。CI 检查文件路径和 header 一致性, 不一致就 build 红。 |
| 90 | + |
| 91 | +3. **数据库表分层**: 企业新加的表用 `enterprise_` 前缀 (比如 `enterprise_license_keys`), 但 alembic migration 仍走开源主链, **不开 alembic 多 head** (多 head 在双仓维护下会很脆弱, 团队 huangheng 在讨论里专门提过这个坑)。 |
| 92 | + |
| 93 | +4. **配置文件分层**: 企业版独占的环境变量 / Helm values / connector 配置, 都放企业目录, 开源 deploy 路径不带任何企业字段。 |
| 94 | + |
| 95 | +### 3.3 build 双套 |
| 96 | + |
| 97 | +CI 跑两套 build: |
| 98 | + |
| 99 | +- `EDITION=oss` build: 把 `enterprise/` `web-enterprise/` `deploy/enterprise/` `docs/enterprise/` `tests/enterprise/` 临时挪走, 跑完整开源 lint + test + build, **必须能通过** |
| 100 | +- `EDITION=enterprise` build: 全代码跑企业 CI, 含开源 + 企业测试 |
| 101 | + |
| 102 | +第一种 build 的存在保证了「开源版独立可运行」这个硬契约。任何 PR 让开源 build 跑不过, 不允许合。 |
| 103 | + |
| 104 | +## 4. PR 工作流 |
| 105 | + |
| 106 | +### 4.1 PR 必打标签 |
| 107 | + |
| 108 | +企业仓里每个 PR 创建时, 模板强制选一个标签: |
| 109 | + |
| 110 | +| 标签 | 含义 | 改动范围 | 同步行为 | |
| 111 | +|------|------|---------|---------| |
| 112 | +| `oss-safe` | 开源可回流 | 只动开源目录 (`aperag/` `web/` `deploy/aperag/` `docs/` `tests/`) | 合并后 bot 自动到开源仓开 cherry-pick PR | |
| 113 | +| `enterprise-only` | 企业独占 | 只动企业目录 (`enterprise/` `web-enterprise/` `deploy/enterprise/` etc.) | 不流到开源仓 | |
| 114 | +| `mixed` | 混合 | 同时动开源和企业 | CI 拒绝, 必须拆成两个 PR (一个 oss-safe + 一个 enterprise-only) | |
| 115 | + |
| 116 | +**为什么强制拆 mixed**: |
| 117 | + |
| 118 | +如果允许同一个 PR 既改开源又改企业, 后期回流到开源时只能拿这个 PR 的部分内容, 拆 commit 很难做干净。如果开发时就拆开, 流程自然 — 哪些进开源哪些不进, 一眼看清楚。 |
| 119 | + |
| 120 | +### 4.2 自动同步流程 (减少人工纪律消耗) |
| 121 | + |
| 122 | +每个 enterprise PR 在 CI 阶段自动跑一个「同步预演」: |
| 123 | + |
| 124 | +- 如果 PR 标 `oss-safe`: CI 模拟把改动应用到开源仓, 显示「这个 PR 会让开源仓增加哪些改动」, reviewer 一眼看清楚, 没问题就 merge |
| 125 | +- 如果 PR 标 `enterprise-only`: CI 验证「这个 PR 应用到开源仓后开源仓 0 改动」, 防止开发者误把企业代码写进开源路径 |
| 126 | + |
| 127 | +PR merge 之后: |
| 128 | + |
| 129 | +- `oss-safe` 标签的 PR: bot 自动到开源仓 (`apecloud/ApeRAG`) 开一个对应的 cherry-pick PR (草稿状态), 作者点 publish 就发布给开源仓 reviewer 看, 走正常开源 PR 流程 |
| 130 | +- `enterprise-only` 标签的 PR: 留在企业仓不动 |
| 131 | + |
| 132 | +### 4.3 开源贡献流回企业 |
| 133 | + |
| 134 | +社区贡献者还是在 `apecloud/ApeRAG` 提 PR (开源仓继续是社区入口), maintainer review + merge 到开源主分支。 |
| 135 | + |
| 136 | +之后每周一次 bot 自动跑一个任务: |
| 137 | + |
| 138 | +```bash |
| 139 | +git fetch upstream main # upstream = apecloud/ApeRAG |
| 140 | +git merge upstream/main # 合并到企业仓主分支 |
| 141 | +# 跑企业全量 CI, 通过则推送企业仓 main |
| 142 | +``` |
| 143 | + |
| 144 | +这样开源仓的所有改动 (社区 PR + cherry-pick 回来的企业改动) 都自动同步到企业仓, 不会丢。 |
| 145 | + |
| 146 | +### 4.4 防泄漏 (4 道闸, 不是 1 道) |
| 147 | + |
| 148 | +不靠任何单一机制, 4 道闸叠加: |
| 149 | + |
| 150 | +1. **路径闸**: CI 静态分析每个 PR, 检查开源路径不能 import 企业路径 — 违反 build 红 |
| 151 | +2. **License header 闸**: CI 检查企业文件首行必须有商业许可 header, 开源文件不能有 — 违反 build 红 |
| 152 | +3. **关键词扫描闸**: CI 跑 grep 扫描 PR 改动, 如果开源路径里出现客户名 / 私有 endpoint / API key / 商业许可关键词等 — 警告 + 可能 block (whitelist 化, 不依赖 commit message) |
| 153 | +4. **同步预演闸**: 每个 PR 跑 dry-run sync, 显示对开源仓的实际影响给 reviewer 看, reviewer 是最后一道人审 |
| 154 | + |
| 155 | +任何一道闸 fail 都不允许 merge。 |
| 156 | + |
| 157 | +## 5. 启动时机和时间表 |
| 158 | + |
| 159 | +### 5.1 启动前提 (双 gate) |
| 160 | + |
| 161 | +启动企业版迁移之前必须满足两个条件: |
| 162 | + |
| 163 | +1. **earayu2 确认渐进式方向** (本文档 ratify) |
| 164 | +2. **当前 in-flight 工作收口**: |
| 165 | + - PR #1951 (可观测性 P0 spec) ratify + merge |
| 166 | + - PR #1952 v2 (可观测性需求对齐文档) 重写 + ratify + merge |
| 167 | + - task #89 telemetry P0 子任务 X1-X5 dispatch + 完成 |
| 168 | + - task #11 GC orphan vector follow-up |
| 169 | + - huangheng follow-up sediment fold-in queue (cr-checklist 累计 lesson) |
| 170 | + |
| 171 | +为什么要等 in-flight 收口: 这些 epic 都在 `apecloud/ApeRAG` 主仓上正常推进, 如果同时切主仓写权 + 启动迁移, 会让所有 in-flight PR 不知道往哪个仓提, 造成混乱。huangheng 在讨论里专门提了这个时序约束 (msg=1320ff5a), 团队一致同意。 |
| 172 | + |
| 173 | +### 5.2 时间表 (启动后约 1-1.5 周) |
| 174 | + |
| 175 | +| 步骤 | 内容 | 工期 | 主导人 | |
| 176 | +|------|------|------|------| |
| 177 | +| Step 0 | freeze in-flight, 等所有正在跑的 PR / task 收口 | 1-3 天 | PM @不穷 | |
| 178 | +| Step 1 | 建仓: `git push --mirror` 把 `apecloud/ApeRAG` 完整历史推到 `apecloud/aperag-enterprise` + 配 remote | ~1 天 | @Planetegg (SRE) | |
| 179 | +| Step 2 | 加企业目录 + import 闸 + License header 闸 + 关键词闸 + 同步预演闸 + PR 模板 + 同步策略文档 | ~3 天 | @符炫炜 (代码边界 + 策略) + @明书 (CI gate 工具) | |
| 180 | +| Step 3 | 双向同步 bot + 团队培训 PR 标签纪律 + 一次完整 round-trip 验证 | ~3 天 | @Planetegg (CI) + @符炫炜 (培训) | |
| 181 | + |
| 182 | +最后一次 round-trip 验证: 把企业仓主分支跑一次抽取 → 跟当前 `apecloud/ApeRAG` 主分支对比, **必须 0 diff**。如果有 diff 说明哪里出问题, 修完再来一次, 直到 0 diff 才上。 |
| 183 | + |
| 184 | +### 5.3 启动后 |
| 185 | + |
| 186 | +- 团队日常开发全切到 `apecloud/aperag-enterprise` |
| 187 | +- `apecloud/ApeRAG` 仍正常接受社区 PR (不锁写, 不 force-push) |
| 188 | +- 周期性 bot 双向 sync 跑起来 |
| 189 | +- 1-2 个月后看运行数据, 决定是否需要进一步升级 (见下面 § 8) |
| 190 | + |
| 191 | +## 6. 角色分工 |
| 192 | + |
| 193 | +| 角色 | 谁 | 工作 | |
| 194 | +|------|------|------| |
| 195 | +| 仓库搭建 + CI workflow + 同步 bot | @Planetegg (SRE) | step 1 + step 3 主导 | |
| 196 | +| 代码边界设计 + `enterprise-sync-policy.md` 起草 + PR 标签纪律 spec | @符炫炜 (架构) | step 2 主导 | |
| 197 | +| CI gate 工具 (import 闸 / 同步预演闸 / round-trip 测试) | @明书 (资深程序员) | step 2 协作, 起草 `tools/sync_oss.py` + `.ossignore` + GH Action | |
| 198 | +| 架构 cross-CR boundary 一致性 | @Weston | step 2 完成后审 + step 3 round-trip 验证 | |
| 199 | +| cr-checklist sediment 入仓 | @huangheng | step 完成后 fold 进 cr-checklist (Lesson 应用 demo) | |
| 200 | +| 测试边界 + 防泄漏 lint | @huangzhangshu | step 2 + step 3 协助 | |
| 201 | +| 前端开源边界 verify | @dongdong | step 2 web 目录边界审 | |
| 202 | +| index/worker domain verify | @ziang | step 2 backend 目录边界审 | |
| 203 | + |
| 204 | +PM @不穷 推进节奏。 |
| 205 | + |
| 206 | +## 7. 风险 + 应对 |
| 207 | + |
| 208 | +| 风险 | 影响 | 应对 | |
| 209 | +|------|------|------| |
| 210 | +| 现有 in-flight PR 一直没 drain | 启动时机延后 | freeze + 加速现有 epic 收口, 不并发 | |
| 211 | +| 团队适应 PR 标签纪律慢 | 早期可能有 mixed PR 提交 | CI 强制拒, 自然倒逼; 第一周做培训 | |
| 212 | +| 法务边界没拍板就启动 | 后期反复改目录 | step 0 之前 earayu2 + 法务先拍板「哪些功能开源 / 哪些企业独占」, 边界一次定 | |
| 213 | +| 开源用户问「为什么没有 X 功能」 | 社区体验 | docs/enterprise/ 写清楚开源版 / 企业版差异表; 开源 README 不出现企业字眼 | |
| 214 | +| 同步 bot 出 bug 让企业代码漏到开源仓 | 严重泄漏事故 | 4 道闸叠加 + round-trip 测试 + dry-run sync 预演给 reviewer 看, 单点失误不会直接漏 | |
| 215 | +| 企业代码越来越多, 开源版 scope 萎缩 | 开源版失去吸引力, 影响品牌 | 每月 review 一次开源版 / 企业版功能比例, 关键能力守住开源 (检索 / 索引 / 图谱 / agent 框架等核心) | |
| 216 | + |
| 217 | +## 8. 之后什么时候重评 |
| 218 | + |
| 219 | +启动后 1-3 个月数据驱动重评。触发条件 (任何一个就启动重评讨论): |
| 220 | + |
| 221 | +- **企业代码总行数 > 开源代码总行数的 30%** → 评估是否要做更深的代码分层 (比如 packages 化) |
| 222 | +- **手工 cherry-pick 回流的 PR 月 > 30 个** → 评估是否要把 cherry-pick 流程自动化加强 |
| 223 | +- **同步预演闸 false-positive 月 > 5 次** → 加强 import 闸的静态分析精度 |
| 224 | +- **社区抱怨「开源版功能缩水」反馈频率 > 1 次/周** → 重新评估开源 / 企业边界 |
| 225 | + |
| 226 | +到时候团队再开会讨论, 不预先承诺升级时机和方案。 |
| 227 | + |
| 228 | +## 9. 不做什么 (避免折腾) |
| 229 | + |
| 230 | +- **不做** 一次性把现有 OSS 代码重组到 `packages/community-core/` 这种新目录 — 风险太大, 牵动太多 (Weston 在讨论里专门 push back 了我前面这个方案 msg=846de8f2) |
| 231 | +- **不做** 用 `git filter-repo --subdirectory-filter` 自动重写开源仓主分支历史 — 会破坏现有社区 fork / PR 评论里的 commit hash 引用, 信誉成本高 (Weston msg=3b42599f) |
| 232 | +- **不做** 把开源仓锁成 bot-only 写权限 — 切断社区 PR 入口 (Weston msg=30f96387) |
| 233 | +- **不做** 单仓多分支 / 单仓 build flag 编译切换 — 开源用户 git clone 能看到企业代码, 知识产权 / 法律风险大 |
| 234 | +- **不做** 把 commit message 黑名单作为防泄漏主要防线 — 测试 / fixture / docs / 配置 / 注释都可能泄漏, 黑名单 cover 不全 (Bryce msg=d6120b07 自己撤回了这个方案) |
| 235 | +- **不做** 给所有现有外部贡献者发邮件强制迁移 — 让社区在公开仓继续提 PR 是更自然的协作方式 |
| 236 | +- **不做** 短期内大改 alembic migration chain 拆多 head — 双仓维护下多 head 很脆弱, 必要时 EE 表用前缀 + 共享单链 (huangheng msg=1320ff5a) |
| 237 | + |
| 238 | +## 10. 法务边界 (启动前必须拍板) |
| 239 | + |
| 240 | +技术方案不能解决法务边界问题。启动前 earayu2 + 法务必须先拍板: |
| 241 | + |
| 242 | +**开源必有** (`apecloud/ApeRAG` 永远包含): |
| 243 | +- 现有 ApeRAG 全部基础功能 (向量索引 / 全文索引 / 图谱索引 / 检索 / 重排 / agent 框架 / admin 基础) |
| 244 | +- 文档解析 / chunk / embedding 基础流程 |
| 245 | +- 现有部署 (Docker / Helm / 基础 SRE) |
| 246 | + |
| 247 | +**企业独占** (候选, 待 earayu2 + 法务确认): |
| 248 | +- License 管理 / Edition gate |
| 249 | +- SSO / 高级权限管理 / audit log |
| 250 | +- 客户定制 connectors (specific customer integrations) |
| 251 | +- 私有部署高级配置 (HA / 多 region / 混合云) |
| 252 | +- 企业 dashboard (cost / token / SLA UI) |
| 253 | +- 高级 LLM 账本和 cost 归因 UI (per task #89 P2 LLM ledger 上层 UI 部分) |
| 254 | + |
| 255 | +边界一次定下来, 后期不要反复改。如果未来要把某个企业功能开源, 走单独流程: 该功能从 `enterprise/` 移到 `aperag/` + 改 License header + 在企业仓里走 `oss-safe` PR + cherry-pick 回开源。 |
| 256 | + |
| 257 | +## 11. 关联文档 |
| 258 | + |
| 259 | +- earayu2 directives: `#企业版` msg=c2c8d8f2 + msg=c0b009e2 |
| 260 | +- 团队讨论 trail: `#企业版` 10 lane converge (Weston / dongdong / 符炫炜 / ziang / huangzhangshu / 不穷 / huangheng / 明书 / Bryce / Planetegg) |
| 261 | +- 同步策略详细 spec: `enterprise-sync-policy.md` (启动后 step 2 起草) |
| 262 | +- 当前 in-flight 收口 list: PR #1951 / PR #1952 / task #89 X1-X5 / task #11 / sediment fold-in queue |
| 263 | +- 现有 license 模式: `apecloud/ApeRAG` Apache 2.0 |
| 264 | + |
| 265 | +--- |
| 266 | + |
| 267 | +**起草**: @符炫炜 (总架构师) |
| 268 | +**日期**: 2026-04-30 |
| 269 | +**版本**: v1 (10 lane 团队讨论收口 + earayu2 directive 后起草; 待 earayu2 ratify + 法务边界拍板后启动) |
| 270 | +**讨论模式**: 跟 task #31 Phase A 自然中文实施方案 (PR #1934) 同 directive — 用自然中文回答业务问题, 不堆内部术语 |
0 commit comments