UG Admin 开发指南

启动和接入真实服务见 使用指南,文档与 Skill 分流见 导航。本指南定义框架维护合同。

双适配器开发模式

React 与 Vue 按同一产品合同分阶段同步交付。复杂交互可以先在一个适配器中验证,但必须在同一阶段完成另一端的原生实现、合同测试与浏览器验收,不能长期保留冻结适配器。

同步目标是信息架构、行为、可访问性和视觉合同一致,不要求组件源码或框架 API 写法一致。

目录职责

apps/react/                   React Router + @ug666/ui-react 原生应用
apps/vue/                     Vue Router + @ug666/ui-vue 原生应用
packages/admin-core/        框架无关的页面、认证、数据访问、主题和共享样式
tests/e2e/                    跨 React/Vue 的 Playwright 浏览器验收
configs/                      跨工作区工具配置
scripts/checks/               架构、仓库卫生与构建产物检查
scripts/dev/                  本地联调工具
scripts/scaffold/             资源脚手架及其测试
scripts/testing/              工程测试辅助
docs/                         稳定架构、开发合同与公开使用 Skills
.agents/skills/               仓库维护工作流
temp/                         本地临时文件、浏览器报告和诊断产物,不提交

packages/admin-core 不得导入 React、Vue、路由库或框架专属 UG UI 包。单端探索中的临时判断不得提前放进共享包;只有双端确认的产品语义才能提升为共享合同。

共享源码的职责目录见 目录地图。新增文件直接归入对应目录,导入使用 @ug666/admin-core/<职责>/<文件>;移动时同步相对导入、脚手架模板、工具入口和文档,不在根目录添加兼容转发文件。跨工作区工具规则放 configs/,需要自动发现的根配置仅保留入口及根扫描范围。

