Skip to content

feat: 引入 App Builder 应用装配与生命周期运行时 - #259

Draft
tanbro wants to merge 6 commits into
HuangPuStar:mainfrom
tanbro:feat/app-builder-foundation
Draft

tanbro wants to merge 6 commits into
HuangPuStar:mainfrom
tanbro:feat/app-builder-foundation

Conversation

@tanbro

@tanbro tanbro commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

背景

src/index.ts 同时承担环境配置、Elysia 路由装配、业务资源启动、listen、signal 和 shutdown。模块顺序依赖入口中的代码位置,应用也无法在不启动真实外部资源的情况下完整构造。

本 PR 引入代码级 App Builder,把“应用如何组合”与“进程如何启动”分离,同时保持社区默认应用与改造前完整等价。

设计与评审文档

建议按以下顺序评审:

  1. 详细设计:App Builder 设计
    • 文档位置:docs/design/2026-09-04-app-builder-design.md
    • 说明问题、范围、领域与模块边界、接口、生命周期时序、兼容要求、验证方式及后续演进边界。
  2. ADR 提案:使用代码级 Profile 组装服务端应用(状态:提议中)
    • 文档位置:docs/adr/0001-application-profile-composition.md
    • 记录拟长期采用的架构决策、理由、替代方案与后果;待详细设计评审通过、实现一致且 Linux CI 通过后再接受。
  3. 当前态架构:应用装配与进程生命周期
    • 文档位置:docs/arch/24-application-bootstrap.md
    • 描述本 PR 实现后的真实目录、依赖方向、启动/停止数据流和扩展约束。

三类文档职责有意分离:Design 回答“准备怎样设计”,ADR 回答“为何长期采用”,Arch 回答“代码现在如何运行”。

前置稳定性修复与合并顺序

本 PR 依赖前置修复 #260#260 不包含 App Builder 实现,而是修复 main 中既有的跨测试全局状态泄漏与异步清理逃逸。

#259 增加测试文件后改变了 fresh checkout 中未排序文件列表的枚举结果,从而暴露这些既有缺陷;失败不由 App Builder 的 Runtime、Profile 或 route 装配行为引起。为避免扩大本 PR 的架构评审范围,相关修复已独立到 #260

本地已验证以下最终组合:

feat/app-builder-foundation
  + fix/test-state-isolation(#260)
  + legacy-community 对正式 stopHermesClient() 的专属接入

该组合在默认 Bun 1.4.2 和 CI Bun 1.3.14 下执行 precheck 均为 8236 pass / 0 failbuild:webdocs:build、App Builder 定向测试和 @fenix/server-runtime 测试均通过。

建议维护者按以下顺序处理:

  1. 先合并 fix: 隔离跨测试全局状态并等待异步清理 #260main
  2. 再让 feat/app-builder-foundation 同步最新 main
  3. 在本 PR 中补充 legacy-community disposer 对正式 stopHermesClient() 的实现与当前态文档接入;
  4. 重新执行 feat: 引入 App Builder 应用装配与生命周期运行时 #259 的完整 checks。

最终组合目前只存在于本地临时集成分支,尚未推送到 #259,避免在 #260 合并前产生重叠提交。

主要变更

  • 新增业务无关的 @fenix/server-runtime workspace package:
    • ApplicationBuilder
    • ApplicationRuntime
    • ApplicationProfile
    • ServerModule
    • fail-fast startup、逆序 disposer、并发/重复 stop 幂等
  • 将社区应用装配收敛到 src/application/
    • createCommunityBaseApp() 负责固定横切能力
    • community-default Profile 负责默认组合
    • legacy-community 过渡 Module 承接全部既有业务 routes、启动顺序和资源释放
    • src/index.ts 只保留环境、listen、signal 与退出策略
  • 保留 Elysia/Eden 精确 route 类型:fluent .use(module) 惰性累积 ~Routes,大型默认 route tree 从同一有序 tuple 推导静态类型和运行时顺序。
  • 新增两层源码示例:
    • Runtime package 示例展示两个显式 Profile 的 route 省略与生命周期差异
    • Fenix 宿主示例展示 Module → Profile → Application factory,并提供浏览器可见页面
  • 补充详细设计、ADR 提案、当前态架构文档和后端开发指南。

设计边界

  • Profile 是受信的静态 TypeScript 配置,不支持运行时插件发现、热切换或环境变量 Module 列表。
  • 不提供 capability registry、通用 DI 容器、Service Locator、同名 Module 覆盖或 route override。
  • 启动遇到首个错误立即停止;只释放此前成功 Module 返回的易失资源 disposer,不回滚 migration 等持久化事实。
  • 正常停止顺序为 app.stop() → abort signal → reverse Module disposers
  • legacy-community 仅是无行为变化接入 Runtime 的过渡边界,不代表已经确认的领域模块或企业扩展 API。
  • 本 PR 不拆分 Channels、Agent Sites 等生产能力;真实业务模块化按领域职责和第二消费者需求独立推进。

如何试用

最小自定义 Profile(无需生产数据库或 API key):

bun run example:app-builder

命令只监听 127.0.0.1 的系统分配端口,并输出 /example 页面地址。页面展示当前 Profile、Module、复用的 Community base app、已省略的 legacy-community,以及可访问的 health/ping routes;Ctrl+C 经 Runtime stop 关闭 listener。

完整默认应用仍使用:

bun run dev
#
bun run start

完整调用链为:

src/index.ts
  → createDefaultApplication()
  → community-default
  → legacy-community

验证

在干净 tracked-source 快照中,使用与 upstream CI 相同的 Bun 1.3.14 验证:

  • 冷缓存 bun install --frozen-lockfile:2452 packages;package.jsonbun.lock 安装前后哈希不变
  • bun run precheck:8232 pass / 0 fail(format、import-sort、server/web tsc、lint、tests 全绿)
  • CI 等价拆分测试:
    • backend:3722 pass / 0 fail
    • packages:2489 pass / 2 skip / 0 fail
    • frontend:2261 pass / 0 fail
  • bun run --cwd packages/server-runtime typecheck
  • bun run --cwd packages/server-runtime test:15 pass / 0 fail
  • bun run --cwd packages/server-runtime example
  • App Builder 定向测试:9 pass / 0 fail,82 assertions
  • bun run docs:build
  • 零生产配置 smoke:/example 200,/example/ping 200,无 Better Auth / DATABASE_URL / RCS_API_KEYS 告警
  • Chrome headless 实际渲染检查:页面结构、中文文本、Profile/Module/省略项和链接正常

兼容性

  • 不修改 /api/*/web/*、ACP、MCP 或 WebSocket 对外协议。
  • 不修改数据库 schema 或 migration。
  • 社区默认 routes、OpenAPI、鉴权、route precedence 和生产启动顺序保持。
  • 自定义示例不进入生产稳定导出面,也不是第二个正式进程入口。

🤖 Generated with Claude Code

liu_xue_yan and others added 6 commits September 4, 2026 13:36
明确服务端模块装配、生命周期资源释放及未来定制版演进边界。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
提供与业务无关的类型安全应用装配和统一资源生命周期,为不同 Profile 组合保留稳定边界。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
将社区路由和启动链收敛到单一过渡模块,使进程入口只负责配置、监听与退出策略,并保持现有行为边界。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
固定跨平台文本规范,并清除阻塞全仓静态检查的既有 Biome 警告。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant