BitzOrcas 前端位于后端单仓的 frontend/ 目录下,与 .NET 的 src/ 树平级。它通过 git subtree add 从独立的 bitzeditor 仓库迁入,因此自带独立的 package.json、yarn.lock 与内嵌的 Yarn 4 release。两侧不共享源码——唯一的连接是一份类型化契约与一条明确的认证流程。
1. 前端的位置
| 关注点 | 后端(.NET) | 前端(TypeScript) |
|---|---|---|
| 仓库位置 | src/、tests/、src/Hosts | frontend/apps、frontend/packages |
| 包管理器 | NuGet + Central Package Management | Yarn 4.17.0(packageManager 字段;.yarn/releases/yarn-4.17.0.cjs 内嵌) |
| 运行时 | .NET 10(Api、JobHost、AppHost) | Node;浏览器 / 原生壳 |
| 契约面 | 产出 artifacts/openapi/openapi-v1.json | @bitz/platform-sdk 消费 |
| 认证事实 | JWT + WebRefreshCookieService | access token 存内存;refresh token 存 HttpOnly cookie |
前端不得放进 src/ 内部。它是一个拥有独立工具链的平级子树——这样后端构建永远不依赖 Node,前端构建永远不依赖 .NET SDK。
2. 两个栈,一个单仓
这里有两个 app,且不是同一套技术栈。Web 管理端与移动端壳共享一个 Yarn workspace,但除此之外几乎不共享:
| App | 技术栈 | React | 打包器 | 后端桥 |
|---|---|---|---|---|
apps/app(Web 管理端) | Vite SPA、RR7、Jotai、TanStack Query 5、Tailwind v4 | 19 | Vite 8 + rolldown、Babel 8(仅 dev 的 Locator) | @bitz/platform-sdk + @bitz/widgets |
apps/app-mobile(移动端壳) | Taro 4 多端(H5 / 微信 / Harmony)、Capacitor 8 原生(Android / iOS) | 18 | Taro 的 Vite 4 runner、Babel 7 | 无——独立 Jotai store,没有 platform-sdk |
版本拆分是有意的:Taro 4 当前适配 React 18,其构建工具链固定 Vite 4 / Babel 7,这就是移动端 workspace 用 resolutions 锁这些版本的原因。完整画面见 移动端套壳。
3. Web 应用的请求路径
整个应用共享唯一一个 request pipeline 实例(在 PlatformProvider 里 useMemo 创建)与唯一一个 AuthSession。页面从不自建 client,而是调 usePlatform().api.<method>(...)。字段级细节见平台契约层;分页、列表和复杂只读请求的传输规则见 QUERY 请求协议。
4. 技术栈(Web 应用)
| 层 | 选型 | 说明 |
|---|---|---|
| 语言 | TypeScript 6+ | 严格模式;各 workspace tsc --noEmit |
| 包管理器 | Yarn 4.17.0 | nodeLinker: node-modules;.yarn/releases/yarn-4.17.0.cjs 内嵌;registry registry.npmmirror.com |
| UI 框架 | React 19+ | @bitz/app |
| 打包器 | Vite 8 + rolldown | dev proxy 让浏览器同源,避免 CORS |
| 路由 | React Router 7 | react-router-dom;import.meta.glob 懒加载;路由级 RouteGuard |
| 客户端状态 | Jotai | atoms;URL 状态用 nuqs |
| 服务端状态 | TanStack React Query 5 | Web 应用唯一被允许的数据获取通道 |
| 样式 | Tailwind CSS v4 | @tailwindcss/vite |
| UI 原语 | shadcn 模式(Radix / Base UI) | @bitz/components——shadcn 原语 barrel(数十个 UI 组件再导出) |
| 富文本 | Tiptap 3 | @bitz/editor——基于 StarterKit 的 useBitzEditor 封装 |
| 图标 | unplugin-icons + @iconify-json/lucide | 自动导入 |
| 构建辅助 | unplugin-auto-import、unplugin-svgr | |
| i18n | @bitz/i18n | Context + 类型安全 t();当前仅 zh-CN,多语言延后 |
| PWA | vite-plugin-pwa | registerType: prompt;manifest FD WORK |
| 质量 | ESLint + typescript-eslint、Prettier、Husky、lint-staged、commitlint | Conventional Commits;允许中文 subject |
5. 单仓布局
frontend/├── apps/│ ├── app/ @bitz/app — Web 管理端 SPA(React 19 + Vite 8)│ └── app-mobile/ @bitz/app-mobile — Taro 4 + Capacitor 8(独立栈)└── packages/ ├── platform-sdk/ @bitz/platform-sdk — 深模块:request pipeline、auth session、gates、契约类型 ├── widgets/ @bitz/widgets — 复合业务 widget(AppShell、ServerDataTable、FormField …) ├── components/ @bitz/components — shadcn 原语 barrel(按钮/表单/表格/浮层等)+ `cn` 工具 ├── editor/ @bitz/editor — Tiptap `useBitzEditor` 封装 ├── i18n/ @bitz/i18n — Context + 类型安全 t()(zh-CN bundle) ├── materials/ @bitz/materials — Design System 1.2 Token source、生成器与运行时 ├── hooks/ @bitz/hooks — `useDebounce`(脚手架阶段) ├── utils/ @bitz/utils — `slugify`、`cx`、`formatDate` └── scripts/ @bitz/scripts — 脚手架 banner 辅助apps/* 与 packages/* 是两个 Yarn workspace glob。页面只从 package barrel(@bitz/widgets、@bitz/platform-sdk)导入,绝不深入 package 内部路径。materials 已承担 Token source 与生成门禁;hooks、scripts、editor 仍是相对薄的 package。
6. 与后端的契约
Web 应用通过唯一一条通道与后端交互,而不是散落的 HTTP 调用:
- 后端通过
scripts/build/export-openapi.sh产出 OpenAPI artifactartifacts/openapi/openapi-v1.json。 @bitz/platform-sdk消费 artifact;generate-client通过 openapi-typescript 更新src/client/generated.d.ts,模块契约文件只做类型桥接。- 所有运行时调用都走单例 request pipeline——它注入 base URL、
Authorization: Bearer、X-Client-Platform头,发credentials: 'include'让 HttpOnly refresh cookie 自动随行,并把 RFC 9457 ProblemDetails 解析为类型化的AppError。 - artifact 与线上 API 的 drift 由
scripts/build/check-openapi-drift.sh守护。
认证遵循固定契约:login 在 JSON body 中返回 access token,在 HttpOnly cookie 中返回 refresh token(浏览器自动携带)。refresh 读 cookie;logout 在服务端撤销 refresh token 并清除 cookie。
7. 红线
这些是已经落地的架构不变量。
| # | 红线 | 状态 |
|---|---|---|
| 1 | 生成的 client 不手改 | 当前。修改后端契约,重新导出并生成。 |
| 2 | 前端权限判断只算 UX | 当前。后端授权管道才是权限的唯一事实。 |
| 3 | refresh token 不进 localStorage | 当前。Web 的 refresh 只走 HttpOnly cookie;access token 是模块私有字段。 |
| 4 | 权限事实不进 localStorage | 当前。TenantId / UserId / 权限来自 /api/auth/me 或 JWT claim。 |
| 5 | 禁手写后端 DTO | 当前。模块契约只能桥接 generated.d.ts 的 schema。 |
| 6 | 页面禁散落 fetch | 当前。所有 HTTP 走 usePlatform().api。 |
| 7 | 单一 request pipeline 实例 | 当前。PlatformProvider 为整个 app memo 一个 client。 |
8. 快速开始
# 从后端单仓根目录cd frontend
# 严格按 lockfile 安装yarn install --immutable
# Web 管理端 dev server(Vite,端口 6800,dev proxy → Api Host 6881)yarn dev
# 移动端 H5 壳(独立栈;见移动端套壳页)yarn dev:mobiledev proxy 让浏览器在 6800 看到同源的 /api/*,因此开发期没有 CORS。当设置了 VITE_API_BASE_URL 时,前端直连后端,此时后端必须放行该 origin。
9. 学习路线
| 目标 | 阅读顺序 |
|---|---|
| 理解架构 | 本页 → 架构与红线 → 平台契约层 |
| 理解列表请求 | QUERY 请求协议 → 平台契约层 |
| 理解登录与账号安全 | 本页 → Identity 前端 → 平台契约层 |
| 做一个管理端页面 | 平台契约层 → Web 管理端 |
| 出一个移动端包 | 移动端套壳 → 工具链与提交流程 |
| 提交一次改动 | 工具链与提交流程 |
- 01/09
单仓、深模块与红线
前端把 apps 与 packages 组织成依赖方向固定的深模块,并用红线把后端契约收敛为单一来源、把凭据挡在脚本够不到的地方。
- 02/09
平台契约层
@bitz/platform-sdk 是 Web 应用与 .NET 后端之间唯一被允许的桥梁——它独占 request pipeline、auth session、ProblemDetails 映射、权限/特性 gate 与 OpenAPI 生成契约。
- 03/09
HTTP QUERY 与 POST 自动降级
说明 BitzOrcas 如何使用 RFC 10008 QUERY 承载分页、列表和复杂只读请求,以及 Platform SDK、OpenAPI 3.1、CORS、网关和未来 .NET 11 / OpenAPI 3.2 的兼容边界。
- 04/09
Web 管理端
@bitz/app 是 React 19 + Vite 8 的管理端 SPA。它组合 widgets、platform-sdk context、Jotai 与 React Query,经 Vite dev proxy 同源抵达后端。
- 05/09
管理端工作区与导航
BitzOrcas 管理端按七个服务端治理的工作区组织功能;菜单随权限和租户/Host 范围变化,并提供吸顶页面上下文、面包屑切换和个人固定视图。
- 06/09
移动端套壳 — Taro + Capacitor + Harmony
'@bitz/app-mobile 是独立的 Taro 4 + React 18 栈,分别编译到 H5、微信小程序与 HarmonyOS Next hybrid,再用 Capacitor 8 套成 Android 与 iOS 原生。它不用 platform-sdk 或 widgets。'
- 07/09
Identity 前端
BitzOrcas Web Identity 完整使用与开发参考:登录(RSA 密码密文)、验证码、MFA、密码、邀请准入、用户授权、组织、应用凭据与租户治理。
- 08/09
工具链与提交流程
如何用 Yarn 4 安装、lint、typecheck、构建 BitzOrcas 前端单仓,以及 Husky 与 commitlint 强制的提交规范。
- 09/09
页面开发
面向 C# 后端开发者的 Recipe 驱动前端页面开发流程、概念映射、红线与完成检查。
10. 源核对
从后端单仓根目录:
# 确认前端子树、固定的 Yarn runtime、与双 app 布局。rg -n "packageManager" frontend/package.jsonrg -n '"react"' frontend/apps/app/package.json frontend/apps/app-mobile/package.jsonls frontend/apps frontend/packages前端契约、package 布局或红线一旦在源里变更,本页必须同步 review,而不是任由文档过期。