系统功能和消费业务共用 AdminModule:id、pages: [{ page, load, icon? }]、可选 permissions/enabled。各端 src/app/routing/modules.ts 自动发现 src/modules/*/index.ts,统一登记页面和权限;核心没有内置页面枚举。系统元数据在 management/pages.ts,原生实现与 loader 在各端 modules/system/;新增系统页面只维护模块自身,不改创建器。模块可含多个页面,业务只写所选框架。共享路由校验冲突并提供导航、面包屑与页签算法。

面包屑的 breadcrumb.label 必须是当前页面名称;页面兼作导航分组时,可通过 ancestorLabel 单独定义后代页面的祖先名称。例如部门页当前显示“部门管理”,用户、角色页的祖先显示“组织与权限”;系统设置兼作“系统管理”分组,字典归入该组。窄屏只保留当前项时仍能识别所处页面。历史地址通过共享 aliases 登记,双端统一替换跳转,页签先迁移再校验页面身份和权限;历史地址不生成额外菜单或授权。

共享样式从 styles/app.css 统一导入,按 shell、dashboard、workspace、showcase、patterns、management、core、auth、responsive 分责维护。入口顺序属于级联合同;响应式覆盖最后加载,不在应用端重新拼接或复制这些模块。

默认新系统只开启核心后台。模板仓库的学习示例通过 VITE_ADMIN_EXAMPLES=true 开启。业务模块的 permissions 在路由生成前统一交给 configureAdminPermissions;登记不等于授权,也不替代 Access Provider 与后端校验。项目品牌和启动装配放 src/project.ts,项目后端实现放 src/backend/,由启动入口按顺序注入。

本地 UG UI 联调

默认依赖使用锁文件中的已发布版本。已有可用依赖时不必重复安装;只有需要相邻 ug-ui 未发布的公开 API 且允许修改本地依赖链接时,执行:

mise run install
mise run link:ui

link:ui 会按 core、web、React、Vue 的依赖顺序构建公开包,并在各应用的 node_modules/@ug666 下创建工作区链接;它不会注册全局 Bun 链接、升级其他依赖或修改应用的依赖声明。ug-ui 不在相邻目录时,通过任务专用环境变量指定绝对路径:

# PowerShell
$env:UG_UI_ROOT = "E:\\path\\to\\ug-ui"
mise run link:ui

# Bash
UG_UI_ROOT=/absolute/path/to/ug-ui mise run link:ui

链接完成后会删除两个应用的 Vite 依赖预构建缓存,避免切换 Registry 包与本地包后继续加载旧导出表。两个仓库的 main 必须保持公共合同兼容。

用户要求保留依赖与链接时不执行上述安装或重链操作;沿用当前环境验证。不手改依赖包来代替公共源码修复。

临时文件与生成物

  • 根目录 temp/ 是临时文件唯一入口。一次性脚本、截图、Trace、Playwright 报告、诊断日志、接口样本、导出文件和处理中间产物按用途放入 temp/<task>/,不得与 apps、packages、tests、scripts 或 docs 的长期文件混放。
  • temp/ 下除 .gitkeep 外全部由 Git 忽略。需要长期维护的脚本、Fixture、配置或文档不再属于临时文件,必须迁入正式目录并纳入检查。
  • Playwright 固定输出到 temp/playwright/report 和 temp/playwright/test-results,便于本地检查失败截图、Trace 和报告。
  • node_modules、应用的 dist、.vite 与 coverage 遵循工具标准目录并保持忽略。根目录 dist、playwright-report、test-results、.artifacts、tmp 和 scratch 均属于不允许的散落产物。
  • Playwright 场景放在 tests/e2e/ 并按产品职责拆分;通用登录和状态重置放在 tests/e2e/support.ts。测试源码受版本控制,运行报告仍进入 temp/playwright/。
  • mise run check:architecture 会检查上述目录以及散落的 .tmp、.temp、.bak、.old、.orig、.rej、.log、.trace 和 .har 文件。
  • 工程测试使用 scripts/testing/workspace.ts 在 temp/tooling/ 创建隔离夹具,成功或失败后均回收自身目录,不使用系统临时目录遗留文件。

未使用代码检查(Knip)

移动或删除文件、调整导出和依赖后,在 ug-admin 根目录运行:

mise run check:unused

也可执行 bun run check:unused;完整的 mise run check 已包含这一步。Knip 会报告疑似未使用的文件、导出和依赖,便于在重构时定位清理候选,不会自动删除代码。看到报告后先核对实际调用方、动态加载、路由登记、测试入口与外部消费,再决定是否修改;不能仅凭一条报告删除文件或依赖。

configs/knip.json 定义扫描范围:根工作区覆盖共享合同、脚本和 E2E,React/Vue 工作区分别覆盖各自源码与测试;entry 声明独立入口,project 声明待检查源码。新增独立运行的脚本或测试入口、移动工作区目录时,要同步核对这些路径。data/platform.ts、data/resources.ts 是预留给外部接入的扩展合同,因此有定向例外;新增例外前须确认确有外部消费,并尽量限定到具体文件与问题类型。

本地 file: 依赖与运行时副本

跨仓联调把 @ug666/ui-* 指向本地源码时,包管理器会为 file: 依赖单独安装一份运行时:ui-vue 会带进自己的 vue,导致同一页面出现两个 Vue 运行时,渲染时报 Cannot read properties of null (reading 'ce') 并整页崩成错误页。

约束:根 overrides 固定 vue 与 @vue/* 到同一版本,apps/vue/vite.config.ts 的 resolve.dedupe 同时列出 vue、@vue/runtime-core、@vue/runtime-dom、@vue/reactivity、@vue/shared。调整 ug-ui 依赖方式后要复查 node_modules/.bun/@vue+runtime-core@* 是否只剩一个版本。

删除业务模块

mise run remove:module <模块名>            # 只体检:列出目录与模块外引用
mise run remove:module <模块名> --apply    # 无外部引用时真正删除
mise run remove:module <模块名> --vue      # 只处理指定端
mise run remove:module <模块名> --apply --force   # 带引用强制删除(需手工清理引用)

命令会先扫描 apps、packages、scripts、tests、docs 中模块目录之外的引用;存在引用时默认拦截并逐条列出文件与行号,避免删掉目录却留下悬空导入。删除后按提示跑 check:modules 与 check:parity 复核残留。

模块清理与包导出

删除功能或移动目录后运行:

mise run check:modules   # 模块内页面是否都被入口引用
mise run check:exports   # 各包 exports 是否指向真实文件

check:modules 收集 apps/*/src/modules 内的本地引用(相对与 @/ 别名),未被任何模块文件引用的 *Page 视为孤立页面;确需保留时在 configs/module-exempt.json 登记 path、reason、reviewAt。

