Skip to content

开发手册导读 ​

本手册面向 二次开发者与平台维护者:讲清楚启凌智搭的代码怎么组织、低代码链路怎么跑通、权限体系怎么决策、自研 Agent 模块怎么扩展,以及「新增一个功能要动哪些文件」。

组织方式参照按域切分:不追求覆盖上游开源框架的每一行,而是把 本项目定制的部分讲透,上游部分只讲约定与扩展点。

三个入口,按你的问题选

你的问题是走这里
我要做某件事,翻哪页?任务索引 —— 按「要动的那件事」查,直接跳到目标页的那一节
我该按什么顺序读?下面的按角色的阅读路线
这个症状是哪来的?坑位索引 —— 按「现象 → 根因 → 怎么办」查(编号 A1–F6),全部带实测证据;移动端专属的另有一页移动端坑位(编号 M1–M24)

侧栏是按「你要动哪一端」分组的,不是按目录编号,原因见章节地图下面那条警告。

读者与前置知识 ​

你是谁需要先知道建议入口
后端开发Java 17、Spring Boot 3、Maven 多模块、MyBatis-Plus、Dynamic Datasource环境准备与启动 → 后端架构与模块依赖
Web 前端开发Vue 3、Vite、TypeScript、Element Plus、Form Create(开源版)前端工程结构 → 路由与权限机制
移动端开发Vue 3、uni-app、TypeScript、wot-design-uni、UnoCSS、只能用 pnpm移动端总览 → 移动端环境准备与启动
低代码平台开发以上任一 + 平台的模型 / 表单 / 菜单三件套概念低代码平台开发总览
Agent 能力开发Spring AI、Spring AI Alibaba架构总览

先读平台使用手册再看代码

开发手册默认你已经会用这套系统。不了解「数据模型 / 表单设计 / 资源授权」在界面上长什么样,直接读代码会非常吃力——请先过一遍使用手册的 02 基础设施与 01 系统管理对应章节。

移动端是个例外:使用手册目前没有移动端篇(截图流水线只跑 Web 端 :80)。要看移动端在界面上长什么样,只能起 H5 :9000 自己点,或者看移动端仓库 README.md 里的演示图。

三个仓库与技术栈 ​

仓库内容关键版本本地端口
ainb后端,Maven 多模块单体Java 17、Spring Boot 3.5、MyBatis-Plus、Redisson48080(/admin-api)
ainb-ui-admin-vue3后台前端(Web)Vue 3、Vite、TypeScript、Element Plus、pnpm(Node ≥ 20.19)80
ainb-ui-admin-uniapp移动端(H5 / 小程序 / App 同一套代码)Vue 3.4、uni-app 3.0、Vite 5.2、TypeScript 5.8、wot-design-uni 2.2、UnoCSS 66、z-paging 2.8、pnpm(Node ≥ 20)H5 9000

三者共用同一套后端、同一套权限体系与租户。移动端不是「另一个后台」,而是同一平台的第二个运行时宿主:工作台 / 审批 / 消息 / 我的 + 在线表单的移动端运行时,工作台菜单由服务端 system_nav_node 下发、不在前端写死。它不走 Vite proxy,直连后端 :48080(Web 端同样直连,vite.config.ts 的 server.proxy 整段是注释掉的)。

上游归属各不相同,别混为一谈:

仓库直接上游
ainb芋道 ruoyi-vue-pro
ainb-ui-admin-vue3芋道 yudao-ui-admin-vue3
ainb-ui-admin-uniapp芋道 yudao-ui-admin-uniapp(业务页底座),而它本身又派生自 unibest(工程骨架)

三者都是改名分支:包名 cn.iocoder.yudao → cn.enlev.ainb,构件前缀 yudao- → enlev-,产品名「启凌智搭」。仓库里残留的 yudao 字样与上游文档只作参考,不要改回上游命名。

与上游最大的结构差异:模块是扁平 jar

上游把每个业务模块拆成 -api / -biz 两个构件,本项目没有拆——api 只是同一构件里的一个 package。所有代码生成器模板、模块依赖、启动类扫描都按扁平结构写好。把上游的拆分方式「改回来」会直接破坏代码生成与编译。

模块依赖关系 ​

依赖是单向的:agent → {ai, infra, bpm, system},没有任何模块反向依赖 agent。这意味着给 agent 加工具时可以直接调用其他模块的 service;反过来,其他模块要用 agent 能力,只能通过接口或事件解耦。这条纪律由 AgentArchitectureTest#testOnlyDependOnApiLayer 钉住,反向依赖当场编译不过。

