Skip to content
bitzorcas
中EN

Concept

前端总览

BitzOrcas 前端是一个 Yarn 4 单仓。Web 管理端是 React 19 + Vite;移动端是 Taro 4 + Capacitor。两侧都经唯一的类型化契约抵达 .NET 后端。

Last updated

BitzOrcas 前端位于后端单仓的 frontend/ 目录下,与 .NET 的 src/ 树平级。它通过 git subtree add 从独立的 bitzeditor 仓库迁入,因此自带独立的 package.json、yarn.lock 与内嵌的 Yarn 4 release。两侧不共享源码——唯一的连接是一份类型化契约与一条明确的认证流程。

1. 前端的位置

关注点后端(.NET)前端(TypeScript)
仓库位置src/、tests/、src/Hostsfrontend/apps、frontend/packages
包管理器NuGet + Central Package ManagementYarn 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 + WebRefreshCookieServiceaccess token 存内存;refresh token 存 HttpOnly cookie

前端不得放进 src/ 内部。它是一个拥有独立工具链的平级子树——这样后端构建永远不依赖 Node,前端构建永远不依赖 .NET SDK。

2. 两个栈,一个单仓

这里有两个 app,且不是同一套技术栈。Web 管理端与移动端壳共享一个 Yarn workspace,但除此之外几乎不共享:

not used by

frontend/ (Yarn 4 workspaces: apps/* + packages/*)

apps/app @bitz/app

apps/app-mobile @bitz/app-mobile

React 19 · Vite 8 · RR7 · Jotai · TanStack Query 5

platform-sdk · widgets · components · editor · i18n

Taro 4 · React 18 · Capacitor 8 · Jotai

App技术栈React打包器后端桥
apps/app(Web 管理端)Vite SPA、RR7、Jotai、TanStack Query 5、Tailwind v419Vite 8 + rolldown、Babel 8(仅 dev 的 Locator)@bitz/platform-sdk + @bitz/widgets
apps/app-mobile(移动端壳)Taro 4 多端(H5 / 微信 / Harmony)、Capacitor 8 原生(Android / iOS)18Taro 的 Vite 4 runner、Babel 7无——独立 Jotai store,没有 platform-sdk

版本拆分是有意的:Taro 4 当前适配 React 18,其构建工具链固定 Vite 4 / Babel 7,这就是移动端 workspace 用 resolutions 锁这些版本的原因。完整画面见 移动端套壳。

3. Web 应用的请求路径

.NET Api Hostfetch · credentials: includeAuthSessionrequest pipeline (单例)PlatformProvider (usePlatform)页面组件.NET Api Hostfetch · credentials: includeAuthSessionrequest pipeline (单例)PlatformProvider (usePlatform)页面组件alt[401 且尚未刷新过]api.searchUsers(query)request('/api/users', opts)注入 base URL · Authorization · X-Client-PlatformAbortSignal.timeout(30s)QUERY /api/users(不支持时 POST /_query)200 或 RFC 9457 ProblemDetailsresponserefreshOnce()新 access token重试一次PlatformResult<UserPage>{ ok: true, data } | { ok: false, error }

整个应用共享唯一一个 request pipeline 实例(在 PlatformProvider 里 useMemo 创建)与唯一一个 AuthSession。页面从不自建 client,而是调 usePlatform().api.<method>(...)。字段级细节见平台契约层;分页、列表和复杂只读请求的传输规则见 QUERY 请求协议。

4. 技术栈(Web 应用)

层选型说明
语言TypeScript 6+严格模式;各 workspace tsc --noEmit
包管理器Yarn 4.17.0nodeLinker: node-modules;.yarn/releases/yarn-4.17.0.cjs 内嵌;registry registry.npmmirror.com
UI 框架React 19+@bitz/app
打包器Vite 8 + rolldowndev proxy 让浏览器同源,避免 CORS
路由React Router 7react-router-dom;import.meta.glob 懒加载;路由级 RouteGuard
客户端状态Jotaiatoms;URL 状态用 nuqs
服务端状态TanStack React Query 5Web 应用唯一被允许的数据获取通道
样式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/i18nContext + 类型安全 t();当前仅 zh-CN,多语言延后
PWAvite-plugin-pwaregisterType: prompt;manifest FD WORK
质量ESLint + typescript-eslint、Prettier、Husky、lint-staged、commitlintConventional 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 调用:

  1. 后端通过 scripts/build/export-openapi.sh 产出 OpenAPI artifact artifacts/openapi/openapi-v1.json。
  2. @bitz/platform-sdk 消费 artifact;generate-client 通过 openapi-typescript 更新 src/client/generated.d.ts,模块契约文件只做类型桥接。
  3. 所有运行时调用都走单例 request pipeline——它注入 base URL、Authorization: Bearer、X-Client-Platform 头,发 credentials: 'include' 让 HttpOnly refresh cookie 自动随行,并把 RFC 9457 ProblemDetails 解析为类型化的 AppError。
  4. 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当前。后端授权管道才是权限的唯一事实。
3refresh 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. 快速开始

Terminal window
# 从后端单仓根目录
cd frontend
# 严格按 lockfile 安装
yarn install --immutable
# Web 管理端 dev server(Vite,端口 6800,dev proxy → Api Host 6881)
yarn dev
# 移动端 H5 壳(独立栈;见移动端套壳页)
yarn dev:mobile

dev proxy 让浏览器在 6800 看到同源的 /api/*,因此开发期没有 CORS。当设置了 VITE_API_BASE_URL 时,前端直连后端,此时后端必须放行该 origin。

9. 学习路线

目标阅读顺序
理解架构本页 → 架构与红线 → 平台契约层
理解列表请求QUERY 请求协议 → 平台契约层
理解登录与账号安全本页 → Identity 前端 → 平台契约层
做一个管理端页面平台契约层 → Web 管理端
出一个移动端包移动端套壳 → 工具链与提交流程
提交一次改动工具链与提交流程

10. 源核对

从后端单仓根目录:

Terminal window
# 确认前端子树、固定的 Yarn runtime、与双 app 布局。
rg -n "packageManager" frontend/package.json
rg -n '"react"' frontend/apps/app/package.json frontend/apps/app-mobile/package.json
ls frontend/apps frontend/packages

前端契约、package 布局或红线一旦在源里变更,本页必须同步 review,而不是任由文档过期。

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%