check:exports 校验 packages/* 的 exports 目标与 version 是否完整,防止桶文件或目录移动后对外契约静默断链。

多语言

公共文案集中在 packages/admin-core/src/i18n/locales.ts(zh-CN / en-US 键集合必须一致),运行时用 configureAdminLocale 切换、t(key, { params }) 取词:

import { configureAdminLocale, t } from "@ug666/admin-core/i18n";

configureAdminLocale("en-US");
label.textContent = t("common.save");
  • 页面与组件不得硬编码公共动作、状态与无障碍标签,先加键再引用;
  • 缺失键返回键名并记入 getMissingAdminMessageKeys(),便于测试期发现漏翻;
  • 新增语言时同时在 adminLocales 注册,并在用例里补齐键集合校验。

响应式断点

三档语义由 packages/admin-core/src/config/viewport.ts 定义:手机 < 48rem(768px)、平板 48–90rem、桌面 ≥ 90rem(1440px)。CSS 无法在 media query 里使用变量,因此样式侧只允许两个停止点:max-width: 47.999rem(手机)与 max-width: 89.999rem(平板及以下),需要 min-width 时用 48rem / 90rem。

mise run check:responsive

出现其它数值(例如 767px、74.999rem)即失败。prefers-color-scheme 等非宽度查询不受限制。

双端对称检查

React 与 Vue 是同一产品合同下的两个原生应用,页面只在两端各实现一次、但必须同时存在。新增或删除页面后运行:

mise run check:parity

检查按模块内 *Page 页面文件比较两端,辅助函数与组合式实现的拆分方式允许不同。确需单端先行时,在 configs/parity-exempt.json 登记 path、reason 与 reviewAt(复审版本号),缺少原因或复审版本的条目会直接报错,避免长期静默分叉;补齐后立即删除对应豁免。

开发者文档站

bun run dev:docs 启动独立的 apps/docs,固定使用 127.0.0.1:3400(端口序列的第一位),端口占用时退出,不挤占后台服务。文档站基于 Astro + @astrojs/react(React 只用于交互孤岛),正文来自 docs/*.md;文章收录与分组在 apps/docs/src/lib/documents.ts,不在页面中复制使用教程。构建时用 marked 转换正文并丢弃原始 HTML,链接协议单独校验,章节锚点保留中文。站内文章链接转换为页面地址,源码和未收录文档显示仓库路径,不生成失效网页链接;不读取相邻仓库内容。

bun run build:docs 执行文档站类型检查并输出 apps/docs/dist,可单独部署为静态站。它不使用后台会话和 API,不进入后台菜单或单端创建器,生产后台的构建检查仍只检查 React/Vue 的业务产物。Knip 的 docs 工作区覆盖阅读页和 Markdown 构建入口。正文修改检查引用与实际命令;渲染或导航变化检查文档站构建;不因此触发业务全量测试或自动浏览器验收。

页面开发合同

  • 全局侧栏、顶栏、次级导航、移动导航和内容容器由 UGAdminShell 负责;页面标签通过独立的 secondaryBar 区域接入,并由壳层与主顶栏编排为连续的吸顶层级。
  • 页面标签栏通过 appTabsVisible 开关和 appTabsDensity 间距密度进入后台偏好;它们不属于外观弹窗,项目需要开放设置入口时应在业务设置页同步接入 React/Vue,不能通过隐藏 DOM 或覆盖内部定位实现显隐。
  • 侧栏折叠按钮、紧凑 Logo、顶栏高度和边界线由 UGAdminShell 公开合同统一维护;导航默认颜色由当前主题与明暗基准共同解析,偏好只在用户手动改色后保存覆盖;当前项样式和菜单密度通过外观弹窗写入偏好,再由应用传给壳层。
  • 模板侧栏默认配置集中在 packages/admin-core/config/admin-layout.ts:品牌对齐和分隔线、搜索区域显隐/文案/分隔线、折叠能力及入口位置、拖拽宽度均使用独立配置。collapsible 控制是否允许折叠,togglePlacement 在 sidebar / topbar / bottom 中选择入口位置;切换位置或关闭能力不删除 UG UI 的公开实现。应用默认不注入页脚内容,项目需要时通过 sidebarFooter / #sidebarFooter 插槽放置自身业务内容。侧栏导航由 UG UI 在视口内独立滚动,应用不穿透内部 Anatomy 修补。
  • 包含子级的一级侧栏项整行只负责展开或收起,不能直接导航;分组首页应作为首个“概览”二级菜单呈现,只有叶子菜单负责跳转。显式收起当前分组后也不得被路由状态立即强制展开。
  • 页面标题、说明和操作区由 UGPageHeader 负责,并保持唯一 h1。
  • 系统页面的路径、菜单、面包屑、访问声明与页签语义登记在 packages/admin-core/management/pages.ts,其他业务由各自模块的 pages 登记,由 routing/admin-pages.ts 统一导出。后端菜单必须通过 adaptBackendMenuItems 适配,不能把组件路径写入响应。
  • 新页面先登记共享页面合同,再分别补充 React/Vue 图标和懒加载组件适配;禁止手写第二份菜单或面包屑数组。
  • permission 只表达访问要求;菜单过滤用于体验收敛,不等同于路由鉴权或服务端授权。旧 access 字段仅用于兼容迁移。
  • 页面不得直接读写认证存储;登录、恢复和退出统一通过 AdminAuthProvider,权限判断统一使用共享页面合同。
  • 生产认证接入使用 createHttpAuthProvider 或实现同一 8 方法合同,并通过各应用的 configureAdminAuthProvider 注入。Mock 只能位于 packages/admin-core/testing,不得作为生产默认 Provider。
  • 页面只负责内容组合,不重新实现 Button、Input、Card、Drawer、Dialog、Table 等基础组件。
  • 用户、部门和角色管理是正式模板能力,共享合同在 management/,双端实现各自放 src/modules/system/management/;字典类型、条目和业务选项合同在 dictionaries/,对应双端 src/modules/system/dictionaries/。任务中心仍为扩展示例,其优先级消费正式字典。用户页组织快捷筛选复用 users/options 的精简部门选项,可选 parentId 用于层级,缺失时平铺;不要为该页引入完整部门列表权限。行业流程、多租户、后端项目与组织特有流程按真实需求另行接入,不自动预建。
  • 产品名称、Logo、favicon、登录文案、默认主题与存储命名空间统一在 config/brand.ts 配置。默认使用现有 UG 素材;消费产品经授权可提供自己的品牌资源,禁止把应用名称和存储前缀散落到页面。
  • 页面文案必须面向最终使用者。仓库架构、组件职责、接入状态、实现进度、完成度、后续计划和 TODO 只写在规则或开发文档中,不得渲染为产品卡片、徽标、空状态或说明。
  • 没有真实业务内容时使用中性的标题与空状态,不以开发汇报内容充当演示数据。

数据访问合同

  • 页面通过 React 的 useAdminDataProvider 或 Vue 的同名 composable 获取 AdminDataProvider,不得直接调用 fetch,也不得在页面组件内维护另一份长期 Mock 数据源。
  • 服务端状态通过各框架的 TanStack Query 原生 API 管理。查询键统一由 adminQueryKeys 生成,并把 Query 提供的 AbortSignal 传给 Data Provider。
  • 列表请求使用统一的 page、pageSize、sort、order、filters、search 和 signal 参数;响应始终返回 data、total、page、pageSize 和可选 meta。业务字段类型在业务模块声明,不放进通用合同。
  • 多记录读取、批量删除和端点特有操作分别使用 getMany、deleteMany 与 custom,不得把这类操作伪装成列表查询或在页面中拼接 URL。
  • 创建、更新或删除成功后,由业务 Hook/composable 精确失效对应资源查询;表单组件不直接操作全局查询缓存。
  • 页面按 AdminDataError.code 呈现可恢复错误,表单从 fieldErrors 映射字段提示。401 的退出、缓存清理和登录跳转由数据层与认证层联动处理,业务页面不得重复实现。
  • 通用认证头通过 getHeaders 注入;跨项目请求规范使用 beforeRequest / afterResponse;服务端响应结构差异使用 rest.responseMappers 收敛。它们都在创建 HTTP Data Provider 时配置,禁止泄漏到业务页面。完整示例见 后端接入。
  • 本地默认 demo 认证/Mock 数据,生产默认 HTTP 且拒绝 demo/mock。联调真实服务时在对应 .env.local 同时设置 VITE_AUTH_PROVIDER=http、VITE_DATA_PROVIDER=http 和公开 API 地址;HTTP 会话恢复询问服务端,不复用 demo 会话。任何机密都不得使用 VITE_ 变量。
  • 新增提供者能力时先补共享合同测试,再分别验证 React/Vue 类型检查、测试和生产构建。

平台偏好与扩展接口

  • 主题外观、侧栏样式、页面宽度、标签栏状态和侧栏折叠状态统一通过偏好上下文/composable 修改,页面不得直接维护第二份本地存储键。外观弹窗只呈现“主题外观 / 侧边导航”两个分类,不混入页面宽度、标签栏或组件细节。
  • 标签页由路由合同的 tab 字段控制;持久化、关闭和恢复使用 packages/admin-core/routing/app-tabs.ts,不缓存框架组件实例。已打开标签保持固定顺序,查询参数变化只更新当前标签地址;关闭当前标签优先接续右侧相邻项,活动标签必须自动进入横向可视区。
  • 文件、导入导出、审计、实时消息和国际化通过 packages/admin-core/data/platform.ts 注入具体 Provider。接口只表达前端边界,不在应用中伪造服务端能力。

后台页面模式

  • “组织与权限”提供部门、用户和角色的完整查询与写入流程,React/Vue 使用同一模型、权限目录与路由合同,各端原生组合 UG UI。修改字段、关联和授权行为时先读 基础管理合同,同步共享校验、双端表单和后端 Adapter。
  • 部门树使用 getManagementOptions 读取完整分页;用户关联通过 getManagementUserOptions 读取 users/options 的精简名称与可分配标记,不附加完整角色/部门列表权限。两者转发取消信号,不用固定“前 1000 条”假设。管理写入后同步失效 users/departments/roles 的列表与选项,刷新身份权限,避免显示旧角色或部门名称。
  • 超级管理员的功能全权不等于绕过业务约束;内置角色保护、自删/自停用、最后启用超管、越权分配、部门循环与关联删除保护必须在真实服务端再次执行。前端模型不存密码,开户/邀请/重置由后端接入实现。
  • 列表页使用各端 AdminListPage + AdminSearchForm 与 ug-ui/patterns 的 UGDataTable 组合,不在业务页重复实现加载骨架、失败重试、空状态、全选、排序表头和分页结构。
  • AdminListPage 沿壳层可用空间伸展且不受普通页的最大宽度限制;表格使用 UGDataTable fill,保持有名称的内部滚动区与底部分页。任务、用户、角色的每页条数由 UG UI 分页选择器回传,更新 Provider 查询并重置到第一页;部门树使用完整选项数据,避免分页切断层级。
  • 列表使用 surface-1 平面工作区,AdminListPage 及用户组织工作区均使用普通布局容器,main/content 外圈内边距和路由区间距归零,直接衔接页签下沿。不要再套整页 Card、圆角、阴影或外边框;真正的信息卡片仍使用 UG Card。内部 DataTable 使用公开 bordered={false} / :bordered="false" 保留行分隔而避免双重网格线;业务列宽可在响应式断点收敛,窄屏只滚动有名称的表格区域,不压缩操作文字或让整页横向溢出。
  • 用户列表将用户名称和账号分列显示,单行数据与表头沿用 UG UI 的同一密度;不要把两个独立字段强行合成双行 Identity,再用页面 CSS 补表头高度。多行描述是显式的业务选择,其行高可以高于表头。
  • 管理列表按搜索、生效条件、记录操作、数据与分页的任务关系组合,语义分区不要求各占整行;后续排版遵循 横向排布规则,能清楚同行的内容优先同行。现有列表各区域保持连续工作区;查询、操作与组织栏保留内部留白和有用分割线,表格内容从工作区边界开始,不叠加 CardContent 横向内边距。分页内边距由 UG UI 的 UGDataTable fill 统一提供。列表页的可见标题由壳层当前位置与面包屑承担,页面保留屏幕阅读器可识别的唯一 h1;新建放操作栏左侧,刷新和列设置放右侧。搜索表单采用 UG UI 默认控件尺寸,不在单页硬改输入框与按钮高度。表格容器从列标题开始,不在表格顶部重复结果数或刷新;总数交给 UGDataTable 底部分页摘要。数据行需要辨识度时使用 UG UI 的 striped 属性;排序必须同时接通列 sortable、受控 sort/order 与 Provider 查询,不能仅显示排序图标。
  • AdminListPage 通过 React summary 属性和 Vue #summary 插槽承载独立条件摘要;内容自己判断是否存在生效条件、错误或待查询状态,空内容不生成额外空行。用户页以“当前筛选条件”命名该区域,覆盖关键词、部门、角色、状态、手机和创建时间,并在窄屏保留部门范围入口;已选记录数及“清空选择”属于 CRUD 操作区。关闭标签继续经原查询校验提交其他草稿,成功后焦点转到更新后的摘要;最后条件清空时转到持续存在的搜索显隐按钮,校验失败保留原关闭按钮及错误。标签文本省略、关闭按钮与基础外观由 UG UI 负责,业务只约束可用宽度,不穿透 Tag 内部。
  • 查询字段使用 UG UI 的 FormField / FormItem / FormLabel / FormControl 横向标签合同;无可见标签的紧凑搜索要有 aria-label。AdminSearchForm 默认标签列按内容宽度排列,也可通过公开 labelWidth 为需要等宽控件的字段统一标签列;现有用户页的关键词、手机与状态采用相同宽度,日期起止保持一组;这不是新页面必须照搬的宽度规则,后续按内容预算与实际容器空间选择。标签与控件的垂直居中、Button 图标与文字的对齐由 UG UI 负责,不在业务页补内边距或移动图标。同行 Input、Select、Button 继承同一个 Form size;字段之间的距离应大于字段内标签与控件的距离,空间不足时整组换行。手机展开及整体搜索显隐均保留草稿,展开按钮提供真实 aria-expanded/aria-controls,生效的隐藏条件仍显示可清除摘要。
  • 双列表单的跨列字段必须让网格直接子节点跨列;UG UI Input / Textarea 的 className 或 class 作用于原生控件,不是表单网格项。用 .admin-field-span 包一层,错误文本另用 .admin-form-error,避免把错误色带到输入控件。文本域原生拖拽手柄与字数提示的间距由 UG UI 统一维护。
  • 整体查询显隐通过 AdminListPage 的 searchId/searchHidden 关联按钮 aria-controls/aria-expanded;隐藏区域持续挂载以保留草稿及手机展开状态,并使用原生 hidden 退出布局和键盘访问。
  • 表单页使用 AdminFormPage 统一返回、保存、保存并返回、提交状态和未保存离开确认;服务端 422 错误通过 AdminDataError.fieldErrors 映射到字段,不以 Toast 代替字段提示。
  • 详情页使用 AdminDetailPage 组织信息分组,危险操作通过 AdminConfirmAction 二次确认;提交按钮必须有同步防重复锁,不能只依赖异步 loading 渲染。
  • 路由级访问元数据决定能否进入页面,按钮与记录级操作使用 PermissionGate;普通业务组件不得自行解析权限字符串。
  • 本地开发场景可使用 demoScenario 查询参数验证空、超长、大数据量、慢请求、401、403 和 500。夹具必须放在 packages/admin-core/testing,生产构建不得包含夹具文案或持久化键。
  • 响应式覆盖维度包括 390、768、960、1280、1920 和 2560 CSS 像素,按本次布局影响选取,局部微调不重复完整矩阵。960/1280 可近似检查 1920 屏幕在较高浏览器缩放下的布局,但不等于真实缩放验收。页面本身不得产生横向滚动;宽表格必须在有可访问名称的表格滚动区内滚动,并检查表头/单行数据高度及折叠侧栏与页签的相邻空间。

样式合同

  • 使用 UG UI 的语义 Token 控制颜色、边框、间距、圆角、阴影和动效。
  • 宿主原生控件重置使用 :where(...) 保持低优先级的继承基线,不能用后加载的元素级 font: inherit 覆盖 UG UI 的公开字号与行高规则;字体不一致时核对实际级联,不在单页追加字体覆盖。
  • 业务 CSS 只处理页面 Grid、区域比例和内容编排,不穿透 [data-ug-slot] 修改组件内部结构。
  • 不使用裸色值、任意像素堆叠、卡片套卡片或重复边框掩盖组件问题。
  • 单端探索阶段的适配器专属调整留在对应应用;确认可跨框架复用后,才提升到共享样式并同步另一端。

UG UI 缺口处理

定位归属与完成接入

先检查消费项目实际解析的包版本、公开 Props/Slots/Token、外层布局和 CSS 级联。按问题来源决定修改位置:

问题 修改位置
Props 使用错误、业务容器布局、应用 CSS 干扰、路由或查询状态 UG Admin 或对应业务模块
正确使用后仍存在的组件尺寸、字体、hover/focus/disabled、主题、键盘、浮层或响应式缺陷 UG UI 对应组件、Web 样式或共享合同
已有公开能力能满足需求 Admin 通过公开属性、插槽或页面组合使用,不为此增加组件 API
真实场景证明公共能力缺失 在 UG UI 扩展现有能力;仅有不可替代的复用需求时新增组件
业务字段、权限判定、数据范围、请求格式或事务 Admin 模块、项目 backend 适配或后端服务;不进入 UG UI

例如圆形头像触发器:若 Button 已有圆形公开属性,调用方选用该属性;若该属性下 hover 仍方形,则修组件状态样式。className/class 可安排公开根节点与业务容器布局,不能用内部选择器、!important、DOM 查询、复制组件或通用包装器隐藏组件缺陷。包装器可以组织业务内容,但不另造公共控件的尺寸、状态和焦点行为。

跨仓处理在已有用户授权范围内执行,不因涉及第二个仓库自动重复索要确认;先检查两仓 Git 状态和实际依赖,保留并行改动。UI 修复在 UI 源码完成,再通过匹配版本的包或获准的本地联调交付给 Admin,核对实际解析版本和直接消费者。vendor 是分发快照,不是维护源码:修复后从源包重新生成受影响快照并更新依赖/锁文件,禁止直接编辑 vendor、node_modules 或 dist。尚未交付到消费版本时,明确仍未接入,不用应用补丁代替,也不把本地链接当成已发布。

公共语义变化核对 React/Vue 对应实现,必要时在组件侧补最小回归;Admin 复用已有直接消费场景,不按页面数量复制同类测试。使用方式变化才同步 exports、Registry、Demo、公开 Skill 等受影响事实源;内部修复不强制修改全部文档。用户自行验收界面时保留未验收状态,按允许范围完成静态或定向检查。提交、发布、推送与部署仍分别遵守用户授权。

成熟后台代码的 UG 适配

RuoYi 等后台可作为管理流程和代码生成能力的参考来源。复用源码时记录固定上游版本、文件与本地改编,保留相应许可,当前用户管理来源见 docs/legal/THIRD_PARTY_NOTICES.md;页面、生成模板及公共交互使用 @ug666/ui-react / @ug666/ui-vue 的公开 API。Element Plus 的树选择、表单、表格等能力由 ug-ui 原生组件提供,颜色、密度、焦点和弹层继续服从 UG 合同。

先核对现有公开能力和实际消费场景,再补缺口;不因为参考库提供某个组件就重复预建。数据库、认证、权限、接口 DTO 和 URL 状态由对应后端或 Admin Adapter 管理,公共 UI 只接收数据与回调。

发现基础组件无法满足场景时,先确认是否存在公开 Props、Slots、Patterns 或组合方式。确属公共缺口时记录:

  1. 真实后台场景。
  2. 当前公开 API 为什么无法完成。
  3. 建议的框架无关能力。

不要在 UG Admin 偷偷造一份临时公共组件,也不要未经授权发布 UG UI。

完成检查

  • 先遵循用户指定的验证范围。若本轮禁止启动服务或浏览器验收,工程迁移检查命令、静态引用、类型与必要构建,并用 bun run e2e --list 核对测试发现;不运行 e2e/check:all,也不把用例清单当作浏览器通过。
  • 先列出实际影响和要验证的用户行为,再选择检查;不能仅因为本次叫“阶段交付”就默认全测。视觉判断见 设计依据。
  • 测试按风险新增,不按修改次数新增:文案、样式、组件现有属性切换和未定型的展示页面,默认不新建测试文件、不增加截图矩阵。优先复用已有用例;新增权限边界、数据变换、写入或已复现缺陷时,才补覆盖该风险的最小测试。明确由用户验收视觉时,不主动启动浏览器、批量截图或重复验收;简单改动只做必要的差异与静态检查,不串行堆叠 lint、类型检查、构建和 E2E。临时排查优先使用直接命令,只有确需复用时才保存脚本。
改动 默认验证范围
文档、维护规则、Skill 差异、相对链接、frontmatter、命令存在性;不构建、不跑业务测试
架构检查器或规则模板 现有检查器故障夹具、实际仓库边界检查和单端创建结果;同时验证合法依赖与错误依赖,不新增业务测试矩阵
文案、间距、颜色、局部布局 相关文件格式检查、实际受影响页面与关键状态;按影响补代表视口/主题,不自动全仓检查
单页表单、查询或操作行为 相关类型检查、已有单测及对应 E2E 文件/用例;共享变化检查双端直接消费者
共享 Token、组件或页面模式 验证受影响组件及直接消费页面,覆盖相关亮暗/窄屏/键盘状态;先定向,不因改到共享文件就自动全测
跨模块结构性变更、依赖/构建/测试发现变化,或无法界定影响的全局调整 收敛改动后运行一次 mise run check:all;用户明确要求完整回归时也使用此入口

已有 check:react/check:vue 包含该端完整检查,不作为纯 CSS 微调的强制前置。局部 E2E 使用现有 Playwright 配置和文件/--grep 筛选,报告真实范围,不把定向结果称为全量通过。发布准备保留完整门禁。

从仓库根通过 bun run e2e --list 列出用例,或用 bun run e2e tests/e2e/auth.spec.ts --project react 定向执行。直接使用 Playwright CLI 时必须传 --config tests/playwright.config.ts。工程测试随工具共置,test:tooling 使用显式目录 bun test ./scripts,避免 Bun 将裸 scripts 当作过滤词而扫描 temp/ 中的历史源码副本;目录移动不改变命令名称、资源生成路径或现有测试断言。

已通过的检查只在相关源码再次变化、新失败或未覆盖影响出现时重跑。失败修复先复验失败场景及相邻行为;文档回写、报告签署和截图整理不触发新一轮构建/全测。普通样式修改不追加包体/source-map 全量审计,不删除测试、放宽断言或刷新基线来节省时间。

  • check 顺序执行 Biome、依赖边界与循环依赖、Knip、架构故障夹具与脚手架测试、双端单测/类型/构建及生产构建检查;mise run check 直接调用同一 package.json 脚本,不并发启动两端 Vitest。架构检查覆盖应用、共享包、测试、脚本、configs 和根工程 TS/CSS 文件,检查静态本地导入失效、跨框架泄漏与产品源码反向依赖工具;动态拼接路径仍需人工核对。
  • e2e 同时运行 React/Vue,检查 390、768、1280、1440、1920、2560 像素、亮色/暗色/system、键盘焦点、axe 严重问题,以及登录、CRUD、权限和错误边界。配置分为学习示例 react/vue(3401/3402)与默认核心 core-react/core-vue(3420/3421);core-platform.spec.ts 专门验证停用路由、旧页签、真实偏好与本人资料。测试显式选择模块开关,不继承实际后端模式或复用未知服务。
  • 未经明确要求,不提交、不推送、不发布、不部署。

单端项目与业务脚手架

bun run create:project --framework vue --dir ../my-admin --name my-admin
bun run scaffold:resource --framework vue --name audit-logs --label 审计日志 --dry-run

创建器按所选端 src、system 模块和共享源码目录边界复制;不分析源码依赖或重写应用代码,不维护核心 loader 映射。Vite 与初始化使用 scripts/scaffold/templates 的固定模板。输出为根 src/shared/public 的单端项目,不带 apps 工作区、另一端、学习页面、测试、私有环境文件或缓存。保留 vendor 中兼容 UI 分发包及许可证;独立安装生成锁文件。

资源名必须为小写 kebab-case。单端输出自动识别框架,双端模板要求 --framework。默认生成模块入口、api.ts 和查询列表三个文件;--crud 追加新增/编辑与详情,共五个文件,使用现有 Provider/Query/DataTable/Form/Detail 模式。模板在 scripts/scaffold/templates//resource-*.template,生成的是可维护源码,不引入运行时 Schema 或低代码引擎。若任一目标存在则拒绝写入。开发者在模块内补充业务字段和操作,后端接口和授权仍须真实实现。维护时验证生成模块不写核心、写入前权限与错误转换,并独立检查两端生成源码;复用现有脚手架用例,不按页面数增加测试文件。接口规范和部署事实源分别为 BACKEND_ADAPTER.md 与 DEPLOYMENT.md。

效果预览与文档站解耦

/demo/ 是真实组件样板间,与文档正文分开:正文页面不加载 React,预览页只挂一个孤岛。

  • 预览孤岛自带错误边界,出错只影响本页并显示说明,不会带崩文档站其余页面。
  • UG_DOCS_PREVIEW=false bun run build:docs 可整体关闭预览孤岛,用于文档独立发布或预览依赖出问题时先恢复文档。
  • 预览不算文档能力,故障时优先关闭预览而不是回退文档发布。