enlev-module-im 已被整体删除

ls -d enlev-module-* 只剩 agent ai bpm infra system 5 个;根 pom.xml 里连注释掉的那行也没了。-pl enlev-module-im 必然失败——不是因为被注释,是因为不存在(删除于 12347efcd1,305 个文件)。移动端仓里那 11 个 pages-{crm,erp,im,iot,mall,...} 分包编译进包但用户点不到,正是因为后端这些模块已删。实测清单与 reactor 的 24 个模块怎么数见后端架构与模块依赖。

章节地图 ​

侧栏的 8 个分组就是本手册的全部结构:

分组这一组回答什么问题页数从哪进
开始怎么跑起来、代码归属怎么判断、要干某件事翻哪页4任务索引
后端模块怎么分、一条请求怎么走、表怎么建;含子分组「上游域」7后端架构与模块依赖
Web 管理端前端工程怎么组织、路由与权限怎么串、请求怎么发、有哪些现成组件与 hook4前端工程结构
移动端 ★同一套后端的第二个运行时宿主:约定式路由、双 token、服务端下发的工作台、在线表单的移动端渲染器、三端产物9移动端总览
低代码平台模型 / 接口 / 表单 / 控件 / 取号 / 门户这五个域怎么在运行时被解释执行8低代码平台开发总览
权限体系三层权限怎么在一次请求里叠加、配了为什么不生效6权限体系总览
Agent 模块 ★全仓唯一完全自研的模块:工具、ReAct、工作流、HITL、安全、计量、SSE8架构总览
工程实践端到端做一件事、怎么写测试、怎么打包部署、有哪些已知坑4新增一个菜单功能端到端

页数含本页与任务索引这两个导航页,合计 50。要复核就数侧栏,别数目录(05-mobile/ 恰好一组一目录,其余都不是)。

侧栏分组 ≠ 目录编号,这是刻意的

分组按读者要动哪一端组织,目录编号是历史 ID。所以 00-intro/ 的 9 页被拆进了「开始 / 后端 / Web 管理端」三组,04-upstream/ 挂在「后端」组下作子分组——文件都没动,只有归组变了。

不要「顺手对齐」编号与分组:那要么得改 36 个已进 AI 知识库的 URL(tools/gen-kb-url-map.mjs 会与站点路由逐条对账、不符即 exit 1),要么得把「按端找页」退回成「按编号猜页」。

同理,本页不维护逐页清单——那份权威在 docs/.vitepress/sidebar.mjs,而且它有门禁(pnpm check:pages 会校验侧栏每条文字与页面 H1 逐字一致、每个链接都有对应文件)。以前这里有一份逐页表,那是第二份拷贝、没有任何门禁,已经在漂移。下面各节只讲「这一组为什么值得读、有什么反直觉的地方」,不重复列页面。

开始 · 后端 · Web 管理端 ​

这三组的正文页都在 00-intro/ 目录下,是按端拆开的:跑起来与代码归属放「开始」,后端三页放「后端」,前端四页放「Web 管理端」。

它们是入门材料,但不是软材料:00-intro/ 里的每一页都带着实测出来的反直觉结论,比如「岗位代码在 dept 包不在 post 包」「v-hasPermi 传字符串会直接 throw」「auto-*.d.ts 只由 dev server 生成」。第一次读建议按阅读路线走,之后当参考查。

移动端 ★ ​

这一组是本轮新加的,也是三仓里最容易被误判的一个:它看着像「Web 端的缩小版」,实际是同一套后端的第二个运行时宿主——共用 /admin-api、共用权限判定与租户,但工程约定几乎处处与 Web 端不同(只能 pnpm、约定式路由、easycom 自动注册、不走 Vite proxy、没有单测)。拿 Web 端的习惯去套,第一小时就会撞墙。

