No description
- Go 51.9%
- TypeScript 25.1%
- JavaScript 8%
- Python 7.7%
- CSS 6.9%
- Other 0.4%
| build | ||
| cmd | ||
| controllers/markitdown | ||
| deploy/executor-manager | ||
| docs | ||
| internal | ||
| pkg | ||
| protocol | ||
| sdk | ||
| tests | ||
| web/platform | ||
| workers/markitdown | ||
| .dockerignore | ||
| .gitignore | ||
| go.mod | ||
| go.sum | ||
| README.md | ||
Layla TAB V2 项目说明文档
基于提交
d125797cb1411233cfcd0c6afdb1b08cfa408998("test(platform-web): cover spec editing and task filters")分析。
一、项目定位
Layla TAB V2 是一个任务执行控制平面(Control Plane),用于注册业务契约(Spec)、将任务路由到本地执行器 Worker、并在组件之间搬运产物(Artifact),同时保证 Platform 不与任何业务逻辑耦合。
核心思想:Platform 永远只是控制面——它校验、存储、匹配、转发 Spec,但从不执行业务任务、从不发明业务版本,业务逻辑被严格隔离在独立的 Worker / Controller 进程中。
二、整体架构
2.1 四层组件
┌─────────────────────────────────────────────────────────────┐
│ Controller(浏览器 iframe 中的业务 UI,如 MarkItDown UI) │
│ ——通过 Host SDK 桥接,无任何凭据 │
└──────────────────────────────┬──────────────────────────────┘
│ Controller Profile(postMessage 桥)
┌──────────────────────────────▼──────────────────────────────┐
│ Platform(唯一以 Docker 容器部署的组件,Go + React 19) │
│ 管理 Manager/Worker/Spec/Controller/Task/Artifact 注册表 │
│ 持有长期 S3 凭据,签发短期 Presigned URL │
└──────────────────────────────┬──────────────────────────────┘
│ Platform Protocol v1(HTTP+Bearer Key,Manager 主动拉取)
┌──────────────────────────────▼──────────────────────────────┐
│ Executor Manager(执行主机上的原生进程,Go) │
│ 持有 Manager Key;管理工作区;通过 Presigned URL 中转文件 │
└──────────────────────────────┬──────────────────────────────┘
│ Manager/Worker Runtime Protocol v1
│ (仅 loopback WebSocket,127.0.0.1:9090)
┌──────────────────────────────▼──────────────────────────────┐
│ Worker(业务执行进程,如 Python MarkItDown Worker) │
│ 无任何凭据:无 Platform URL / Manager Key / S3 凭据 │
└─────────────────────────────────────────────────────────────┘
2.2 凭据与信任边界
| 组件 | 持有的秘密 | 绝不能持有 |
|---|---|---|
| Platform | S3 长期凭据、管理员会话、OIDC 配置 | — |
| Manager | Manager Key(Bearer Token) | S3 凭据 |
| Worker | 仅 Worker ID(非秘密) | Manager Key、Platform URL、S3 凭据 |
| Controller | 无(不直接持有任何凭据或 Presigned URL) | 一切凭据与传输 URL |
Artifact 的跨组件身份是 Artifact ID(而非 S3 object key),文件传输全部通过 Platform 签发的短期 Presigned GET/PUT 完成。
三、Monorepo 目录结构
Layla-TAB-V2/
├── cmd/
│ ├── layla-platform/ # Platform 可执行入口(Go)
│ └── layla-manager/ # Manager 可执行入口(Go)
├── internal/
│ ├── platform/ # Platform 核心实现
│ │ ├── app/ # HTTP 服务器 + Controller Host
│ │ ├── core/ # 任务引擎、注册表、Artifact 生命周期
│ │ ├── controller/ # Controller 包安装与校验
│ │ ├── persistence/ # Platform SQLite
│ │ ├── spec/ # Spec JSON Schema 校验
│ │ └── storage/ # S3 / MinIO 客户端
│ └── manager/ # Executor Manager 实现
│ ├── app/ # Manager 生命周期
│ ├── config/ # env/flag 配置加载
│ ├── hostmetrics/ # 主机指标采集(CPU/内存/磁盘)
│ ├── persistence/ # Manager SQLite(独立库)
│ ├── platformclient/ # Platform Protocol v1 客户端
│ ├── runtime/ # Worker WebSocket 运行时
│ └── workspace/ # 任务工作区、路径遍历防护
├── protocol/ # 所有公开契约的唯一事实来源
│ ├── platform/v1/ # Platform Protocol(OpenAPI 3.1)
│ ├── spec/v1/ # Spec Protocol Meta Standard(JSON Schema)
│ ├── manager-worker/v1/ # Manager↔Worker 运行时消息(JSON Schema)
│ └── controller/v1/ # Controller Manifest + 桥接消息 Schema
├── sdk/
│ ├── manager-worker/go/ # Go Worker SDK
│ ├── manager-worker/python/ # Python Worker SDK
│ └── controller/typescript/ # Controller Host SDK (@layla/controller-sdk)
├── workers/
│ └── markitdown/ # 第一个真实业务 Worker(Python + MarkItDown 0.1.1)
├── controllers/
│ └── markitdown/ # MarkItDown Controller(React 19 + Vite,静态 ZIP 包)
├── web/
│ └── platform/ # Platform 管理后台(React 19 + Vite + lucide-react)
├── deploy/
│ └── executor-manager/ # 原生部署布局 + systemd 单元模板
├── build/ # 三个 Dockerfile(platform / manager / worker)
├── tests/
│ ├── e2e/ # Phase3/Phase4 验收测试(Python + Playwright)
│ └── fixtures/
└── docs/
├── INVARIANTS.md # 26 条架构不变量(验收标准)
├── guides/ # 手动安装指南
├── proposals/ # 协议演进提案(MWPV1-001、PPV1-001)
└── reports/ # Phase 1–4 完成报告
四、核心协议(protocol/ 为唯一事实来源)
| 协议 | 版本 | 形式 | 用途 |
|---|---|---|---|
| Platform Protocol | v1 | OpenAPI 3.1 YAML | Manager → Platform 的拉取式 API(心跳、Worker 同步、任务认领/状态、Artifact 授权、异常上报) |
| Spec Protocol Meta Standard | v1 | JSON Schema (2020-12) | 定义业务契约(输入 payload/artifacts + 输出 result/artifacts) |
| Manager/Worker Runtime Protocol | v1 | JSON Schema | loopback WebSocket 上的消息(hello / execute / started / progress / succeeded / failed / ping) |
| Controller Manifest | v1 | JSON Schema + OpenAPI | Controller 包清单与 Host 桥消息 |
兼容性原则:同一主版本内只能增量演进(加可选字段/端点/错误码),必填字段不可删除、改名或收紧;解析方必须忽略未知可选字段。
五、Spec(业务契约)机制
Spec Name + Spec Version唯一标识一个不可变定义。- 内容以规范 JSON(canonical JSON)计算
sha256摘要;同名同版本但摘要不同即为冲突。 - 第一个上报某 Spec 的 Worker 会产出该 Spec 的初始定义;旧版本永不覆盖。
- 创建 Task 时会冻结 Spec 的 Name/Version/Digest。
- Manager 把
spec_payload/spec_result当作不透明 JSON 透传,永不解析业务字段。 - Controller 与 Worker 的 Active Spec 版本必须一致才能新建任务。
示例(MarkItDown/1.0):输入 1 个本地文档(PDF/DOCX/PPTX/XLSX/HTML/CSV 等),输出 1 个 text/markdown Artifact,结果含字符数、文件名、MarkItDown 版本号。
六、技术栈
| 层 | 技术 |
|---|---|
| Platform | Go 1.24(gorilla/websocket、minio-go v7、go-oidc v3、modernc.org/sqlite),React 19 + Vite + TypeScript 管理后台 |
| Manager | Go 1.24,原生部署(systemd),loopback WebSocket 服务 |
| Worker SDK | Go / Python(≥3.10)双实现 |
| 示例 Worker | Python + Microsoft MarkItDown 0.1.1(docx/pdf/pptx/xlsx extras),仅用 convert_local() |
| Controller SDK | TypeScript @layla/controller-sdk(稳定 Context / Spec / Worker / Artifact / Task API) |
| 示例 Controller | React 19 + Vite,构建为确定性 ZIP 静态包 |
| 存储 | SQLite(WAL,Platform 与 Manager 各自独立库)+ S3 兼容对象存储(MinIO 验证通过) |
| 认证 | 本地管理员会话 + OIDC Authorization Code + PKCE(state/nonce/签名/issuer/audience 校验) |
| 部署 | 仅 Platform 为 Docker 容器(distroless nonroot);Manager/Worker 原生 systemd 部署 |
七、部署形态
执行主机(原生目录树,归 layla-executor 系统账户所有):
executor-manager/
├── bin/layla-manager
├── config/manager.env # 含 Manager Key,权限 0600
├── data/manager.db + workspaces/
├── systemd/*.service # Manager 与 Worker 的单元模板
└── workers/markitdown/
├── config/worker.env # 仅 Worker ID + loopback 地址(无秘密)
└── venv/
- Platform 容器暴露
:8080,Manager Worker 运行时监听127.0.0.1:9090。 - Worker 崩溃不会拖垮 Manager;Controller 崩溃/异常请求不影响 Platform
/healthz。 - 默认 Worker 并发为 1;业务失败不自动重试,人工重试会创建新 Task。
八、开发门槛(Development Gates)
Platform → Manager → Worker → Controller
每个组件必须通过自己的测试才能进入下一层。验收测试在指定 Linux 主机 /opt/agent/Layla_TAB_V2 上执行。仓库内含:
- Go 单元测试与契约测试(含 race-enabled)
- Python SDK / Worker 测试(生产镜像内、非 root 运行)
- TypeScript 类型检查 + Vite 生产构建(零 npm audit)
- Playwright/Chromium 真实浏览器端到端验收(Phase 4:上传 → 建任务 → 轮询 → 下载 Markdown 全链路)
九、26 条架构不变量(要点摘录)
docs/INVARIANTS.md 是验收标准而非建议,关键条目:
- Platform 永不执行业务任务;无 Manager/Worker/Controller/S3 也能启动。
- Platform 永不主动连接 Manager;Manager 用 Manager Key 认证一切受保护交互。
- Task 目标是 Worker 而非 Manager;Worker 永不直连 Platform。
- Manager 视
spec_payload/spec_result为不透明 JSON。 - Controller 永不直连 Manager/Worker,只能走 Host SDK。
- Spec 不可变:同名同版本不同 digest = 冲突;旧版本不覆盖。
- 业务失败不自动重试;Artifact ID 是跨组件文件身份(不是 S3 key)。
- 长期 S3 凭据只留在 Platform。
十、当前版本状态(d125797)
四个 Phase 全部完成,首个真实业务闭环已打通:
Controller → Platform Host SDK → Platform → Manager → Worker → Artifact → Controller
- 验收实证:Worker
wrk_8f50f284a76c36bbcc584579129bfdc9,Spec digestsha256:6162f8f3…93bc4,浏览器上传 HTML → 任务tsk_693591af…成功 → 下载 85 字节 Markdown 结果。 - 已验证的隔离性:未知 Worker 隔离、过期会话拒绝、崩溃隔离、禁用 Manager 拒领任务、zip-slip/路径遍历防护、Manager Key 不泄露给 Presigned 目标。
十一、快速上手
# Platform(Docker)
docker build -f build/platform.Dockerfile -t layla-platform .
# 运行需 env:LAYLA_S3_ENDPOINT/BUCKET/ACCESS_KEY/SECRET_KEY、
# LAYLA_ADMIN_USERNAME/LAYLA_ADMIN_PASSWORD 等
# Manager(原生)
go build ./cmd/layla-manager
# 配置 deploy/executor-manager/config/manager.env(Manager Key、Platform URL)
# MarkItDown Worker(原生 Python venv)
cd workers/markitdown && pip install .
LAYLA_WORKER_ID=wrk_xxx LAYLA_MANAGER_ADDRESS=127.0.0.1:9090 layla-markitdown-worker
# 管理后台开发
cd web/platform && npm ci && npm run dev
# Controller 打包
cd controllers/markitdown && npm ci && npm run package # 产出可安装的 ZIP
十二、已知限制与风险
- Platform V1 使用内存会话,重启后需重新登录(单实例基线可接受)。
- UI 中修改存储设置后需重启 Platform 才能重建 S3 客户端。
- Manager 重启后不恢复进行中的任务,已认领任务需显式解决。
- Worker 传输为可信 loopback WebSocket,无独立 Worker 密钥——主机级进程隔离属运维责任。
- MarkItDown 为上游 beta 依赖,升级需走显式 Worker 发布 + 新测试镜像。
- Controller 隔离基于浏览器 iframe sandbox(
allow-scripts allow-forms allow-downloads,无allow-same-origin)+ CSP,而非独立 OS 进程。