diff --git a/docs/monorepo-design.md b/docs/monorepo-design.md new file mode 100644 index 0000000..c63a881 --- /dev/null +++ b/docs/monorepo-design.md @@ -0,0 +1,241 @@ +# light-ocr Monorepo 设计 + +状态:草案(2026-07-21)。 +受众:维护者、贡献者。本文定义 monorepo 的目录结构、包依赖关系、迁移路径和约束,不替代各包自身的实现设计。 + +## 1. 动机 + +Roadmap §3.1 规划了 7+ 个 npm 包(runtime、light-ocr、tiny、medium、document、layout、model-*),加上 server-side OCR 服务后达到 8+ 个。当前 `bindings/node/` 单包结构无法支撑跨包改动(如 runtime 提取后 tiny/medium/document 都需要同步更新)。Monorepo 用 npm workspaces 统一管理这些包,保持一次 install、一次 lint、一次 test 的开发体验。 + +## 2. 目录结构 + +``` +light-ocr/ +├── package.json # root workspace config(private, workspaces) +├── packages/ +│ ├── runtime/ # @arcships/light-ocr-runtime +│ │ ├── package.json +│ │ ├── src/ +│ │ └── test/ +│ ├── light-ocr/ # @arcships/light-ocr(small 默认,从 bindings/node 迁移) +│ │ ├── package.json # 含 "bin": { "light-ocr": "./src/cli.cjs" } +│ │ ├── src/ +│ │ └── test/ +│ ├── light-ocr-server/ # @arcships/light-ocr-server(REST API + Docker) +│ │ ├── package.json +│ │ ├── Dockerfile +│ │ ├── .dockerignore +│ │ ├── src/ +│ │ └── test/ +│ ├── light-ocr-tiny/ # @arcships/light-ocr-tiny(N2) +│ ├── light-ocr-medium/ # @arcships/light-ocr-medium(N2) +│ ├── light-ocr-document/ # @arcships/light-ocr-document(N3) +│ ├── light-ocr-layout/ # @arcships/light-ocr-layout(N4) +│ └── model-*/ # @arcships/light-ocr-model-*(纯数据包) +├── native/ # native addon 源码与 CMake(从 bindings/node 拆出 JS 后的残留) +│ ├── CMakeLists.txt +│ └── src/ +│ └── addon.cpp +├── src/ # C++ Core(不变) +├── docs/ +├── tests/ # 跨包集成测试与 corpus +├── tools/ +└── contracts/ # 公共契约(cli-design.md §2.5 的 contracts/) + ├── cli/ + │ ├── flags.json5 + │ ├── envelope.schema.json + │ ├── exit-codes.json + │ └── fixtures/ + └── errors/ + └── ocr-error-codes.json +``` + +### 2.1 关键设计决策 + +- **`native/` vs `packages/native/`:** native addon 不是独立的 npm 用户入口包,其预编译产物通过 platform-specific optional dependency 被 `runtime` 引用。`native/` 放在根目录,与 `src/`(C++ Core)平级,保持 CMake 构建路径简洁。 +- **`contracts/`:** 多个包共享的 flag 定义、schema、exit code 表、golden fixtures。单一来源,由各包的构建/测试脚本读取。 +- **`packages/light-ocr/` 的 bin:** roadmap §3.1 规定 `light-ocr` bin 只属于默认 small 包。tiny/medium 若有 CLI,bin 命名为 `light-ocr-tiny` / `light-ocr-medium`。 +- **`packages/light-ocr-server/`:** 唯一携带 Dockerfile 的包。它是一个 npm 包(可发布到 registry),也是一个可独立构建的 Docker 镜像。 + +## 3. 包依赖关系 + +```text +@arcships/light-ocr-runtime +├── native addon(platform-specific optionalDependencies) +├── express? 否 — runtime 不含 HTTP 层 +└── 不默认携带模型 + +@arcships/light-ocr +├── exact: @arcships/light-ocr-runtime +├── exact: @arcships/light-ocr-model-ppocrv6-small +├── bin: light-ocr +└── 唯一代表"开箱即用"的默认入口 + +@arcships/light-ocr-server +├── exact: @arcships/light-ocr(默认 small 模型) +├── express, multer +├── Dockerfile(基于 node:22-trixie-slim) +└── 部署制品:Docker 镜像 + +@arcships/light-ocr-tiny / -medium +├── exact: @arcships/light-ocr-runtime +├── exact: 对应模型包 +└── 与 light-ocr 共享相同 JS API + 类型 + +@arcships/light-ocr-document(N3) +├── exact: @arcships/light-ocr-runtime(或接受注入的 engine factory) +├── PDF renderer(S3 接受分支) +└── 不强制依赖特定杯型 + +@arcships/light-ocr-layout(N4) +├── exact: @arcships/light-ocr-runtime +├── exact: Layout 模型包 +└── 不拥有 CLI bin +``` + +### 3.1 Server 的依赖方向 + +Server 依赖 `@arcships/light-ocr`(默认 small),而不是 `runtime`。这确保 server 开箱即用:一个 `docker run` 就能跑 OCR,不需要用户另外装模型。 + +未来可选支持通过环境变量切换模型杯型(例如 `MODEL_PACKAGE=@arcships/light-ocr-medium`),但默认保持 small。 + +## 4. 工具链 + +### 4.1 选择:npm workspaces + +当前项目使用 npm,零额外工具迁移成本。 + +```jsonc +// 根 package.json +{ + "private": true, + "workspaces": [ + "packages/*", + "native" + ] +} +``` + +- `npm install` 在根目录执行,自动为所有 workspace 安装依赖并创建 symlink。 +- `npm test --workspaces` 运行所有包的测试。 +- `npm publish --workspace packages/light-ocr` 发布单个包。 + +不需要 rush、lerna、turbo 等额外编排工具,当前 8 个包的规模 npm workspaces 完全够用。如果将来需要统一版本发布、changelog 生成,再评估 changesets。 + +### 4.2 版本策略 + +采用**独立版本**(independent versioning),每个包有自己的 `version` 字段: + +| 包 | 版本锚点 | 说明 | +| --- | --- | --- | +| `runtime` | 与 Core 版本解耦 | 适配层,变化频率低 | +| `light-ocr` | 跟随项目 semver | 默认入口,用户感知的主版本号 | +| `server` | 独立 semver | 部署制品,有自己的 breaking change 周期 | +| `model-*` | 与模型 bundle ID 对齐 | 数据包,模型变更时发新版 | +| `tiny/medium/document/layout` | 各自独立 | 按各自成熟度独立发版 | + +约束: +- `light-ocr` 精确锁定 `runtime` 和 `model-*` 的兼容版本(`"@arcships/light-ocr-runtime": "1.2.3"` 精确 pin,不用 `^`)。 +- `server` 精确锁定 `light-ocr` 版本。 +- 每次 `light-ocr` 发版时,同步检查 `server` 是否需要更新依赖版本。 + +## 5. 迁移路径 + +### 5.1 阶段 0:当前状态(不破坏现有结构) + +``` +bindings/node/ # @arcships/light-ocr,JS + native addon 混合 +├── js/ # JS facade(未来 → packages/runtime/) +├── src/ # native addon(未来 → native/) +├── CMakeLists.txt +└── package.json +``` + +### 5.2 阶段 1:建立 monorepo 骨架(N2 启动时) + +- 创建 `packages/runtime/`,从 `bindings/node/js/` 迁移 JS facade 代码。 +- 创建 `packages/light-ocr/`,依赖 `runtime` + 模型包,包含 CLI bin。 +- `native/` 保持 addon 源码 + CMake,平台预编译包独立发布。 +- `bindings/node/` 标记为 deprecated,保留到确认迁移稳定后删除。 +- 此阶段 CI 同时运行旧路径和新 workspace。 + +### 5.3 阶段 2:加入 server(N2 完成或 N3 前后) + +- `packages/light-ocr-server/` 加入 workspace。 +- Dockerfile 使用两阶段构建或从 npm registry 安装依赖。 +- 本地开发时 `npm install` 自动 symlink workspace 内的 `light-ocr`,无需先发布。 + +### 5.4 阶段 3:加入 tiny、medium(N2 GA) + +- 两个新包加入 workspace。 +- 验证三杯型共享同一 API、类型、测试套件。 + +### 5.5 阶段 4:document、layout(N3、N4) + +- 按各自节点加入。 + +## 6. Server Docker 构建 + +Server 是特殊的包:它既作为 npm 包发布,也作为 Docker 镜像分发。 + +### 6.1 Dockerfile 策略 + +```dockerfile +# packages/light-ocr-server/Dockerfile +FROM node:22-trixie-slim + +WORKDIR /app + +# 从 npm registry 安装(生产模式不需要 workspace) +COPY package.json package-lock.json ./ +RUN npm ci --omit=dev + +COPY src/ ./src/ + +RUN groupadd -r ocr && useradd -r -g ocr ocr +USER ocr + +EXPOSE 3000 +ENV EXECUTION_MODE=cpu +ENV QUEUE_CAPACITY=4 + +CMD ["node", "src/server.js"] +``` + +### 6.2 本地开发 vs 生产构建 + +- **本地开发**:`npm install`(workspace 解析为 `packages/light-ocr/` 的 symlink),直接 `node src/server.js`,改动即时生效。 +- **生产 Docker 构建**:`npm install` 走 npm registry,拉取已发布的 `@arcships/light-ocr`。镜像构建独立于 monorepo。 +- **CI 集成测试**:先 `npm install`(workspace),再 `npm test --workspace packages/light-ocr-server`,验证 server + engine 的端到端行为。 + +### 6.3 与 docker-compose 的关系 + +根目录 `docker-compose.yml` 引用 `packages/light-ocr-server/Dockerfile`: + +```yaml +services: + light-ocr-api: + build: + context: . + dockerfile: packages/light-ocr-server/Dockerfile + ports: + - "3000:3000" + environment: + - EXECUTION_MODE=cpu +``` + +## 7. 约束 + +- **根 `package.json` 不包含业务依赖。** 只声明 `workspaces` 和顶层 scripts(lint、test、build 编排)。 +- **每个包独立可发布。** `npm publish --workspace ` 不依赖 workspace symlink。 +- **跨包依赖使用精确版本。** `"@arcships/light-ocr": "0.4.0"`,不用 `^` 或 `~`。 +- **`contracts/` 是跨包共享的单一来源。** 各包 CI 从 `contracts/` 生成 flag parser 或验证 golden fixtures,不自行复制 schema。 +- **`native/` 不在 npm workspace 中发布为用户包。** 它只作为 `runtime` 的 platform-specific optionalDependency 的构建源。 +- **Server 的 Docker 镜像版本与 npm 包版本保持一致。** 每次 `packages/light-ocr-server/package.json` 的 version bump 对应一个 Docker image tag。 + +## 8. 不做 + +- 不引入 rush/lerna/turbo/nx 等额外编排工具,除非 npm workspaces 被证明不够用。 +- 不把所有包强制统一版本号(lockstep versioning)。server 和 light-ocr 的 breaking change 周期不同。 +- 不修改 C++ Core 的源码目录结构。 +- 不在 monorepo 迁移完成前向用户承诺 server package 的 API 稳定性。 diff --git a/docs/roadmap.md b/docs/roadmap.md index 9d5ef90..6f9a54b 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -3,7 +3,7 @@ ![light-ocr Roadmap 像素风宣传图](assets/light-ocr-roadmap.png) - 状态:Draft -- 更新时间:2026-07-16 +- 更新时间:2026-07-21 - 适用范围:`0.2.x` 之后至 `1.0` 的产品与工程演进 ## 1. 目标与定位 @@ -159,6 +159,7 @@ Roadmap 结束时应形成以下入口,而不是一个不断膨胀的单包 AP | `@arcships/light-ocr-layout`(逻辑角色) | 显式选择 Layout 的用户 | Layout analyzer、公共 label 映射和 capability resolver;依赖 runtime 与一个精确 Layout model,不拥有 CLI bin | | `@arcships/light-ocr-model-`(逻辑角色) | 由 Layout capability 间接安装 | 纯数据 Layout bundle、manifest、license 和模型 identity;不包含编排代码 | | Agent Skill / Plugin | Codex 与其他可调用本地命令的 Agent | 选择正确命令、约束输出、处理错误,不实现 OCR | +| `@arcships/light-ocr-server` | 后端服务、CI/CD pipeline、非 JS 调用方 | HTTP REST API 包装 OCR engine;Docker 镜像分发;不替代 CLI 作为本地入口 | 具体包名可在 N2/N3 的设计决策中调整,但以下约束必须保持: @@ -176,6 +177,8 @@ Roadmap 结束时应形成以下入口,而不是一个不断膨胀的单包 AP - Document Node API 接受调用方注入兼容的 engine factory,因此不强制 small;`light-ocr-document` CLI Preview 可以精确依赖 small 作为开箱即用默认值; - Layout model 不成为 Document 包的默认依赖。`@arcships/light-ocr-layout` 精确锁定兼容 runtime 和 Layout model;Document 只接受注入的 versioned Layout analyzer interface,避免反向依赖和循环依赖; - 上述 Layout 包名是待 D109 接受的逻辑角色,不在 Roadmap 中提前冻结最终 registry 名称。 +- `@arcships/light-ocr-server` 依赖 `@arcships/light-ocr`(默认 small),精确锁定兼容版本;server 的 HTTP API 与 CLI 共享相同的 OcrError 语义和 exit code 映射,但不要求 CLI 先达到 stable——server 可以独立 preview 发布。 +- server 的开发和分发依赖 monorepo 结构(见 [monorepo 设计](monorepo-design.md));在 monorepo 迁移完成前,server 作为独立仓库存在,不在主仓库 `server/` 目录下开发。 ### 3.2 结果模型演进 @@ -225,6 +228,17 @@ N1 冻结以下术语,后续 PDF 和 Layout 只能扩展,不能重新解释 - JSONL page record 带 document identity、page index 和 `status`。中途取消或失败时,已完成记录保持有效,stderr 给出终态,进程返回非零 exit code; - `structure: "ocr-order"` 表示只有 OCR 几何顺序;`structure: "layout"` 仅在 Layout compose 成功时出现,不表示结果达到人工真值。 +### 3.4 Monorepo 与工程结构 + +Roadmap §3.1 规划的产品入口对应 8+ 个 npm 包。跨包改动(runtime 提取、模型切换、共享契约更新)在单包结构下不可维护。monorepo 是这些包的工程基础,不是产品功能。 + +设计决策: + +- 工具链选择 npm workspaces,零额外迁移成本。 +- 目录结构、包依赖关系、版本策略和迁移路径见 [monorepo 设计文档](monorepo-design.md)。 +- monorepo 迁移在 N2 启动时执行(runtime 提取是迁移的第一步),不与 N1 CLI 竞争资源。 +- `packages/light-ocr-server/` 在 monorepo 就绪后加入;在此之前,server 作为独立仓库(`light-ocr-server`)存在,引用已发布的 `@arcships/light-ocr`。 + ## 4. N0 — 发布与需求基础 ### 4.1 目标 @@ -272,6 +286,8 @@ N1 冻结以下术语,后续 PDF 和 Layout 只能扩展,不能重新解释 ## 5. N1 — CLI、结果契约与 ROI +> 落地前细化设计见 [cli-design.md](cli-design.md)(2026-07-20 草案,含分发形态对比、分层 help、stdout/stderr 严格分离、退出码表、批量 JSONL 分页语义、agent 友好性 checklist 与 8 项 D-N1 待决策)。SKILL.md 草稿在 [`.agents/skills/local-ocr/SKILL.md`](../.agents/skills/local-ocr/SKILL.md)。 + ### 5.1 目标 让普通用户和 Agent 无需编写 Node.js 集成代码,即可从本地图片获得稳定文本、置信度和坐标;同时建立 PDF、Layout 和多模型都能复用的版本化结果契约。 @@ -989,7 +1005,7 @@ Roadmap 允许调整,但调整必须说明证据和受影响节点。 - 默认安装全部模型或运行时自动下载模型; - 让 tiny/small/medium 形成不同 API; - 将 PDF renderer、Layout、表格和公式全部并入 C++ OCR Core; -- 在 CLI 稳定前优先建设 MCP server; +- 在 CLI 稳定前优先建设 MCP server;REST API server 作为可选部署制品在 monorepo 就绪后提供,不阻塞 CLI 的主路径交付。 - 没有独立验证就承诺字符级坐标、任意模型兼容或 GPU 全平台; - 将 GPU 作为默认必需依赖,或把 provider 不可用静默伪装成 GPU 成功; - 为内部实现名称保留长期兼容 shim; @@ -1015,6 +1031,7 @@ Roadmap 允许调整,但调整必须说明证据和受影响节点。 - [Apple Device 加速技术方案](apple-device-acceleration.md) - [Windows Device 加速技术方案](windows-device-acceleration.md) - [Linux Device 加速技术方案](linux-device-acceleration.md) +- [Monorepo 设计](monorepo-design.md) - [Core requirements](requirements.md) - [Architecture](architecture.md) - [Accepted and deferred decisions](decisions.md)