三件反直觉的事,先记住再读:

  • 工作台菜单不在前端写死。上游那套 267 项手写 menu.json 被换成了库里的 system_nav_node(terminal=app)自引用树,由 /system/nav-node/tree 下发。这条链路横跨三仓(后端建表 + Web 仓的「移动端导航」编辑器与「App菜单」页 + 移动端渲染),动任何一端都要先看服务端驱动导航。
  • 约一半产物是用户点不到的。11 个 pages-{crm,erp,im,iot,mall,...} 分包编译进包,但后端对应模块早已删除、导航树不建节点,实测占 H5 产物体积的 52%。这是历史遗留而非 bug,别去「修好」它,详见移动端总览。
  • mode 与 command 不是一回事。非 H5 端连 pnpm dev:app 的 command 都是 build(只有 mode 是 development)。所以「现在是不是生产」只能问 mode / NODE_ENV,问 command 会得到相反的答案——本仓已经因此长出过一个把凭据内联进生产包的缺陷。

这一组有两条「致命」级坑,都在构建与发布链路上

M9:env/.env 是所有 mode 的公共基底,而 Vite 会把 VITE_* 静态内联进产物——写在这里的默认账号口令会原样出现在生产包里,且运行时没有任何开关能关掉(已修,但机制还在)。 M18:VITE_WX_APPID / VITE_UNI_APPID / VITE_BAIDU_MAP_KEY 三个身份标识仍是上游的值,照着文档上传小程序会传到上游账号下(未修,需要你先定值)。

这一组没有测试网

移动端仓库没有单测,只有 pnpm type-check(vue-tsc)、pnpm lint、pnpm check:color(品牌色硬编码守卫)。所以本组页面的结论全部来自实测源码、脚本量测与产物字面量,而不是「跑一遍测试就知道了」。改完之后要验证,只能起 H5 :9000 手点。

低代码平台 ​

五个域(数据建模、表单设计、数据接口、门户、取号管理)上游 yudao 一个都没有。上游只有代码生成器——生成 Java/Vue 源码,产物脱离平台运行;本项目的低代码是运行时解释:配置存在库里,由平台自己解释执行。

这个区别决定了读法:代码生成器你只要看模板,运行时解释你得看解释器。所以这一组的每页都在讲「配置怎么被读出来、怎么被校验、怎么被执行」,而不是「产物长什么样」。

权限体系 ​

sys_ 前缀的 7 张表、决策引擎、行级规则、字段模式、记录共享、权限诊断——整套都是本项目自研。上游 yudao 只有 system_role_menu(角色 ↔ 菜单的多对多)加一个 @DataScope 注解;它的判定就一句 roleMenuMapper.selectListByUserIdAndMenuIds 判非空——没有 DENY、没有动作维度、没有继承、没有理由。

这一组的坑密度是全手册最高的

权限体系的缺陷形态不是报错,而是「配了、保存成功了、发布成功了、界面上一切正常,但就是没生效」。所以每一页都有一节很长的「坑与注意」,而诊断与排错把全域已知的静默失效汇成了一张「症状 → 根因 → 去哪查 → 报错吗」的表。只读一页的话读它。

另外:「塌缩」这一件事在三页里各写了一面——权限资源(开发视角)是写库侧、授权与决策引擎是判定侧、诊断与排错是检测侧,必须连着看。

Agent 模块 ★ ​

enlev-module-agent 是本仓唯一一个从第一行起就完全自研的业务模块。上游 yudao 只有「对话 + 绘图」,没有「让模型去建表、发布表单、部署流程、发起审批」这条链路——所以这一组讲的东西在上游找不到任何参照物,别拿对 yudao 的记忆去推。

它也是全仓测试网最密的地方,实测(2026-10-25;口径同 ai 域开发 · 测试:数 src/test 下全部 .java,注解按行首锚定):

模块测试文件@Test@Disabled
enlev-module-agent1612,2250
enlev-module-ai4318786(46%)

对照很说明问题:管着所有厂商模型调用的 ai 模块,近一半测试是关掉的;而自研的 agent 一个都没关。改 ai 域时别指望测试网兜住你。

⚠️ 这两个「测试文件」数与测试规范那张表的「测试类」数(agent 160、ai 13)不是同一个口径,两张表都对、别互相「订正」:那边只数 *Test.java,这边数 src/test 下全部 .java——ai 那 43 个里有 29 个是整体禁用的 *Tests.java(联网测试)加 1 个 fixture VendorApiKeys.java。86 个 @Disabled 的逐条归类见 ai 域开发 · 测试。

这一组有全平台唯一一处匿名可达的入口

POST /admin-api/agent/webhook/{path} 是整个 agent 模块唯一的 @PermitAll 端点(注解全模块只有一处,在 AgentWebhookController)——不要 token、不要登录态,只靠「IP × path 两维限流 + 验签 + body 整体闸」挡着,而每一次命中都是一次无头拉起流程:烧 token、写库、占图执行线程。动它之前先读安全与提示注入防护。

两页对「发布」的定义不一样

工作流引擎讲的是引擎侧的生效,Plan 预览确认与 HITL讲的是闸门侧的放行。改工作流时两页必须连着看,否则会以为发出去了其实没发、或以为被拦了其实是生效了。

上游域(挂在「后端」组下) ​

四页讲的都是上游 yudao 的模块,但四个的定制方式完全不同,读法也不同。先看这张实测的归属占比(@author 走进新时代 的文件数 / 该模块 src/main/java 下的 .java 总数):

域本项目怎么定制它自研占比
system在旁边加了一整套自研权限体系(7 张 sys_* 表 + service/permission/ 一整包)101 / 575 ≈ 17.6%
infra低代码引擎整套挂在它身上:formdesign / datamodel / datainterface / billtemplate / portal199 / 469 ≈ 42.4%
bpm直接改上游的类:改 SimpleModelUtils、改 BpmModelServiceImpl、在事件基类里加一道守卫39 / 265 ≈ 14.7%
ai只改了 14 个文件,但这 14 个管着所有厂商模型调用14 / 199 ≈ 7.0%

⚠️ 这四个数会随提交漂移(system 与 infra 已经各漂过一次)。要复核就现场量,别信本页:

bash
cd ainb && for m in system infra bpm ai; do
  b=enlev-module-$m/src/main/java
  echo "$m $(grep -rl '@author 走进新时代' $b --include=*.java | wc -l) / $(find $b -name '*.java' | wc -l)"
done

所以每页开头都有一张实测规模表:先看那张表,分清哪些是你不能乱动的底座、哪些是本项目自己的东西。判断单段代码归属最省事的办法是看 @author——「芋道源码」是上游,「走进新时代」是本项目。

01-lowcode 讲「它怎么工作」,04-upstream 讲「它挂在哪个模块的哪个包里」——要找低代码的某一层,先在 infra 域定位子域,再回低代码平台组看机制。

工程实践 ​

这一组不按概念组织,按你要干的那件事组织。四页里坑位索引是被引用最多的一页:48 个正文页里有 45 个带「坑与注意」节,而这 45 个节的末尾都有一行指回它(剩下 3 页是仓库结构与改名约定与两份坑位索引自己——索引页本身就是清单,不再指回自己)。

坑位索引现在分两处,别只查一处:跨端通用的 29 条(编号 A1–F6)在坑位索引,移动端专属的 24 条(编号 M1–M24)在移动端坑位。前者的 G 节把后者标 🔴 的那几条指了过来,所以「上线前过一遍」这件事仍然能在一个页面里做完——条目正文只有一份,不重复。

上线前只看一页的话

看坑位索引,把它索引表里标 🔴 的条目过一遍,再顺着 G 节过移动端那几条——尤其是 A1(免登录 mock token 曾长期在生产 profile 里开着,Bearer test1 就是超级管理员;已修,但代码路径一行没删,开关一开就复活)、A2(Druid 控制台曾无鉴权暴露 JDBC URL 与全部已执行 SQL;已修,但改的是 yaml,不重启不生效)与 M18(小程序身份标识仍是上游的,未修)。

条数这里刻意不写:它是索引表的一个筛选结果,写死一个数字就是又造一处会漂移的拷贝——本页上一版写的是 11,而表里当时已经有 12 条。

按角色的阅读路线 ​

每条路线都是有序的,读完就能动手;不在这个角色上的章节先跳过。

1. 第一次跑起来(谁都先走这条) ​

  1. 环境准备与启动 —— 装什么、SQL 怎么导、后端与 Web 端怎么起、怎么验证起来了。这一页不含移动端:三端共用同一个后端与同一个库,所以第 1 步照走,之后起 H5 :9000 的部分转移动端环境准备与启动
  2. 仓库结构与改名约定 —— 三个仓库、yudao→enlev 改名规律、怎么判断一段代码是谁写的
  3. 任务索引 —— 之后按你要做的事查,不必通读

第 1 步的 SQL 有个真陷阱

