@@ -0,0 +1,460 @@
# 前后端开发约束规范(abacus 动静分离微服务)
> 版本:1.0( 2026-08-19) · 权威来源:本文件(`docs/coding-standards.md`)
> 适用范围:基于 `abacus-static-framework`( Vue 前端底座)与 `abacus.springboot.example`( Spring Boot Maven 微服务模板)开展的一切业务开发。
> 读者:**AI 智能体**(生成代码时强制遵守)与**团队全体成员**(评审与开发时共同遵循)。
---
## 1. 规范目的与适用范围
### 1.1 目的
1. **界面 → 代码 ** :用户可直接提供界面(原型图 / 截图 / 描述),由 AI 依据本规范生成前后端代码,无需逐条追问技术细节。
2. **统一约束 ** :团队所有成员在相同约束下开发,代码结构与风格一致,实现可预期的 Vibe Coding 工作流。
### 1.2 边界(必须)
| 端 | 只读共享区(不得修改) | 业务可写区(唯一开发位置) |
|---|---|---|
| 前端 | `abacus-static-framework/src/framework/**` | `abacus-static-framework/src/subsystem/**` |
| 后端 | `abacus.springboot.example` 的 `pom.xml` / `assembly.xml` / `config/{dev,test,prod}/` 基础结构 | `src/main/java/abacus/springboot.<应用名>/**` + `src/main/resources/sql/**` + `doc/升级日志.md` |
- **禁止**在 `src/framework/**` 内新增或修改代码;业务组件/工具无法复用标准件时,按 §4.6/§4.7 提交框架负责人评审后纳入框架,而非绕过。
- 前端框架升级不覆盖清单:`public` 、`vite.config.ts` 、`src/subsystem` 。
### 1.3 文档层级(单源化)
- 本规范是**前后端共享约束的唯一权威**;各子项目 `.project.agents/docs/context/CONVENTIONS.md` 只写本仓库特有约定,共享内容一律以 `详见 ../../docs/coding-standards.md §N` 指针引用,**禁止复制正文**(防止文档漂移)。
---
## 2. 动静分离架构总览
```
[前端] Vue 3 源码 (src/subsystem/**)
│ npm run build:prod
▼
vite outDir ──► [后端] 微服务工程 src/main/resources/html/vue/<应用名>/
│
│ mvn package( assembly.xml)
▼
发布包 *-bin.zip( jar + doc + sql + html)──► 部署(Nginx / 容器托管 html, Java 进程提供 API)
```
- 前后端通过 **HTTP 接口**通信;开发期由 `vite.config.ts server.proxy` 反代到后端(代替 Nginx)。
- 后端通过 Nacos 注册/发现;接口文档 springdoc( OpenAPI);统一响应体由 abacus.commons 的 `ResultResponseBodyWrapper` 包装(`Application.java` 注册 `@Bean` , `abacus.responseExcludePath` 排除不包装的 URI)。
---
## 3. APP_NAME 四处一致性(最高优先级,漏配静默失败)
新系统/新应用开发时,**应用名(APP_NAME)必须在以下四个位置一致**,任一处漏配即静默失败(启动正常但页面 404 / 接口不可达 / 路由不装配):
| # | 位置 | 作用 | 示例 |
|---|---|---|---|
| ① | 后端 `bootstrap.yml` → `spring.application.name` | Nacos 注册名(须唯一) | `example` |
| ② | 后端 `application.yml` → `abacus.controllerPackages` / `abacus.entitypackages` / `springdoc.packages-to-scan` 的**包前缀** | 框架装配 Controller / Entity / 接口文档扫描 | `abacus.springboot.example` |
| ③ | 前端 `src/subsystem/api/<APP_NAME>/*.ts` 的 **URL 首段 ** | 服务别名映射(§6.3) | `/example/xxx` |
| ④ | 前端 `vite.config.ts` → `build.outDir` 的**目录名** | 构建产物输出到后端 html 目录 | `html/vue/example/` |
包前缀规范:`abacus.springboot.<应用名>.<层>` (分层见 §5.1)。
**排查表 ** (页面/接口异常时按症状定位):
| 症状 | 优先检查 |
|---|---|
| 页面 404 / 菜单空白 | ④ outDir 目录名 ≠ 后端 html 实际加载目录;③ URL 首段错误 |
| 接口 404 / 未装配 | ② 扫描包前缀未含新包;① Nacos 未注册 |
| 接口 500 / 服务不可达 | ① 与 ③ 映射不一致(backendServices 找不到别名) |
**必须 ** :AI 生成代码完成后执行"APP_NAME 四联检"(见 §7.3 检查清单第 1 项)。
---
## 4. 前端开发规范(Vue 3 + TS + Vite + Element Plus + vxe-table + Pinia)
### 4.1 目录结构(`src/subsystem/**` 内)
```
src/subsystem/
├── api/<服务别名>/ # 接口封装:按微服务名分目录,按 Controller 分 ts 文件
├── router/dynamicRouter.ts # 菜单路由唯一注册点
├── views/<一级菜单>/<二级菜单>/index.vue # 菜单页面,按一/二级菜单分目录
├── extend/ # 框架扩展钩子(如初始化定时器、菜单徽章)
├── components/ # (业务需要时自建)子系统内部通用组件
├── hooks/ # (自建)业务组合式函数
├── store/ # (自建)业务状态机(Pinia)
├── styles/ # (自建)业务公共 css
├── types/ # (自建)业务公共类型
└── utils/ # (自建)业务工具函数与常量
```
- 参考实现:`views/log/operationLog/index.vue` (列表页)、`views/document/dataDictionary/index.vue` (客户端分页)、`views/config/business/index.vue` (可编辑表格)、`views/document/interfacedoc/` (容器页 :is 切换 List/Detail)。
- `unplugin-auto-import` 已配置(vue/vue-router/@vueuse/core + Element Plus resolver):**禁止**手动 `import { ref, reactive } from 'vue'` 等自动导入项。
### 4.2 命名
- 组件名:PascalCase,且必须与路由 `name` 一致(`<script lang="ts">export default { name: 'xxx' }</script>` )。
- 文件/目录:小写 + 短横线(kebab-case);views 目录用一级/二级菜单中文名或语义名。
- API 函数:`getXxx` / `saveXxx` / `deleteXxx` / `exportXxx` (动词+名词)。
- **禁止**语义为空的命名:`Manager` / `Helper` / `Util` / `Common` / `Misc` / `Tools` (工具类需用具体动词命名,如 `useTableQueryReload` )。
### 4.3 API 封装(`api/<服务别名>/*.ts`)
``` ts
import request from '@/framework/utils/request' ;
// GET:查询,参数走 params
export function getOperationLogs ( params : any = { } ) {
return request ( { url : '/sms/operationLogs' , method : 'get' , params } ) ;
}
// POST:表单提交(urlencoded)或 JSON(默认)
export function getAbacusAPIs ( data : any = { } ) {
return request ( {
headers : { 'Content-Type' : 'application/x-www-form-urlencoded' } ,
url : '/sms/document/abacusAPI/list' , method : 'post' , data
} ) ;
}
```
- **必须**: `url` 首段为服务别名(§6.3 映射);默认参数 `params/data = {}` 。
- **必须**: `status === 200` 时拦截器已自动解包 `data` , **业务代码禁止再取 `.data` **(直接使用返回值)。
- **禁止**:在组件内直接 `axios.get` / `fetch` ;一律经 `request` 封装(自动携带 token / commonParam / 服务映射 / 错误提示)。
### 4.4 页面模式(对应用户给出的界面)
| 界面形态 | 标准实现 |
|---|---|
| 查询 + 列表 | `AbQueryForm` ( fieldConfigs 配置式)+ `vxe-grid` ( `gridDefaultProps` + `proxyConfig.ajax.query` ) |
| 服务端分页 | `clientPage: false` (默认,配 `pagerConfig` ) |
| 客户端分页 | `clientPage: true` (配 `tableDataCache` / `filterNameRef` / `useQueryAndClientPaging` ) |
| 新增/编辑表单 | `el-dialog` + `AbForm` (配置式) |
| 详情 | `el-drawer` 或容器页 `:is` 切换 List/Detail 组件 |
| 可编辑表格 | `editConfig: { trigger: 'dblclick', mode: 'row' }` + `editRender: { name: 'input' }` + `@edit-closed` 保存 |
| 表内搜索 | `useInVxeGridSearch` |
| 刷新/查询联动 | `useTableQueryReload` / `useQueryParamsHandle` |
列表页模板骨架:
``` vue
< template >
< Title ... / > <!-- 页头 -- >
< div class = "form-container" > < AbQueryForm : formModel : fieldConfigs : queryEvent / > < / div >
< div class = "table-container" > < vxe-grid v-bind = "tableOptions" /> < / div >
< el -dialog > ... < / el-dialog >
< / template >
< script lang = "ts" >
export default { name : 'OperationLog' } <!-- 与路由 name 一致 -- >
< / script >
< script setup lang = "ts" >
const tableOptions = reactive < VxeGridProps > ( gridDefaultProps ( {
params : reactive < VxeTableParam > ( { clientPage : false } ) ,
rowConfig : { keyField : 'id' } ,
pagerConfig : { enabled : true , pageSize : 10 } ,
proxyConfig : {
seq : true , sort : true , filter : true ,
props : { result : 'data' , total : 'total' } , <!-- 与后端分页契约一致 , § 6.4 -- >
ajax : { query : ( { page , sorts , filters } ) => getOperationLogs ( useQueryParamsHandle ( params , page , sorts , filters ) ) }
} ,
columns : [ { type : 'seq' , title : '序号' } , { field : 'menu' , title : '系统模块' } , ... ]
} ) )
< / script >
```
### 4.5 菜单与路由
- **唯一注册点**: `src/subsystem/router/dynamicRouter.ts` 。一级菜单 `{path, name, redirect, meta:{title}}` ,二级 `{path, name, component: () => import('@/subsystem/views/...'), meta:{title, keepAlive:true}}` 。
- 权限:无 `v-permission` 指令。框架 `permissionStore.filterAsyncRoutes` 将后端菜单(`listRoutes` / `publicData.extLocalRouter` )与 dynamicRouter 按 `url === path` 匹配、过滤无权限路由后 `addRoute` 。**业务侧只需正确注册路由与后端菜单 URL 一致**。
- 内置指令:`v-debounce` / `v-throttle` ( `framework/directives/` )。
### 4.6 UI 组件优先级(必须按序选用)
1. `src/framework/components/standard/` (标准件:`AbForm` 、`AbQueryForm` 、`AbSection` 、`ClickCopy` 、`FilePreviewDialog` 、`ImportExcel` 、`LogShow` 、`RealTimeSearchSelect` 、`SensitiveText` 、`Text` 、`Layout/BottomFloat` 等,使用方式见框架示例模块);
2. 表格一律使用 **vxe-table ** ( `vxe-grid` + `gridDefaultProps` );
3. 除表格外使用 **Element Plus ** (已自动按需引入);
4. 以上均不满足时,用 css/html 自实现组件;**泛用性高的必须提交框架负责人**发布到公司 UI 组件库,不得仅留在业务内。
### 4.7 工具函数优先级
1. `src/framework/utils/standard/` (标准件:`vxe` 、`dataHandleUtil` 、`globalHandle` 、`security` 、`baiduMap` );
2. 已集成的 `xe-utils` ;
3. 自研(同上,泛用性高需提交评审)。
### 4.8 状态管理(Pinia)
- 业务状态放 `subsystem/store/` , `defineStore` 命名 `use<Xxx>Store` 。
- 服务别名映射:`settingsStore.backendServices` (来自 `window.frameBaseConfig` ),**业务代码不得篡改**。
### 4.9 发布与框架升级
- 打包:`npm run build:prod` (测试 `build:stage` 、开发 `dev` );产物直出到后端 `resources/html/vue/<应用名>/` 。
- 发布前:在 `/data/doc/升级日志.md` (后端)记录本次升级内容。
- 框架升级:只覆盖 `src/framework/**` 等非业务区;`public` 、`vite.config.ts` 、`src/subsystem` 不动,覆盖后 `npm install` 。
---
## 5. 后端开发规范(Spring Boot + abacus 微服务模板)
### 5.1 分层职责(包前缀 `abacus.springboot.<应用名>.`)
| 包 | 职责 | 扫描配置 | 示例 |
|---|---|---|---|
| `api` | 对外接口 Controller(微服务间/系统间) | springdoc.packages-to-scan | `JcBillController` |
| `api.view` | 请求/响应 DTO( ApiReq* / ApiResp* / Api*) | — | `ApiReqJcBill` |
| `controller` | 前端/内部接口 Controller | abacus.controllerPackages | `AutoCompleteController` 、`BaseServlet` |
| `dao` | JPA 实体 Entity(表映射) | abacus.entitypackages | `JcBill` |
| `esb` | **Service 编排层 ** ( @Service ,只编排不做 SQL) | — | `JcBillBizService` |
| `wsi` | 服务接口 *ServiceIF( esb/impl 依赖的接口) | — | `JcBillServiceIF` |
| `pi` | 数据访问接口 *AccessIF | — | `JcBillAccessIF` |
| `impl` | 数据访问实现(原生 SQL,**必须参数化**) | — | `JcBillAccess` |
| `repository` | Spring Data JPA Repository | — | `JcBillRepository` |
| `config` | @Configuration (Bean / 配置常量) | — | `JcConfiguration` 、`JcConfigKey` |
| `util` / `vo` | 工具 / 第三方 VO(**只可引用既有,新增禁止**,见 §8.4) | — | `DateUtil` 、`BaiduToken` |
依赖方向(必须单向):`api/controller → esb → {wsi/pi/repository} → dao` ; `impl` 实现 `pi` ; `config` 被各层依赖;**禁止**跨层反向依赖(如 dao 依赖 api、esb 直接写 SQL)。
### 5.2 Controller 模板(必须遵循)
``` java
@RestController
@RequestMapping ( value = " /3.0/jc " )
@Tag ( name = " 稽查接口服务 " , description = " 稽查接口服务说明 " )
public class JcBillController extends BaseServlet {
@Autowired private JcBillBizService jcBillBizService ;
@RequestMapping ( value = " createJcBill " , method = RequestMethod . POST )
@Operation ( summary = " 稽查收货订单保存 " )
public ApiReqJcBill createJcBill ( @RequestParam ( required = false ) String billInfo ) throws Exception {
try {
if ( StringUtils . isBlank ( billInfo ) ) throw new BusinessException ( " 参数[billInfo]为空! " ) ;
ApiReqJcBill reqJcBill = JSON . parseObject ( billInfo , ApiReqJcBill . class ) ;
if ( StringUtils . isBlank ( reqJcBill . getId ( ) ) ) jcBillBizService . saveJcBill ( reqJcBill ) ;
else jcBillBizService . updateJcbill ( reqJcBill ) ;
return reqJcBill ; // 直接返回业务对象,由 ResultResponseBodyWrapper 包装统一响应体
} catch ( Throwable e ) {
LOG . error ( " ... " , e ) ;
throw e ; // 重新抛出,交框架统一处理
}
}
}
```
- **必须**: `@RestController` + `@RequestMapping` + `@Tag` ( springdoc);方法级 `@RequestMapping(value, method)` + `@Operation` 。
- **必须**:方法签名 `throws Exception` ;入参 `@RequestParam(required = false)` ;参数空校验 `StringUtils.isBlank → throw new BusinessException("参数[x]为空!")` 。
- **必须**: **直接 return 业务对象**,禁止手动拼响应体;方法内 try/catch(Throwable) 记日志后 rethrow。
- **禁止**: Controller 内写业务编排/SQL(下沉到 esb,见 §5.3);Controller 与 Repository 直接耦合。
### 5.3 Service 编排层(esb/)
- 一个业务用例对应一个 `XxxBizService` ( @Service ),负责事务边界、多仓储编排、DTO↔Entity 转换。
- **只编排,不做 SQL**;数据访问通过 `wsi` ( ServiceIF)或 `pi` ( AccessIF) / `repository` 完成。
### 5.4 数据访问
- **原生 SQL 复杂查询**: `pi/XxxAccessIF` 定义接口,`impl/XxxAccess` 实现;**SQL 一律 `?` 参数化,禁止字符串拼接**(示例 `JcBillAccess` 已全量参数化)。
- **标准 CRUD / 派生查询**: `repository/XxxRepository extends JpaRepository<Entity, String>, JpaSpecificationExecutor<Entity>` ,派生方法 `findByXxx(...)` 。
- 服务接口 `wsi/XxxServiceIF` 供上层依赖,隔离实现细节。
### 5.5 Entity( dao/)
``` java
@Entity
@Table ( name = " jc_bill " )
@JsonIgnoreProperties ( ignoreUnknown = true )
@Schema ( description = " 稽查主单 " )
public class JcBill implements Serializable {
@Id @Schema ( description = " 稽查单号 " , required = true , example = " JC202411180001 " )
private String id ;
@Version private Integer version = 1 ; // 乐观锁(必须)
private int status = 1 ;
public final static int STATUS_MINUS_THREE = - 3 ; // 状态常量(集中定义)
public final static int STATUS_ZERO = 0 ;
@Transient private String recsource ; // 非持久字段
// 手写 getter/setter(禁止 Lombok 或代码生成依赖,与既有风格一致)
}
```
- **必须**: `@Entity @Table @JsonIgnoreProperties(ignoreUnknown=true) @Schema` ; `@Id String` (业务主键,ID 由 DaoIdGenerator 生成,§5.7);`@Version Integer` 乐观锁;状态用 `public final static int STATUS_*` 常量;`@Transient` 标注非持久字段。
### 5.6 Config( config/)
- `XxxConfiguration` ( @Configuration ):注册框架配置项默认值(`@Bean AbacusConfigNote` , keyGroup 按业务域)、`DaoIdGenerator` 等基础设施 Bean。
- `XxxConfigKey` :配置 key 常量类。
### 5.7 ID 生成(DaoIdGenerator)
``` java
@Bean ( name = " jcBillIdGenerator " )
public DaoIdGenerator jcBillIdGenerator ( ) {
DaoIdGenerator g = new DaoIdGenerator ( ) ;
g . setTargetTableName ( " jc_bill " ) ;
g . setPrefix ( " JC " ) ; // 业务前缀,全局唯一
g . setSerialLength ( 4 ) ;
g . setUseDateFormat ( true ) ;
g . setDateFormat ( " yyyyMMdd " ) ;
return g ;
}
```
**禁止**手动拼 ID(如 `UUID` 混用、自增主键代替业务主键),业务主键一律走 `DaoIdGenerator.takeDaoId(null)` 。
### 5.8 SQL 变更(必须三处联动)
| 场景 | 位置 | 规则 |
|---|---|---|
| 建表 | `sql/table/mysql.sql` **与 ** `sql/table/sqlserver.sql` | **双份必须同步 ** (多库支持) |
| 历史变更 | `sql/upgrade.xml` | `<upgrade version="yyyy-MM-dd[.count]">` 按版本升序执行;`translator="true"` 时以 **SQL Server 语法**书写由框架翻译到各库;明细表自增列写在字段类型后 |
| 初始化数据 | `sql/data/` | acas 子系统/菜单/模块注册等 |
- **禁止**只改一份库脚本;禁止绕过 upgrade.xml 直接改已发布环境的表。
### 5.9 多环境配置(必须三套同步)
- `src/main/resources/config/{dev,test,prod}/` 三套**同构**: `application.yml` / `bootstrap.yml` / `application-xxljob.yml` / `logback-*.xml` 。
- 新增/修改配置项必须同步三个环境(或按需说明);字段结构保持一致。
- Maven profile: `dev` (默认)/ `test` / `prod` , `-P` 指定;resources 仅打包当前环境 config + `sql/**` + `META-INF` 。
### 5.10 打包发布
- `pom.xml` `<artifactId>` 设为 `abacus.springboot.<应用名>` ;版本号在 `<version>` 。
- 发布包:`mvn package` → `target/${artifactId}-${version}-bin.zip` ( jar + doc + sql + html,由 `assembly.xml` 组装)。
- 前端产物:`resources/html/vue/<应用名>/` 自动打入 zip; jar 内**不含** html(动静分离)。
### 5.11 升级日志
- 每个功能更新在 `src/main/resources/doc/升级日志.md` 追加:`## <版本号>(<日期>)` 下按「依赖子系统 / 前置条件 / 更新说明」三段记录,更新说明逐条列变更。
---
## 6. 前后端接口契约(request.ts 实测确认)
### 6.1 统一响应体
```
{ status, message, data, errorCode }
```
- `status` 为**业务状态码,与 HTTP 状态码语义独立**。
- **前端拦截器在 `status === 200` 时自动解包 `data` **——业务代码拿到的就是 data,**禁止再取 `.data` **。
- 后端:Controller 直接 return 业务对象,由 `ResultResponseBodyWrapper` 包装;需排除的 URI 配在 `abacus.responseExcludePath` 。
### 6.2 异常码(强制)
- **业务异常码首位必须为 `9` **(拦截器 `String(status)[0] === '9'` → 提示 message 并 reject);
- **系统异常码首位必须为 `5` **(提示 `[errorCode]系统异常` )。
- 前端对 401 / 429 / 503 有专门提示分支。
### 6.3 URL 别名映射
- 前端 `url` 首段 = **服务别名 ** ; `request.ts` 的 `urlServiceHandle` 用 `settingsStore.backendServices[别名]` (来自 `window.frameBaseConfig` )替换为真实服务名。
- 例:`/sms/operationLogs` → `backendServices.sms` (如 `acas` )→ 实际请求 `/acas/operationLogs` 。
- 新服务接入:在 `window.frameBaseConfig.backendServices` 增加别名映射;**禁止**前端硬编码真实服务名。
### 6.4 分页契约(vxe-grid ↔ 后端)
- 前端 `proxyConfig.props: { result: 'data', total: 'total' }` : **后端分页响应必须为 `{ data: [...], total: N }` **( data 为当前页记录,total 为总数)。
- 查询参数:前端 `useQueryParamsHandle(params, page, sorts, filters)` 组装 page/sort/filter 参数;后端 Controller 接收并映射到分页查询。
### 6.5 Excel 导出(ArrayBuffer 不解包)
- 二进制响应(`response.data.data instanceof ArrayBuffer` )时拦截器**返回整个 response**;前端取 `response.data` (含 status/message)自行处理 Blob 下载,**不得**当 JSON 解包。
### 6.6 鉴权与 Token(前端自动处理,业务无感)
- 请求自动携带 `Authorization: Bearer <access_token>` 。
- **剩余有效期 < 10 分钟自动刷新 token**,并发请求进入队列、刷新完成后重放。
- 请求配置 `custom: { noauth: true }` 可跳过 token(白名单接口)。
- HTTP 401 → 提示并跳登录页;500/404/其他 → 统一提示。
### 6.7 commonParam Header(自动附带)
- 每个请求自动携带 `commonParam` Header( JSON 字符串):`menuName` (一级菜单)、`moduleId` / `moduleName` (二级菜单,经 `meta.id/title` )、`businessDomain` / `businessDomainName` (业务域)。
- 后端可据此做菜单/模块/业务域审计;前端业务代码**无需也不得**手工伪造。
---
## 7. AI 生成代码工作流(用户提供界面 → 前后端代码)
> 面向智能体:收到用户界面素材后,**严格按下述顺序执行**,每步产出物明确。
### 7.1 输入与前置
- 用户输入:界面原型(图片/链接/描述)+ 业务说明。
- AI 必须先确认:应用名(APP_NAME)、服务别名、数据库(MySQL / SQL Server 二选一为主)、所属子系统编码(`public/data/data.js` 的 `currentSubsystem` )。
### 7.2 步骤序列(每步产出物)
| 步骤 | 动作 | 产出物 |
|---|---|---|
| S1 | 界面 → 页面清单 | `views/<一级>/<二级>/index.vue` ( + List/Detail 拆分),确定查询字段/表格列/表单字段/操作按钮 |
| S2 | 生成 API 封装 | `subsystem/api/<别名>/<模块>.ts` (每页一个文件,§4.3) |
| S3 | 注册路由 | `subsystem/router/dynamicRouter.ts` 增加菜单项(name 与组件名一致) |
| S4 | 后端 Controller | `controller/` 或 `api/` 下 XxxController(§5.2 模板);确定 URL(与前端 ts 首段+路径一致) |
| S5 | 后端 Service/数据访问 | `esb/XxxBizService` + `wsi/XxxServiceIF` + `pi/XxxAccessIF` + `impl/XxxAccess` (原生 SQL 参数化)或 `repository/XxxRepository` |
| S6 | 后端 Entity/DTO | `dao/Xxx` + `api/view/` DTO(字段与前端表单/表格对齐,命名驼峰) |
| S7 | SQL 脚本 | `sql/table/{mysql,sqlserver}.sql` 双份 + `sql/upgrade.xml` 追加版本段 |
| S8 | 配置核对 | `application.yml` 扫描包、`vite.config.ts` proxy/outDir、`data.js` 子系统;如为新应用另核 bootstrap.yml/application.yml APP_NAME |
| S9 | 联调自检 | 按 §7.3 清单逐项检查;后端启动 + 前端 `npm run dev` 冒烟 |
| S10 | 收尾 | 升级日志(后端 `doc/升级日志.md` )、Conventional Commits 提交 |
### 7.3 必须/禁止清单(AI 生成代码的强制收尾检查)
**必须: **
1. APP_NAME 四联检(§3 表 ①~④ 一致)。
2. 前端 API 一律走 `request` 封装;`status===200` 后不取 `.data` 。
3. 后端 Controller return 业务对象、`throws Exception` 、参数空校验抛 `BusinessException` 。
4. 原生 SQL 全量 `?` 参数化;建表脚本 mysql/sqlserver 双份同步。
5. 组件/工具优先复用 standard 标准件(§4.6/§4.7)。
6. 分页接口响应 `{ data, total }` ; Excel 导出走 ArrayBuffer 分支。
**禁止: **
1. 修改 `src/framework/**` 、`pom.xml` 依赖版本、`assembly.xml` 结构。
2. 前端硬编码服务名/手动拼 URL;后端手拼业务主键(须 `DaoIdGenerator` )。
3. 新建 `Util/Helper/Manager/Common` 类;Controller 写 SQL;跨层反向依赖。
4. 只改一份数据库脚本;绕过 upgrade.xml。
5. 使用未在项目中的第三方库(先确认已引入或提交评审)。
### 7.4 联调自检清单(冒烟)
- [ ] 后端启动无 Bean/扫描异常(Nacos 已注册、接口文档 springdoc 能列出新接口)
- [ ] 前端菜单可见(后端菜单数据已注册)、页面可打开、查询/新增/编辑/导出全链路通
- [ ] 错误场景(参数为空、无权限)提示符合预期(9xx 业务提示 / 5xx 系统提示)
- [ ] 多库(MySQL/SQL Server)下 DDL 均可执行(若涉及)
---
## 8. Vibe Coding 协作约定(团队通用)
### 8.1 提交规范
- **Conventional Commits**: `type(scope): subject` ,如 `feat(jcbill): 新增稽查收货保存接口` 、`fix(sms): 修复日志分页总数错误` 。type 常用:`feat / fix / docs / refactor / chore / test` 。
### 8.2 代码风格
- Java:4 空格缩进、行宽 ≤ 120;**默认不写注释**,仅在 WHY 不明显处写一行注释。
- TS/Vue:遵循框架现有风格;组件选项式 `name` + `<script setup>` 组合。
- 命名:动词+名词、语义明确;禁语义空名(见 §4.2)。
### 8.3 评审约定
- 提交前自检 §7.3 清单;PR 描述按「变更内容 / 验证方式 / 影响范围」三段。
- 涉及框架标准件扩展:先与框架负责人确认。
### 8.4 util/vo 兼容说明(重要)
- 示例模块遗留的 `util/DateUtil` 、`util/RequestUtil` 、`vo/BaiduToken` 等为**既有兼容代码**:新代码**可以引用**,但**禁止新增**此类语义空名类;新工具按 §4.7 原则命名(如 `DateToUpperChinese` 保留既有)。
- `util/` 、`vo/` 包原则上不再新增文件;确需时先评审。
---
## 附:文档导航
| 文档 | 内容 |
|---|---|
| `docs/architecture.md` | 动静分离架构总览与链路 |
| **本文件(coding-standards.md) ** | 前后端开发约束规范(权威) |
| `docs/agent-guide.md` | AI 生成代码工作流与提示词协议 |
| `docs/README.md` | 文档中心索引 |
| 前端 `.project.agents/` | 前端仓库治理(CLAUDE/AGENTS/CONVENTIONS 等) |
| 后端 `.project.agents/` | 后端仓库治理(CLAUDE/AGENTS/CONVENTIONS 等) |