# backend-parent **Repository Path**: youcai-erp/backend-parent ## Basic Information - **Project Name**: backend-parent - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-11 - **Last Updated**: 2026-10-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # aijoin-backend(后端基础底座) 设计依据:`../docs/superpowers/specs/2026-09-15-backend-foundation-design.md` R1 结论(SB 4.1.1 + Jackson 3 生态可用性):`docs/r1-verdict.md` ## 前置 - **JDK 17**(本机:`F:\developer\soft\Java\zulu17.44.15-ca-jdk17.0.8-win_x64`)。 编译期由 `aijoin-parent` 里 `maven-enforcer-plugin` 的 `requireJavaVersion [17,18)` 硬失败兜底。 - **Maven 3.9.x 及以上(推荐,非硬要求)**。实测 **3.6.3 也够用**:根 `mvn -B clean verify` 在 Maven 3.6.3 + JDK 17 下**已跑通** —— `Tests run: 6, Failures: 0, Errors: 0`、reactor 4/4 SUCCESS (原文见 `docs/r1-verdict.md` §1.2)。Spring Boot 4.1.1 的父 POM **未**声明 Maven 最低版本门槛, "必须先升到 3.9.x"已撤销,只保留推荐。 - **MySQL 8**(本机 8.4,`127.0.0.1:3306`)。默认库 `aijoin_smoke`,由 JDBC URL 的 `createDatabaseIfNotExist=true` 让驱动自动建库(**账号需有 CREATE 权限**);库名/账号/口令 可用环境变量 `AIJOIN_SMOKE_DB_URL` / `AIJOIN_SMOKE_DB_USER` / `AIJOIN_SMOKE_DB_PASSWORD` 覆盖。 默认值见 `smoke-test/src/main/resources/application.yml`,**仅供本机开发,禁止在非本机环境复用**。 首次运行会真的建表(Flyway apply V1),之后运行只做 validate(`No migration necessary`)。 另外,`baseline-on-migrate` 已钉为 `false`(**有意的行为变更**):**非空 schema 但没有 Flyway 历史表时直接报错** (`Found non-empty schema(s) ... but no schema history table`),而不是悄悄 baseline 到版本 1、留下"已迁移"的假绿。 即"把假绿换成硬失败"——干净库照常建表;确实要接管既有库时须显式手工 baseline 并留痕。 ```bash export JAVA_HOME="F:/developer/soft/Java/zulu17.44.15-ca-jdk17.0.8-win_x64" ``` ## 模块 | 模块 | 作用 | 发布 | | --- | --- | --- | | `aijoin-backend-bom` | 依赖版本**分级**管理:Spring Boot BOM 是默认来源;本 BOM 只钉 SB 未管/需覆盖的条目(MyBatis-Plus、jsqlparser、springdoc) | 是 | | `aijoin-parent` | 构建父 POM(继承 SB 4.1.1) | 是 | | `starters/aijoin-common-starter` | **契约层**:统一响应包封 `R`、22 个错误码、traceId、全局异常处理、Jackson 3 序列化契约、分页契约、`IdGenerator` SPI、MP 雪花实现(**已创建**,222 个测试,分支 `feat/common-starter`) | 是 | | `smoke-test` | R1 兼容性回归护栏 + **契约层端到端护栏**(真应用 + 真 HTTP;**已创建**,20 个测试) | **否** | ## 接入 `aijoin-common-starter`(消费方) ```xml com.aijoin aijoin-common-starter ``` 引入即生效(`META-INF/spring/...AutoConfiguration.imports` 链路,无需 `@ComponentScan`): - **统一包封**:controller 直接 `return T`,出站即 `{"code":0,"data":T,"message":null,"traceId":"<32位hex>"}`; 抛 `BizException(CommonErrorCode.XXX)` ⇒ 按该码自身的 `httpStatus()` 出 HTTP 状态与 `code`。 - **traceId**:入站 `X-Trace-Id`(白名单 `[A-Za-z0-9._-]{1,128}`)原样透传,无则生成;响应头与包封同值。 - **Jackson 3 契约**:ID 转字符串(保 19 位精度)、金额 scale=2、时间 ISO-8601 带偏移、空值显式 `null`。 - **分页 `total`**:MP 在场且消费方**未自配** `MybatisPlusInterceptor` 时,本 starter 自动装一个内含 `PaginationInnerInterceptor` 的拦截器(消费方自配则**让位**)—— 否则 `selectPage` 的 `total` **静默为 0** (终审 M-2;契约与覆盖方式见 starter README「分页与 `total` 契约」)。 - **总开关**:`aijoin.common.enabled=false` 时不装配任何 bean。 > ⚠️ **可选依赖的接入方必读**:本 starter 的 web / validation / MyBatis-Plus / Jackson 依赖都是 `optional`, > **守卫必须关在嵌套条件配置类里**,而且**粒度要与最深的那个依赖对齐**:`@ConditionalOnWebApplication(SERVLET)` > **不蕴含 spring-webmvc** ⇒ 需要 webmvc 的包封 advice 必须再套一层 `@ConditionalOnClass(ResponseBodyAdvice.class)` > 的嵌套类(终审 M-1 实测:缺 webmvc 的消费方修复前**启动失败**)。 > 逐装配点的矩阵、可复跑的零残留判据与**入库探针**(`tools/optional-dep-probes/`,含构建/运行/期望退出码) > 见 `starters/aijoin-common-starter/README.md` 的「装配矩阵」与 `tools/optional-dep-probes/README.md`。 ## 验证 ```bash env -u MAVEN_OPTS mvn -B clean verify # 全量:242 个测试全绿(starter 222 + smoke 20),reactor 5/5 SUCCESS env -u MAVEN_OPTS mvn -B -pl smoke-test -am test # 只跑 smoke-test(必须带 -am:BOM/parent 靠 reactor 解析) ``` > 实测计数命令:`grep -E "^\[INFO\] Tests run:" | tail -2` ⇒ starter `222`、smoke `20`; > `grep -c '^\[WARNING\]' ` ⇒ `0`;`grep -ci deprecat ` ⇒ `0`。 > 历史 R1 的 `6 个测试 / reactor 4/4` 是**骨架期**的数字(`docs/r1-verdict.md` §1.2),别当现值。 > **不要在 IDE 里直接跑测试。** `smoke-test` 的三样 surefire 配置**只有经 Maven 运行时才生效**, > IDE 直跑会红(这是**预期**,不是代码坏了): > 1. `argLine` 的 `-Duser.timezone=Asia/Shanghai` —— 走 fork 命令行,IDE 直跑不会带; > 2. `` 空默认属性 —— JaCoCo 等 `@{argLine}` 晚绑定的注入位,IDE 直跑不存在; > 3. `systemPropertyVariables` 把 `spring.profiles.active` 钉成 `test` —— 本机 shell 有全局 > `SPRING_PROFILES_ACTIVE=mysql`,IDE 直跑会把它泄漏进测试上下文。 > > 因此时区与 profile 两条机制断言在 IDE 直跑时必然失败。要跑就用上面两条 `mvn` 命令。