sql/mysql/ 下两份全量 dump 都不能单独用:ainb-professional-init.sql(211 张表)平台表齐全但没有 system_nav_node;ainb-init.sql(95 张表)有 system_nav_node 却缺 64 张代码里 @TableName 声明的表。正确路径是「导专业版快照 → 按依赖顺序跑 update/ 那 6 个增量脚本 → 重启后端」。顺序、原因、以及为什么不能图省事用 update/*.sql 通配,都写在环境准备与启动里。

2. 只改后端 ​

  1. 后端架构与模块依赖 —— 模块依赖图、starter、请求生命周期、/admin-api 前缀怎么来
  2. 接口约定与 CRUD 骨架 —— 以「岗位」为样本走完 Controller→VO→Service→Mapper→DO
  3. 数据库约定与表总览 —— BaseDO、逻辑删除、多租户、建表最小清单
  4. 新增一个菜单功能端到端 —— 两条路线都实测走查过(手写五件套 / 代码生成器)
  5. 要动上游模块时,再进「后端 → 上游域」那四页

3. 只改 Web 管理端 ​

  1. 前端工程结构 —— 目录职责、环境变量与 mode、alias 顺序陷阱、自动导入覆盖范围
  2. 路由与权限机制 —— 登录到建路由的完整链路、三层权限、v-hasPermi 的实现取舍
  3. axios 封装与 API 约定 —— 拦截器七分支、401 无感刷新、api 层标准写法
  4. 通用组件与 hooks —— 全局组件名怎么来、定制组件、hook 全清单、哪些是死代码

4. 只改移动端 ​

  1. 移动端总览 —— 这个仓库是什么、17 个页面目录里哪些真交付了、与 Web 端的能力差
  2. 移动端环境准备与启动 —— 只能 pnpm、init-baseFiles、env 叠加顺序、H5 :9000 怎么确认真跑通了
  3. 工程结构与约定式路由 —— pages.json 是产物不是源码、分包划分、easycom 的 ^yd-(.*) 规则
  4. 请求封装与登录态 —— 拦截器七步、双 token、401 静默刷新与重放队列、加解密开关的真实语义
  5. 移动端页面开发范式 —— 一个列表页的完整最小样例,z-paging / wot-ui / UnoCSS 的既定写法
  6. 再按你要动的那件事挑一页:工作台菜单 →服务端驱动导航;在线表单 →在线表单在移动端;出包上线 →多端构建与发布
  7. 移动端坑位 —— 按症状查(编号 M1–M24),动手前先扫标 🔴 的那几条

第一小时最容易撞的两堵墙

别跳过 pnpm install 直接 pnpm dev:pages.json / manifest.json 由 init-baseFiles 与插件生成,仓库里没有,缺了就是「找不到模块」而不是「请先安装」。别手改 src/pages.json:它是产物,改完会被下一次生成覆盖,要改路由去改 pages.config.ts 与各页的 definePage,而且改完必须重启 dev server。

5. 只排查问题 ​

  1. 坑位索引 —— 按症状查;上线前只过标 🔴 的条目 + G 节指过来的移动端那几条
  2. 权限类:诊断与排错 —— 末尾那张「症状 → 根因 → 去哪查 → 报错吗」总表
  3. Agent 类:ReAct 循环与流式对话(先确定走的哪条路由)→ 计量与配额(那次调用有没有记账)
  4. 移动端类:移动端坑位 —— 按症状查(编号 M1–M24)。「列表页一直转圈」先看 M3,「点了没反应、只提示页面不存在」先看 M5
  5. 确认了机制再回到对应组的正文页

排查时最贵的一个错误

用超管账号自测。super_admin 走短路,压根不查授权——「我这儿一切正常」在权限问题上没有任何信息量。见坑位索引 D3。

页面骨架:每页怎么读 ​

48 个正文页共用一套骨架,节名固定、顺序固定,所以你知道该跳到哪一节:

节覆盖率它回答什么时候直接跳过来
它解决什么问题46 / 48这东西为什么存在、边界在哪第一次接触一个域
代码在哪44 / 48文件与包的路径清单已经知道要改什么,只想定位
核心机制44 / 48它怎么工作(含 Mermaid 图)要改行为、或要判断改动的影响面
数据模型33 / 48表结构、字段语义要写 SQL、要加字段
接口清单30 / 48端点 + 权限串要调接口、要给角色授权
怎么扩展43 / 48「加一个 X」的步骤🎯 最常直接跳来的一节,任务索引里的链接大多指向它
坑与注意45 / 48贴着上下文的提醒改之前扫一眼,改完对一遍
测试32 / 48这块有哪些测试、怎么跑要加测试、或要判断某个结论可不可信
未证实35 / 48作者没能证实的推断🔴 别把这节的内容当结论引用
相关页面48 / 48出边读完一页往下走

覆盖率是实测的,分母是 48 个正文页——本页与任务索引是导航页,不套这套骨架;两份坑位索引(06-practice/pitfalls、05-mobile/pitfalls)是清单页,也刻意不套(它们本身就是「按症状查」,不需要「它解决什么问题」)。复核命令:

bash
cd xpy-blog && for s in 它解决什么问题 代码在哪 核心机制 数据模型 接口清单 怎么扩展 坑与注意 测试 未证实 相关页面; do
  printf '%s %s\n' "$s" "$(find docs/develop -name '*.md' ! -name index.md ! -name tasks.md \
    -exec grep -l "^## $s" {} \; | wc -l)"
done

「未证实」节是刻意存在的

本手册的纪律是结论必须实测,但实测有时做不到(要长跑、要真机、要生产流量)。这类内容不删、也不伪装成结论,而是集中放进「未证实」节并写明为什么没证实。看到它就当作「一个有依据的猜测」。

页头那行「适用端 / 类型」 ​

48 个正文页的 H1 后面都有一行元信息,例:

markdown
> **适用端**:后端 + Web | **类型**:机制

它回答的是**「我该不该看这页」**——在一个 48 页的手册里,读者最先要判断的不是内容对不对,而是「这页讲的是不是我要动的那一端」。

🔴 这行由 tools/check-pages.cjs 守着(pnpm check:pages):缺行、位置不在 H1 后第一行、或类型/适用端取了词表外的值,都会 exit 1。新增页必须带上它——48 页是脚本一次性注入的,没有门禁的话下一页就会漏,而漏了不报错,正是本仓其它守卫要消灭的那类静默漂移。词表若要扩,改 check-pages.cjs 的 KINDS / SCOPES 并同步改本节。

四种口味 ​

⚠️ 两份坑位索引在这里归排错,不归参考。它们确实表格很多、确实适合查,但入口是「我遇到了什么症状」而不是「我要查某个值」——本页旧版本把它们同时列进两栏,读起来像是自相矛盾,已收进一栏。

写作与引用规范 ​

  • 代码定位用「文件路径 + 类名」,行号只标关键锚点。行号会随迭代漂移,路径与类名不会;
  • 代码片段 ≤ 30 行,超出部分给路径让读者自己去看,不整段粘贴;
  • 表结构、API 清单、权限串一律脚本生成(tools/gen-*.mjs → docs/.generated/),不手抄,避免与代码不一致;
  • 图用 Mermaid,架构图 / 时序图 / ER 图全部代码化,便于随代码更新;
  • 定制功能页首加 ::: tip 定制功能,与上游自带能力区分;
  • 结论必须实测。「应该是」「大概会」这类推测不进正文,进「未证实」节;
  • 不维护第二份目录:逐页清单只存在于 sidebar.mjs(有门禁),本页只写「每组为什么值得读」;
  • 正文不记行数:行数是漂移最快的一类数字,写进去就成了下一次的错。章节地图只记页数(改一次侧栏就能对齐),要量行数就现场量。上面那张自研占比表是个例外——它 drift 过两次,所以旁边直接附了复核命令。

本手册的事实来源 ​

来源用途
ainb/** 源码类名、路径、注解、错误码原文
ainb-ui-admin-vue3/** 源码组件路径、API 封装、权限指令
ainb-ui-admin-uniapp/** 源码移动端页面与分包、easycom 组件、请求封装
数据库 ainb-professional-initsystem_menu / system_nav_node 菜单清单、表结构、权限串、租户与账号数据
运行中系统(Web 前端 80 / 移动端 H5 9000 / 后端 48080)截图、真实响应、真实报错文案

别读旧库 ruoyi-vue-pro

本地还留着一个 ruoyi-vue-pro 库,它已停在 nav-node 特性之前——没有 system_nav_node,system_menu 里也没有「App菜单」。拿它生成菜单 / 表结构清单会得到过期结果。后端 application-local.yaml 与 application-dev.yaml 现在都指向 ainb-professional-init(application-prod.yaml 尚未跟随,仍是 ruoyi-vue-pro)。tools/lib/db.mjs 导出的 DB 常量是文档侧唯一口径,改库名只改那一处。

文档语料同步:root-path 已改为必填环境变量(它曾被配成 /,把库冻结在 115 篇)

后端 AgentDocProperties(enlev.agent.doc.*)早已不做向上探测了——第一版靠标记 ainb-ui-admin-vue3/docs 逐级向上找,现在 root-path 必须显式配,没配就抛 AGENT_DOC_ROOT_PATH_MISSING、不是目录则抛 AGENT_DOC_ROOT_PATH_INVALID。

🔴 而 c3dccc1a82 refactor(系统):区分专业版和开源版 曾把三个 profile 的 root-path 全改成 /(同一次提交还删掉了那段解释「为什么必填」的注释,于是配置里再没有任何线索说明 / 是错的)。这个值能通过校验 —— / 确实是个目录(Windows 下解析成当前盘根)—— 可 directories 默认是 ["guide", "develop"],/guide 与 /develop 都不存在,于是 planSync 对每个子目录各记一条「子目录不存在,已跳过」warning、continue 掉,最终语料扫出 0 篇,接口照样返回 200。

✅ 已修:三个 profile 现在都是 root-path: ${AGENT_DOC_ROOT_PATH:...}——local 的默认值是本机手册仓库位置(本站的 docs/guide 与 docs/develop 正好对上那两个子目录名),dev/prod 默认留空:没设环境变量就在第一次调用同步接口时抛 AGENT_DOC_ROOT_PATH_MISSING,而不是静默扫 /。base-url 三个 profile 都是 https://doc.enlev.cn,与前端引用白名单(ainb-ui-admin-vue3/src/utils/url.ts 的 MANUAL_DOC_HOSTS)是同一个事实的两份拷贝,改一边必须改另一边。

但改配置本身不会更新知识库:库里实测仍是 115 篇(root-path 还正确的那次同步灌进去的),本轮新增的 9 页移动端与 tasks.md 还没灌进去、改名的 4 页也还没删掉。实测差异是「语料 125 / 库里 115 / 对上 111」,跑 tools/gen-kb-url-map.mjs 复核。

🔴 而重跑同步也不足以让引用链接可用——线上站点本身还是坏的:托管端把 cleanUrls 的回落写成了 SPA 式 /index.html,对任意路径都返回 200 + 同一份首页,实测 125 条链接里 122 条落在首页(只有 /guide/、/develop/ 这类目录索引页因为命中 $uri/ 而幸免);且线上产物比语料旧(还有 05-practice,没有 06-practice 与 05-mobile)。所以「知识库的引用能点开正确的页」要三件都到位:① nginx 回落改回 try_files $uri $uri.html $uri/ =404;;② 重新构建并上传 dist/;③ 后端跑一次 doc-sync。验证一律用 pnpm check:live(比对渲染出的 <h1>,不看状态码——那台机器上什么都是 200),细节见构建与部署。

🔴 重跑同步曾经是破坏性的:planSync 的 REMOVED 差集判据是「库里有、这次没扫到」,doSync 对 REMOVED 一律删除并连带清掉段落与向量。差集的右项一旦因为 root-path 配错变成空集,左项就整个变成待删清单——在那个状态下跑一次 doc-sync,那 115 篇会被全部删掉,而向量库写入不在事务里、删掉补不回来。

✅ 4093e19c7d(2026-10-25)加了硬守卫:扫到 0 篇即中止整个同步、连知识库都不建,并把「拦下了几篇的删除」写进 failures。所以配错 root-path 的最坏后果已从「清空内置知识库」降级为「同步报错、什么都没做」。

但**「先 plan 再 sync」这一步不能省**:守卫只拦「一篇都没扫到」,拦不住「扫到一半」——例如 root-path 指到一个只 checkout 了一半的仓库,此时 develop 整个目录会被判成待删,而那是守卫刻意放行的(拦了就等于「真的删掉整个目录」永远传播不到库里)。doc-sync-plan 会如实显示 removedCount 与「子目录不存在,已跳过」的 warning,那是唯一能看出「这次扫描不完整」的地方。机制详见架构总览 · 坑与注意第 1 条。

相关页面 ​

  • 任务索引 —— 按「我要做 X」查该翻哪一页
  • 坑位索引 —— 按症状查的跨端清单(编号 A1–F6)
  • 移动端坑位 —— 按症状查的移动端专属清单(编号 M1–M24)
  • 使用手册 —— 界面上怎么用(读代码之前先读它)
  • 更新日志 —— 本站的版本、变更与遗留项