Files
app/APP架构设计.md
T

529 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# LineUp App 架构设计
**状态:** 当前权威设计基线
**更新日期:** 2026-08-04
**适用实现:** Tauri 2 Desktop Host 与同代码 Web Reference Host
**本文取代:** `DESIGN.md``M4_COMPATIBILITY_AND_RELEASE.md``TECHNOLOGY_SELECTION.md`
## 1. 设计结论
**LineUp 是用户安装和使用的主应用;LineUp Runtime 是 LineUp App 内部提供给小程序的核心
运行环境。** Runtime 不是与小程序平级的产品 App,也不是一个独立客户端。
```text
LineUp App
├── App Shell / Host
│ ├── 当前前台小程序的挂载与切换
│ ├── 连接状态、通知和安全恢复入口
│ └── Tauri / Web Host Provider
├── LineUp Runtime
│ ├── AppServer / Remote Agent 通信
│ ├── Conversation、Store、sync loop、outbox
│ ├── MiniApp Registry、Instance、Focus、Lifecycle
│ ├── Tool Router、Inbox、Inventory
│ ├── Surface、Capability、Artifact、Audit
│ └── LineUp MiniApp SDK
└── MiniApps
├── Interact(系统内建:IM / Audio / Video
├── Task Dashboard(参考 / 已安装小程序)
├── Whiteboard(参考 / 已安装小程序)
├── Draw-and-Guess(参考 / 已安装小程序)
└── 未来第三方小程序
```
任何 MiniApp 都必须通过 Runtime SDK 使用通信、Tool、生命周期、Surface 和系统能力;不得
建立独立 Agent 通信链路,或直接访问 Host 特权、Store、认证信息及其他 MiniApp 数据。
## 2. 产品边界与术语
| 术语 | 含义 | 不能做什么 |
|---|---|---|
| **LineUp App** | 用户实际使用的主应用、产品容器和交付单位。 | 不能把业务规则重新堆进 Shell。 |
| **App Shell / Host** | Tauri 或 Web 中的挂载、切换、通知、恢复和受限 Host Provider。 | 不解释 Agent 协议,不决定 Tool/App 路由。 |
| **LineUp Runtime** | App 内部的长期协调环境;唯一拥有通信、可靠性、MiniApp 调度与安全决策。 | 不负责任意 MiniApp 的具体 DOM 或业务 UX。 |
| **MiniApp** | 运行在 Runtime 上的功能单元。 | 不直连 Agent/AppServer,不直写 Runtime 状态。 |
| **System MiniApp** | 随 LineUp 发布、代码可信的内建 MiniApp,如 Interact。 | 仍不能绕过 Runtime 调度或 Capability Policy。 |
| **Installed MiniApp** | 经验证后在受限 Surface 中运行的小程序。 | 不访问 Host DOM、Tauri invoke、token、任意网络或其他 MiniApp。 |
| **MiniApp SDK** | Runtime 向 MiniApp 开放的受控能力集合。 | 不是通用 Web、Tauri 或 Agent SDK。 |
| **Tool** | Agent 通过 Runtime 调用的、Manifest 已声明的 MiniApp 功能。 | 不是 App 内部任意函数。 |
| **Capability** | Runtime/Host 保管的录音、文件、通知等系统能力。 | 不是 MiniApp 自动拥有的权限。 |
| **Surface** | 复杂交互使用的受限 UI 容器。 | 不承载未验证远端脚本或 Host 特权。 |
### 2.1 Interact MiniApp
`Interact` 是第一个系统级 MiniApp,也是用户与 Agent 的默认交互入口:
```text
Interact MiniApp
├── IM Mode:文字、图片、短消息、任务和结果投影
├── Audio Mode:实时语音(后续)
├── Video Mode:实时视频(后续)
└── IM 标准交互的默认 Renderer Providernotice / choice / confirm / input
```
当前实现仍保留兼容名称:
```text
产品概念:Interact MiniApp
当前 app_scopechat
当前目录:tauri/src/core-apps/chat/
```
目录和作用域改名属于独立迁移任务,不能和 Runtime/MiniApp SDK 重构混在一起。
Interact 是可信内建代码,因此可以使用 LineUp 的可信 DOM 组件;但它和所有 MiniApp 一样,
必须经 SDK 请求 Runtime 行为,不能直接访问 Transport、Conversation Store、焦点栈、App
Registry、原始 Agent Envelope 或系统能力。
## 3. 当前技术与 Host 基线
唯一客户端实现与验收基线是:
```text
Tauri 2 Desktop Host + Web Reference Host
```
它们运行同一份 TypeScript Runtime 与 MiniApp 代码,并不是两个客户端:
- **Web Reference Host**:浏览器开发、Tailscale 联调和自动化验证入口;只能提供可安全降级
的浏览器能力。
- **Tauri Desktop Host**:正式桌面交付;只在 Runtime 授权后提供文件、通知、媒体等 Host
Provider 能力。
不规划独立 Android/Kotlin 客户端,也不规划 Wails Host。已退役的 Android/Wails Spike 只保留
在 Git 历史中,不能作为架构、协议、目录或验收依据。
开发命令:
```bash
cd lineup-app/tauri
npm run web:dev # Web / Tailscale Reference Host
npm run desktop:dev # Tauri Desktop Host
npm test -- --run # Runtime、MiniApp 与 Host 回归
npm run build # TypeScript 检查与 Web production build
```
Web Host 与 AppServer 的地址必须按访问位置匹配:同机浏览器使用 `127.0.0.1`Tailscale 浏览器
使用受信任的 Tailscale 地址。`0.0.0.0` 仅是服务器监听地址,不能作为浏览器 API 目标。
## 4. Runtime 的唯一所有权
Runtime 是以下对象的唯一所有者:
```text
Transport
Conversation Store
sync loop
outbox
协议兼容与原始 Envelope 校验
作用域筛选与 message_id 去重
MiniApp Inbox 与 ACK
MiniApp Registry、Instance、Focus、Lifecycle
Tool Router、Inventory、Capability、Surface、审计与恢复
```
当前消息路径必须保持单向:
```text
AppServer / Remote Agent
→ LineUp Runtime
→ 协议、scope、权限、去重和持久化
→ MiniApp SDK Inbox / Tool Call
→ MiniApp UX
→ SDK Result / Progress / Lifecycle Request
→ Runtime 校验、审计、outbox
→ AppServer / Remote Agent
```
禁止项:
```text
MiniApp 直接 fetch AppServer 或 Agent
MiniApp 直接读写 Conversation Store、sync cursor 或 outbox
MiniApp 构造或发送原始 Agent Envelope
MiniApp 直接切换其他 MiniApp、改写 focus stack 或 Registry
MiniApp 直接调用 Tauri invoke、Host DOM 根节点或系统能力
Surface 从消息 payload 直接加载 URL、HTML、CSS、JS、Bundle 或 source
```
## 5. MiniApp 信任模型与 SDK 权限视图
所有 MiniApp 共享 Runtime 的协议语义,但按来源获得不同的 SDK 视图。
| 能力 | Interact / System MiniApp | Installed MiniApp |
|---|---:|---:|
| 接收自身 Inbox、ACK | 可以 | 可以 |
| 接收 Runtime Tool Call | 可以 | 可以 |
| 上报 progress / result / error | 可以 | 可以 |
| 请求前台、后台、关闭 | 可以,由 Runtime 决定 | 可以,由 Runtime 决定 |
| 请求 Surface | 可以,经 Runtime Policy | 可以,经 Runtime Policy |
| 请求 Capability | 可以,经 Runtime Policy | 可以,经 Runtime Policy |
| 可信内建 DOM 组件 | 可以 | 不可以 |
| 隔离 iframe / Surface Bridge | 可选 | 必须 |
| 直连 Transport、Store、Agent | 不可以 | 不可以 |
| 直接 Host / Tauri / OS 调用 | 不可以 | 不可以 |
| 读取其他 MiniApp 数据 | 不可以 | 不可以 |
系统内建不等于绕过 Runtime:可信来源只决定代码的发布与 UI 执行方式,不改变 Runtime 的
通信、焦点、Tool、权限和审计边界。
## 6. MiniApp 实例、焦点与恢复
MiniApp Registry 管理“有哪些小程序”,Instance Manager 管理“哪些实例正在运行”。二者不能
混为一个状态。
```ts
type MiniAppInstanceRecord = {
instance_id: string;
app_scope: string;
conversation_id?: string;
state:
| "starting"
| "foreground"
| "background"
| "suspended"
| "stopping"
| "stopped"
| "failed";
parent_instance_id?: string;
started_at: string;
stopped_at?: string;
error?: string;
};
```
Runtime 保存焦点栈,不以单个 MiniApp 自己的布尔状态作为事实来源:
```text
focus stack:
chat:audio-001
draw-and-guess:game-001
foreground:
draw-and-guess:game-001
background:
chat:audio-001
```
当扩展 MiniApp 关闭或失败时,Runtime 必须恢复焦点栈中的前一有效实例。重启后,Runtime
恢复有界的实例与焦点状态;`starting``stopping` 中断的实例必须安全降级为 `suspended`
不得伪装为已完成的 Host 操作。
## 7. MiniApp SDK v1
下一阶段的核心交付是 **LineUp MiniApp SDK v1**。SDK 不是万能 API,而是 Runtime 根据
Manifest、实例状态、权限和 Policy 开放的最小请求集合。
```ts
interface LineUpMiniAppSDK {
readonly context: MiniAppContext;
inbox: MiniAppInboxAPI;
tools: MiniAppToolAPI;
ui: StandardInteractionAPI;
lifecycle: MiniAppLifecycleAPI;
surfaces: MiniAppSurfaceAPI;
capabilities: MiniAppCapabilityRequestAPI;
}
type MiniAppContext = {
app_scope: string;
instance_id: string;
conversation_id: string;
app_version: string;
state: "starting" | "foreground" | "background" | "suspended";
};
```
### 7.1 Inbox
```ts
interface MiniAppInboxAPI {
list(after_message_id?: string): readonly MiniAppMessage[];
subscribe(listener: (message: MiniAppMessage) => void): Unsubscribe;
acknowledge(message_id: string): boolean;
}
```
Runtime 在投递前校验 Envelope、scope、目标 MiniApp、实例状态和去重;消息先持久化,再由
MiniApp ACK。后台化、刷新、Surface 重载或 Runtime 重启不能丢失未处理消息。
### 7.2 Tool
```ts
interface MiniAppToolAPI {
subscribe(listener: (call: MiniAppToolCall) => void): Unsubscribe;
get(call_id: string): MiniAppToolCall | undefined;
reportProgress(call_id: string, progress: MiniAppToolProgress): Promise<CommandReceipt>;
complete(call_id: string, result: JsonObject): Promise<CommandReceipt>;
fail(call_id: string, failure: MiniAppToolFailure): Promise<CommandReceipt>;
cancel(call_id: string, reason?: string): Promise<CommandReceipt>;
}
```
`complete``fail``cancel` 都是对 Runtime 的请求,不是直接网络发送。Runtime 必须验证
`call_id` 的实例归属、合法状态迁移、输入/输出 schema、幂等性和权限,然后持久化、审计并
写入 outbox。
### 7.3 标准交互、Lifecycle、Surface 与 Capability
Runtime 通过 `sdk.ui` 提供 `notice``choice``confirm``input` 四种标准交互原语。这是由
Runtime 统一拥有的标准输入输出库:Runtime 创建和持久化交互记录,注入 owner、校验请求/结果、
负责恢复、审计与路由,并依照 Shell Policy 决定呈现位置。
`owner` 不属于 SDK 调用参数。Runtime 仅从 SDK 已绑定的 `MiniAppContext` 注入
`app_scope``instance_id``conversation_id`,并可带有已验证的 `parent_call_id``surface_id`
来源;MiniApp 不可伪造、覆盖或访问其他 owner 的交互。`presentation` 只能作为 `inline``modal`
或默认形式的偏好,最终仍由 Runtime/Shell 决定。
Runtime 内部至少持久化以下归属信息:
```ts
type StandardInteractionOwner = {
app_scope: string;
instance_id: string;
conversation_id: string;
parent_call_id?: string;
surface_id?: string;
source: "agent_tool" | "miniapp_tool" | "runtime_policy";
};
```
Agent 在 IM 中的提问由 Interact 作为默认可信 Renderer Provider 呈现在 IM 时间线/卡片内。前台
MiniApp 自己请求的低复杂度事务提示,可在该 MiniApp 的有效容器或 Surface 中以 Runtime 批准的
标准 modal、sheet 或 card 呈现,不能因此强制切换到 Interact。结果始终先返回 Runtime,再仅投递
给 owner MiniAppMiniApp 不可自行创建 Host 弹窗或直接将结果发送给 Agent。
复杂、高频或私有的业务 UI(例如 Whiteboard 画布文字编辑、画笔、颜色选择、拖放和工具栏)留在
MiniApp 自己的 Surface 内,不使用标准交互库。系统权限确认(文件、麦克风、通知等)则属于
Runtime/Host Capability Gateway,而不是普通 `confirm`
```ts
interface MiniAppLifecycleAPI {
requestForeground(): Promise<CommandReceipt>;
requestBackground(): Promise<CommandReceipt>;
requestClose(reason?: string): Promise<CommandReceipt>;
}
```
MiniApp 只能请求生命周期变化;Runtime 决定是否允许,处理 pending Tool/Surface,并负责
焦点恢复。
Surface 与 Capability 也只能请求:
```text
MiniApp requestOpenSurface / requestCapability
→ Runtime 校验 Manifest、Policy、实例状态和用户确认要求
→ Host Provider 执行受限操作
→ Runtime 记录审计并返回受控结果
```
不应在 SDK v1 提供 `fetch`、任意网络、任意文件系统、剪贴板、麦克风、摄像头或 Tauri
直接调用。高风险能力以后通过 Capability Request 按需开放。
## 8. Tool Contract 与 Inventory
MiniApp 只能在 Manifest 中声明 ToolAgent 只能调用当前 Runtime 已公布 Inventory 中的 Tool。
```ts
type ToolDescriptor = {
id: string; // 例如 task-dashboard.open
version: 1;
handling: "direct" | "interactive" | "launch" | "foreground" | "operation";
target: {
app_scope: string;
requires_foreground: boolean;
restore_previous_focus: boolean;
};
input_schema: JsonSchema;
output_schema: JsonSchema;
permissions?: readonly string[];
timeout_ms?: number;
};
```
统一调度路径:
```text
Agent Tool Invoke
→ Runtime 校验 Envelope、Inventory revision、Tool Descriptor、参数、scope、App 状态和权限
→ 创建可持久化 Tool Call / 审计记录
→ Tool Router 判定 direct / interactive / launch / foreground / operation
→ 投递到目标 MiniApp instance
→ MiniApp SDK 报告 progress / result / error
→ Runtime 校验输出 schema、持久化、更新焦点、写 outbox
→ Agent 收到可靠结果
```
`notice``choice``confirm``input` 是 Runtime 的统一 `interactive` Tool/交互记录能力。
Interact 提供 Agent/IM 场景的默认 Renderer,而不拥有记录或绕过统一 Tool Call、持久化和结果路径;
其他 MiniApp 只能通过 `sdk.ui` 在自身有效容器使用 Runtime 批准的标准 Renderer。
建议稳定拒绝码至少包括:
```text
inventory_revision_mismatch
tool_not_advertised
tool_input_invalid
tool_output_invalid
app_disabled
app_instance_not_found
app_scope_mismatch
lifecycle_denied
capability_denied
call_already_final
```
## 9. Surface、Bundle、Capability 与发布安全
复杂 UI 只能运行在受限 Surface 中。Installed MiniApp 的生产 Bundle 必须满足:
```text
签名 Manifest
→ 精确 byte size 校验
→ SHA-256 校验
→ 原子写入已验证 cache
→ app_id + exact version 解析
→ sandbox="allow-scripts" 的隔离 Surface
```
### 9.1 Host 兼容矩阵
| 情况 | Host 必须行为 | 禁止行为 | 观测信号 |
|---|---|---|---|
| 旧 Client 收到未知 `lineup.v1.*` | 安全 fallback,不执行 | 将 payload 当 HTML/能力执行 | `unsupported_type` / `unsupported_version` |
| 新 Client 收到旧 plain text | 仅作为 Markdown 显示 | 赋予交互或能力 | legacy markdown renderer |
| 不支持目标 Surface version | 不挂载,显示安全提示 | 自动前移到相邻版本 | `surface_unavailable` |
| 收到生产 Surface | 仅在签名、长度、SHA-256 成功后挂载已验证 bytes | 接收 URL、HTML、JS、Bundle/source | install disposition |
| 候选 Bundle 验证失败 | 保留当前 active 已验证版本 | 覆盖 active bytes 或执行候选 | `signature_invalid` 等 |
| active Bundle 被撤销 | 原子回滚到已验证 predecessor;没有则不可用 | 回退到未验证缓存/远端 URL | `rolled_back` / `unavailable` |
| Bridge 收到非当前 iframe 消息 | 丢弃 | 仅相信 origin 字符串或调用 Host API | bridge rejection counter |
| Capability Catalog 变化 | 发布最小新 Inventory | 用过期 Inventory 自动执行 | catalog revision |
### 9.2 生产发布序列
1. 发布方创建不可变 artifact 与生产 Manifest`app_id`、精确版本、artifact ID、长度、
SHA-256、最小 Host 版本、权限、可信 `key_id`、Ed25519 签名。
2. Manifest 与 Bundle 部署在 Host 配置的 HTTPS artifact 服务;Manifest 不携带 URL、HTML、
CSS、JS 或 source。
3. Host 在临时内存中验证签名、精确长度与 SHA-256;失败不写 cache。
4. 验证成功后原子安装,并只解析精确 `app_id + version`;不得自动前移版本。
5. 仅向满足最小 Host 版本且已启用目标版本的 Client 灰度发布。
6. 监控签名、摘要、下载、Bridge 与 Capability 状态;安全事件发生时只回滚到已验证的
predecessor。
7. 回滚后保留审计元数据,但不记录 artifact 内容、URL、token、文件路径或 Capability 参数;
新 artifact 必须使用新版本号。
正式 HTTPS Host 才可被标记为 production-capable。HTTP LAN 开发 Host 在浏览器 WebCrypto
受限时必须安全拒绝验签,不能为了联调放宽该规则。
## 10. 当前实现状态
### 10.1 已完成:历史安全基础
历史 M0~M4 已完成并沉淀在当前代码中;它们不是新的平行排期:
| 历史阶段 | 保留能力 |
|---|---|
| M0 | HTTP Transport、Conversation Store、协议解码、Markdown、安全 fallback、基础回归 |
| M1 | Tool Call、Task、可靠交互结果、执行摘要、可信 choice/confirm/input |
| M2 | Surface Registry、实例生命周期、隔离 iframe 与恢复 |
| M3 | Capability Registry、用户确认、审计与受限 Host 执行 |
| M4 | 签名 Manifest、Bundle 校验/缓存/回滚、golden fixture |
### 10.2 已完成:第二次升级
```text
00.base
→ Runtime 托管 Interact IM(当前兼容名 chat)的稳定基线
01.kernel
→ MiniApp Instance / Focus / Lifecycle、Tool Router、App Orchestrator、
Extension SDK 雏形、Workspace 持久化和恢复
```
当前实现已验证登录、同步、本地回显、Markdown、安全渲染、Tool Call、Task、Surface、
Capability、App Inbox、outbox、实例焦点恢复和生产构建。自动化回归当前为 23 个测试文件、
99 个测试;`npm run build` 通过。
Runtime 的关键结构位于:
```text
tauri/src/runtime/app-management/
tauri/src/runtime/coordination/
tauri/src/runtime/persistence/
tauri/src/runtime/protocol/
tauri/src/runtime/surfaces/
tauri/src/runtime/capabilities/
tauri/src/core-apps/chat/
```
### 10.3 下一阶段:03.sdk_and_coreapp
下一阶段不是应用市场,也不是立即建设服务端下载目录。目标见
[03.sdk_and_coreapp.md](迭代/03.sdk_and_coreapp.md):定义并验证 MiniApp SDK v1
```text
冻结 AppManifest、ToolDescriptor、Tool Call、App Context、Result/Progress/Error 和错误码
→ Runtime 实现通用 SDK 请求路由、schema 校验、审计、恢复和 revisioned Inventory
→ Interact 适配为第一个 System MiniApp SDK 样本
→ Task Dashboard 作为第一个参考 MiniApp 验证 Tool、progress、result、focus 与恢复
→ Whiteboard 验证受限 Surface、状态 patch、Artifact 与 Capability 请求
```
参考 MiniApp 在此阶段可以是 `bundled-development`:随开发 Host 内置、有 Manifest 和 Runtime
注册记录,但不依赖服务端 Catalog、远程下载或第三方发布。
### 10.4 后续阶段
MiniApp SDK 与参考实现稳定后,再按顺序推进:
```text
03.reference-miniapps
→ 完成 Task Dashboard / Whiteboard 的端到端参考实现
04.app-delivery-registry
→ Catalog Entry、Manifest/Bundle 下载、验签、安装、启用、禁用、更新、回滚、移除
05.catalog-and-market(按产品需要)
→ 搜索、分类、发布者、安装 UX、组织分发与可能的商业能力
```
“市场”属于最后的产品分发层,不能反向决定 Runtime、SDK、Tool 或安全模型。
## 11. 验收与发布门槛
每次 Runtime、MiniApp SDK 或 Host 改动至少满足:
```text
npm test -- --run
npm run build
```
对于 SDK/参考 MiniApp,还必须有以下证据:
1. 合法与非法 Manifest、Inventory revision、Tool 输入/输出 schema 的自动化测试;
2. Tool 启动 MiniApp、前后台切换、结果回传、失败回焦和重启恢复的场景测试;
3. Interact 的 `notice / choice / confirm / input` IM 呈现不退化,且覆盖 owner 自动注入、跨 owner
访问/提交拒绝、owner 结果回路与 MiniApp 容器内呈现的测试;
4. Installed MiniApp 无法取得 Host DOM、Tauri invoke、token、任意网络或其他 MiniApp 数据;
5. 有头浏览器验证登录、同步、本地回显和代表性 MiniApp 路径;
6. 对生产 Bundle,验证签名 `open → patch → close → rollback`、隔离 Bridge 和 Capability 拒绝路径;
7. `git diff --check` 无格式错误,日志不得包含身份、会话、消息正文、Tool 参数、token 或
artifact 内容。
## 12. 相关文档与源码导航
- [迭代/00.base.md](迭代/00.base.md)Runtime 托管 Interact IM 的稳定基线。
- [迭代/01.kernel.md](迭代/01.kernel.md)Runtime Kernel 与 MiniApp 编排目标和验收。
- [tauri/src/README.md](tauri/src/README.md):当前源码目录和依赖方向。
- [tauri/README.md](tauri/README.md)Tauri/Web Host 的运行、回归与历史实施细节。
- [程序文件清单与功能说明.md](程序文件清单与功能说明.md):实现文件和功能说明。
- [LineUp App 最终设计方案](../设计/02.正式方案/app_final_design.md):跨文档详细契约来源;
若与本文的产品术语或当前迭代顺序冲突,以本文为准并同步更新上游方案。