本文档汇总 tag-system 与 fullstack-merge-deploy 两个技能的硬性约束,实施过程必须严格遵守。
字段命名:group_id、parent_id、sort_order、entity_type、entity_id 全部小写下划线。
parent_id=NULL 的同名根节点buildTree() 时遇到 parent_id=null 的视为根非 RESTful 风格,所有写操作用 POST:
POST /api/tags/groups/{id}/edit 而非 PUT
POST /api/tags/groups/{id}/delete 而非 DELETE
POST /api/tags/{id}/edit
POST /api/tags/{id}/delete
POST /api/tags/{id}/move
请求体定义为 Controller 内部 static class + Lombok @Data。
tagIds 列表,后端先 deleteAll 再 insertmoveTag 必须实现 isDescendant() 检查,向上遍历 parentId 链,防止形成环。
四种:create / overwrite / merge / skip
api/tag.js 所有标签 API 封装
stores/tag.js Pinia store(含 buildTree)
components/tag/
TreeNodeItem.vue 递归树节点
TagSelector.vue 标签选择器弹窗
views/TagsView.vue 标签管理页面(左右分栏)
新增业务对象打标(如 article、knowledge)只需:
TagSelector 传入 entity-type="article" 和 :entity-id="article.id"application.yml 中 server.port: 7945
frontend/vite.config.js 中 build.outDir 必须直接指向后端 static:
build: {
outDir: path.resolve(__dirname, '../backend/src/main/resources/static'),
emptyOutDir: true
}
绝对不能:
addResourceHandlers("/**") — 会饿死 @ControlleraddViewControllers + forward: — Spring Boot 3.x 返回空 body/**/{var} 模式 — PathPatternParser 不支持 ** 后接路径变量必须:
WebMvcConfig.java 只配 CORSSpaController.java 用 @RequestMapping("/{x:[^.]+}") 多段模式返回 ClassPathResource("/static/index.html")@RequestMapping(value = {
"/{x:[^.]+}",
"/{x:[^.]+}/{y:[^.]+}",
"/{x:[^.]+}/{y:[^.]+}/{z:[^.]+}"
})
注意:Java 字符串中 [^.] 不要写成 [^\.]。
run.bat 开头必须 chcp 65001 >nul(中文 UTF-8 输出)npm run build → mvn package -DskipTests*.bat text eol=crlf
*.cmd text eol=crlf
*.sh text eol=lf
spring-boot-starter-web 已内置 classpath:/static/ 处理>/dev/null 或 >nul 重定向到 nul(除 chcp 65001 >nul 这种已知安全场景,cmd 内部识别)$HOME 显式替换为 C:/Users/AdministratorPOST {base_url}/chat/completions{ model, messages, temperature, max_tokens }{ choices: [{ message: { content } }] }org.bitbucket.cowwoc:diff-match-patch:1.2 或 org.eclipse.mylyn.github:org.eclipse.mylyn.wikitext:diff-match-patch按 AGENTS.md 规则: