feat: Kotlin 语法约束——只当语法糖用,不当新范式用

新增 docs/13-kotlin-style.md,并把它落成可执行的构建门禁,而不是一份只能靠
自觉遵守的建议。两条准入标准:只当语法糖(不引入新的思维模型)、每条规则必须
说得出它挡住的具体故障。

- KotlinSyntaxScanTest(源码扫描):禁 !! / lateinit / suspend / kotlinx.coroutines
  / RxJava / Reactor / data class Entity。走源码文本而非 ArchUnit,是因为这些在
  字节码上看不出来——!! 编译成 Intrinsics.checkNotNull(...) 调用,和其他 null
  检查混在一起。
- ArchitectureRulesTest 加「禁止工具类」:只禁 Utils/Util/Helper/Common 四个
  后缀,不禁 XxxManager——Spring 自身大量使用这个命名,一刀切会误伤。
- PersistedEntity + requiredId:把「从 repository 读出来的实体必有 id」变成
  一个有名字的类型,替掉 AuthAppService / LocalSeedDataConfig 里 7 处 .id!!。
- 5 个 Entity 实现 PersistedEntity。

两条故意不自动强制的写进了文档:companion object 靠 review 判断(现存 14 处
用法均合法,硬规则只会误伤);Entity 可被 Hibernate 代理目前没守住——未 apply
kotlin("plugin.jpa"),Entity 是 final 类,fetch = LAZY 会静默降级为 eager,现
因为零懒加载关联而未暴露。

docs/01-project-structure.md 顺带补了 Gradle 版本行的双向约束说明;README 修正
了 12 篇→13 篇文档、10 条→11 条规则,并补上工具类禁名。

验证:./gradlew build -PexcludeIntegration 通过。ArchitectureRulesTest 11 项、
KotlinSyntaxScanTest、NativeQueryScanTest 全绿;两条新规则均以「植入一个故意
违规、确认它变红」的方式验证过不是空转。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
Guangfei.Zhao
2026-09-30 16:01:22 +08:00
co-authored by Claude Code
parent 54f3b35245
commit aca7487be2
14 changed files with 347 additions and 23 deletions
+5 -4
View File
@@ -3,7 +3,7 @@
Continental 门店零售 App 的后端服务。**模块化单体**:14 个 Gradle 模块,一个可部署 jar,
模块边界由 Gradle 依赖图 + ArchUnit 测试守着,将来要拆微服务时按模块切即可。
架构决策全部写在 [`conti-docs/backend/`](../conti-docs/backend/) 的 12 篇文档里,
架构决策全部写在 [`conti-docs/backend/`](../conti-docs/backend/) 的 13 篇文档里,
本仓库是那些决策的落地。**文档是唯一事实来源**——代码和文档不一致时,改代码,不是改文档,
也不是把 ArchUnit 规则调松(规则调松了这套结构就白建了)。
@@ -15,7 +15,7 @@ Continental 门店零售 App 的后端服务。**模块化单体**:14 个 Grad
| Kotlin | 2.4.10 |
| Spring Boot | 4.1.0 |
| Spring Cloud | 2025.1.2 |
| Gradle | 9.5.1(wrapper) |
| Gradle | 9.5.0(wrapper)——**双向约束**:Boot 4.1 插件要 8.14+ 或 9.x,KGP 2.4.10 的完全支持上限是 9.5.0,升任一边都要重取交集 |
| MySQL | 8.4 |
版本对齐一律走 Gradle 原生 `platform()` BOM,**不引** `io.spring.dependency-management` 插件。
@@ -56,7 +56,7 @@ domains/A ───> domains/B-contract 只读查询:允许
domains/A ~~~> ApplicationEvent 写操作/状态联动:@TransactionalEventListener(AFTER_COMMIT)
```
具体 10 条规则见
具体 11 条规则见
[`architecture-test/.../ArchitectureRulesTest.kt`](architecture-test/src/test/kotlin/com/continental/retailapp/architecture/ArchitectureRulesTest.kt),
每条规则的注释里都写了它对应文档的哪一节。几条最容易踩的:
@@ -64,7 +64,8 @@ domains/A ~~~> ApplicationEvent 写操作/状态联动:@TransactionalEventLi
- `domain` 层不许出现 Spring / JPA 的任何引用,它的 bean 由 `infrastructure/config/` 显式 `@Bean` 装配;
- Controller 的端点方法必须返回 `ApiResult`;
- 不许字段注入(`@Autowired` 到字段上);
- 不许用 `java.util.Date` / `Calendar` / `SimpleDateFormat`,时间一律 `Instant`(UTC)。
- 不许用 `java.util.Date` / `Calendar` / `SimpleDateFormat`,时间一律 `Instant`(UTC);
- 不许 `XxxUtils` / `XxxUtil` / `XxxHelper` / `XxxCommon` 这类工具类(无状态逻辑用顶层函数,让文件名表达归属;有状态的用 `@Component`)。注意**不禁 `XxxManager`**——Spring 自身大量用这个后缀。
## 本地怎么跑