@ifrankwang/openspec-agents 0.118.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +91 -0
  2. package/assets/agents/openspec-architect.md +61 -0
  3. package/assets/agents/openspec-developer.md +21 -0
  4. package/assets/agents/openspec-main.md +35 -0
  5. package/assets/agents/openspec-reviewer-architecture.md +60 -0
  6. package/assets/agents/openspec-reviewer-maintainability.md +59 -0
  7. package/assets/agents/openspec-reviewer-performance.md +49 -0
  8. package/assets/agents/openspec-reviewer-security.md +51 -0
  9. package/assets/agents/openspec-reviewer-style.md +50 -0
  10. package/assets/agents/openspec-reviewer-task.md +40 -0
  11. package/assets/agents/openspec-reviewer-tool.md +30 -0
  12. package/assets/dashboard/index.html +295 -0
  13. package/assets/skills/api-conventions/SKILL.md +60 -0
  14. package/assets/skills/api-test/SKILL.md +175 -0
  15. package/assets/skills/architecture-evolution/SKILL.md +60 -0
  16. package/assets/skills/db-conventions/SKILL.md +62 -0
  17. package/assets/skills/ddd-architecture/SKILL.md +261 -0
  18. package/assets/skills/environment-cleanup/SKILL.md +44 -0
  19. package/assets/skills/java-api-conventions/SKILL.md +30 -0
  20. package/assets/skills/java-code-maintainability/SKILL.md +62 -0
  21. package/assets/skills/java-code-performance/SKILL.md +49 -0
  22. package/assets/skills/java-code-style/SKILL.md +54 -0
  23. package/assets/skills/java-db-conventions/SKILL.md +44 -0
  24. package/assets/skills/java-ddd-architecture/SKILL.md +533 -0
  25. package/assets/skills/java-dev-practices/SKILL.md +110 -0
  26. package/assets/skills/java-quality-gate/SKILL.md +455 -0
  27. package/assets/skills/java-quality-gate/reference/pmd-rules.md +16 -0
  28. package/assets/skills/java-quality-tool-improve/SKILL.md +142 -0
  29. package/assets/skills/java-security/SKILL.md +59 -0
  30. package/assets/skills/java-technical-debt/SKILL.md +36 -0
  31. package/assets/skills/orchestrator/SKILL.md +65 -0
  32. package/assets/skills/quality-gate/SKILL.md +84 -0
  33. package/assets/skills/security-baseline/SKILL.md +101 -0
  34. package/assets/skills/technical-debt/SKILL.md +78 -0
  35. package/assets/workflows/task.yaml +177 -0
  36. package/package.json +79 -0
  37. package/src/adapters/agent-md.ts +37 -0
  38. package/src/adapters/claude-code/index.ts +35 -0
  39. package/src/adapters/codex/index.ts +161 -0
  40. package/src/adapters/mcp-common/cli.ts +64 -0
  41. package/src/adapters/mcp-common/index.ts +137 -0
  42. package/src/adapters/mcp-common/json-schema.ts +53 -0
  43. package/src/adapters/mcp-common/server.ts +157 -0
  44. package/src/adapters/opencode/agents.ts +80 -0
  45. package/src/adapters/opencode/dashboard.ts +64 -0
  46. package/src/adapters/opencode/index.ts +34 -0
  47. package/src/adapters/opencode/json-schema.ts +60 -0
  48. package/src/adapters/opencode/skills.ts +19 -0
  49. package/src/adapters/opencode/tools.ts +78 -0
  50. package/src/adapters/plugin-common/index.ts +173 -0
  51. package/src/adapters/zcode/index.ts +32 -0
  52. package/src/core/constants.ts +46 -0
  53. package/src/core/dashboard.ts +101 -0
  54. package/src/core/derive.ts +146 -0
  55. package/src/core/exemptions.ts +168 -0
  56. package/src/core/git.ts +373 -0
  57. package/src/core/index.ts +76 -0
  58. package/src/core/namespace.ts +12 -0
  59. package/src/core/paths.ts +23 -0
  60. package/src/core/provider.ts +74 -0
  61. package/src/core/state.ts +357 -0
  62. package/src/core/task-children.ts +59 -0
  63. package/src/core/tasks-md.ts +89 -0
  64. package/src/core/tools/gate.ts +165 -0
  65. package/src/core/tools/lifecycle.ts +645 -0
  66. package/src/core/tools/schemas.ts +363 -0
  67. package/src/core/tools/submit.ts +863 -0
  68. package/src/core/tools/types.ts +129 -0
  69. package/src/core/types.ts +135 -0
  70. package/src/core/views.ts +195 -0
  71. package/src/core/workflow/collector.ts +150 -0
  72. package/src/core/workflow/engine.ts +576 -0
  73. package/src/core/workflow/index.ts +56 -0
  74. package/src/core/workflow/loader.ts +277 -0
  75. package/src/core/workflow/poller.ts +159 -0
  76. package/src/core/workflow/reset.ts +93 -0
  77. package/src/core/workflow/status.ts +1010 -0
  78. package/src/core/workflow/submit.ts +331 -0
  79. package/src/core/workflow/types.ts +100 -0
  80. package/src/core/workflow/writeback.ts +48 -0
  81. package/src/dashboard/page.ts +19 -0
  82. package/src/index.ts +2 -0
  83. package/src/skills/resolve.ts +95 -0
  84. package/src/skills/scan.ts +29 -0
@@ -0,0 +1,533 @@
1
+ ---
2
+ name: java-ddd-architecture
3
+ description: 仅限 Java 后端开发场景。DDD 四层分层与六边形(Hexagonal)两种架构风格 Java 实现——Java 代码实现规范、Spring DI、MapStruct、ArchUnit 规则。DDD 方法论见 ddd-architecture。适用场景同前。
4
+ capabilities: ["architecture", "tech-stack-java"]
5
+ ---
6
+
7
+ > **项目规范优先**:本 skill 所列约定为推荐标准。若项目已有明确规范且与本 skill 不一致,以项目规范为准。
8
+ > 本 skill 是 ddd-architecture 的 Java 实现配套,仅含 Java/Spring 特有实现细节。DDD 方法论见 ddd-architecture。调用本 skill 须同时加载 ddd-architecture。
9
+
10
+ ## 包结构
11
+
12
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
13
+
14
+ \`\`\`
15
+ {basePackage}
16
+ ├── domain
17
+ │ ├── model ← 聚合根、实体、值对象(纯 POJO,零框架依赖)
18
+ │ │ ├── event ← 领域事件定义(record)
19
+ │ │ └── spec ← Specification 业务规则组合
20
+ │ ├── service ← Domain Service 接口 + 实现(核心领域逻辑)
21
+ │ ├── repository ← Repository 接口(不含实现)
22
+ │ ├── factory ← 领域工厂(复杂对象创建)
23
+ │ └── exception ← 领域异常类 + ErrorCode 常量(零框架依赖)
24
+ ├── application
25
+ │ ├── command ← 写操作命令对象
26
+ │ ├── query ← 读操作查询对象
27
+ │ ├── service ← Application Service(编排用例,不含技术实现)
28
+ │ └── dto ← 应用层 DTO(模块间传输)
29
+ ├── infrastructure
30
+ │ ├── persistence ← PO、Mapper、对象转换器
31
+ │ ├── llm ← LLM 适配器
32
+ │ ├── excel ← POI 解析器/写入器
33
+ │ ├── auth ← 认证适配器
34
+ │ ├── desensitize ← 脱敏适配器
35
+ │ ├── external ← 外部查询适配器(search-provider 等)
36
+ │ ├── acl ← Anti-Corruption Layer(外部模型 ↔ 领域模型转换)
37
+ │ ├── queue ← 消息队列适配器
38
+ │ └── config ← Spring 配置 Bean
39
+ └── interfaces
40
+ ├── controller ← REST Controller(仅参数校验 + 调用 application)
41
+ ├── security ← 登录接口 / JWT 过滤器 / SecurityConfig
42
+ ├── dto ← 接口层 DTO(入参/出参)
43
+ └── assembler ← DTO ↔ Domain 转换器
44
+ ```
45
+
46
+ **六边形(Hexagonal)包组织**
47
+
48
+ 内核保留 `domain` + `application` 两个包共同构成应用内核;`interfaces` 包承担 **driving adapter(入站适配器)** 角色,`infrastructure` 包承担 **driven adapter(出站适配器)** 角色。包结构沿用上表,仅角色语义调整:
49
+
50
+ | 包 | 六边形角色 | 说明 |
51
+ |----|-----------|------|
52
+ | `domain` | 内核 | driven port 定义处(Repository、EventPublisher、OrderGenerationPort 等接口) |
53
+ | `application` | 内核 | driving port 定义处(ApplicationService 接口) |
54
+ | `interfaces` | driving adapter(入站) | Controller 等外部入口调用 application 定义的端口接口 |
55
+ | `infrastructure` | driven adapter(出站) | 实现 domain 定义的 Port 接口(持久化、LLM、外部集成等) |
56
+
57
+ ## 层间依赖
58
+
59
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
60
+
61
+ \`\`\`
62
+ interfaces → application → domain ← infrastructure
63
+ ```
64
+
65
+ 箭头方向即依赖方向:interfaces 依赖 application,application 依赖 domain,infrastructure 依赖 domain(实现 domain 定义的 Port/Repository 接口)。infrastructure 不依赖 interfaces,interfaces 不直接依赖 infrastructure。
66
+
67
+ **六边形**:依赖规则不变,仅换角色表述——driving adapter(interfaces)依赖 application 定义的 driving port(ApplicationService 接口);driven adapter(infrastructure)实现 domain 定义的 driven port(Repository、EventPublisher、OrderGenerationPort 等接口)。adapter 之间无依赖,内核不依赖 adapter。
68
+
69
+ ## 各层职责
70
+
71
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
72
+
73
+ | 层 | 职责 | 禁止 |
74
+ |----|------|------|
75
+ | interfaces | 参数校验、调用 application、DTO 转换 | 写业务逻辑、直接访问 infrastructure/domain 实体 |
76
+ | application | 编排业务用例、事务边界、协调 domain service | 技术实现细节(SQL、HTTP、LLM 调用) |
77
+ | domain | 核心领域逻辑、聚合根行为、领域服务 | 任何框架依赖(Spring/MyBatis/Spring AI) |
78
+ | infrastructure | 技术实现:持久化、外部集成、消息队列、ACL 转换 | 业务规则判断 |
79
+
80
+ 六边形视角下,interfaces 即 driving adapter(入站适配器),infrastructure 即 driven adapter(出站适配器),职责与禁止项对应不变。
81
+
82
+ ## CQRS 读写分离
83
+
84
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
85
+
86
+ Command(写)和 Query(读)走不同路径,互不混淆:
87
+
88
+ ```
89
+ Command 路径: Controller → ApplicationCommandService → Domain Model → Repository(写)
90
+ Query 路径: Controller → ApplicationQueryService → 直接查询投影(DB/DTO)
91
+ ```
92
+
93
+ - Command 走 domain 层:调用聚合根行为 → Repository 持久化
94
+ - Query 不走 domain 层:直接映射到查询投影(DTO),禁止加载 domain 实体再转换
95
+ - Command 方法返回 `void` 或 `CommandResult`(仅 ID/成功/失败),不返回 domain 实体
96
+ - Query 方法返回值必须是 DTO,禁止返回 Entity 或 PO
97
+ - 同一用例中禁止混用 Command 和 Query 逻辑——读方法不修改状态,写方法不返回查询结果
98
+
99
+ ```java
100
+ // 正确:Command
101
+ public class CreateOrderService {
102
+ private final OrderRepository repository;
103
+ private final EventPublisher eventPublisher;
104
+
105
+ public CommandResult execute(CreateOrderCommand cmd) {
106
+ Order order = repository.findById(OrderId.of(cmd.orderId()));
107
+ order.create(cmd.customer());
108
+ eventPublisher.publish(new OrderCreatedEvent(order.getId()));
109
+ return CommandResult.of(order.getId().value());
110
+ }
111
+ }
112
+
113
+ // 正确:Query
114
+ public class OrderListQueryService {
115
+ private final OrderListQueryDao dao; // 直接映射到投影,不走 domain
116
+
117
+ public List<OrderSummaryDto> execute(OrderListQuery query) {
118
+ return dao.findByStatus(query.status());
119
+ }
120
+ }
121
+ ```
122
+
123
+ ## 充血模型
124
+
125
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
126
+
127
+ Domain 实体必须是充血模型——行为封装在实体内部,禁止仅 getter/setter 的贫血模型。
128
+
129
+ ```java
130
+ // 正确:充血模型
131
+ public class Order {
132
+ private OrderId id;
133
+ private OrderStatus status;
134
+ private List<Invoice> invoices;
135
+
136
+ public Invoice addInvoice(Customer customer, BigDecimal amount) {
137
+ if (this.status != OrderStatus.PENDING) {
138
+ throw new IllegalStateException("订单未处理中,不可添加发票");
139
+ }
140
+ var invoice = new Invoice(customer, amount);
141
+ this.invoices.add(invoice);
142
+ return invoice;
143
+ }
144
+
145
+ public void create(Customer customer) {
146
+ if (this.status != OrderStatus.DRAFT) {
147
+ throw new IllegalStateException("草稿状态才能创建");
148
+ }
149
+ this.status = OrderStatus.PENDING;
150
+ }
151
+ }
152
+
153
+ // 错误:贫血模型
154
+ public class Order {
155
+ private Long id;
156
+ private String status;
157
+ public Long getId() { return id; }
158
+ public void setId(Long id) { this.id = id; }
159
+ public String getStatus() { return status; }
160
+ public void setStatus(String status) { this.status = status; }
161
+ }
162
+ ```
163
+
164
+ - 业务逻辑不得在 Service 中操作实体状态后再调用 save——改实体自身方法
165
+ - 判定:删掉所有 setter 后业务逻辑是否还能运转?能 → 充血;不能 → 贫血
166
+
167
+ ## 聚合设计
168
+
169
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
170
+
171
+ | 原则 | 说明 |
172
+ |------|------|
173
+ | 聚合边界 = 事务边界 | 一个事务只修改一个聚合,跨聚合用最终一致性 |
174
+ | 聚合根是唯一入口 | 外部只能通过聚合根方法访问聚合内部 |
175
+ | 跨聚合引用仅 ID | 聚合 A 引用聚合 B 时只存 `B.id`,不存 B 对象引用 |
176
+ | 聚合内一致性 | 聚合根负责子实体一致性校验,禁止外部直接修改子实体 |
177
+
178
+ ```java
179
+ // 聚合根 Order 引用子实体 Invoice,外部通过聚合根访问
180
+ public class Order {
181
+ private OrderId id;
182
+ private List<Invoice> invoices; // 子实体,聚合内
183
+
184
+ public Invoice addInvoice(Customer customer, BigDecimal amount) {
185
+ // 聚合根负责校验一致性
186
+ var invoice = new Invoice(customer, amount);
187
+ this.invoices.add(invoice);
188
+ return invoice;
189
+ }
190
+ }
191
+
192
+ // 跨聚合引用:只存 ID,不存对象
193
+ public class Order {
194
+ private OrderId id;
195
+ private String customerId; // 仅 ID 引用跨聚合
196
+ }
197
+ ```
198
+
199
+ ## Repository 领域语义
200
+
201
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
202
+
203
+ Repository 对 domain 层暴露集合语义,不暴露持久化语义:
204
+
205
+ ```java
206
+ // 正确:集合语义
207
+ public interface OrderRepository {
208
+ Order findById(OrderId id);
209
+ void add(Order order);
210
+ void remove(OrderId id);
211
+ }
212
+
213
+ // 错误:CRUD 语义
214
+ public interface OrderRepository {
215
+ OrderPO selectById(Long id);
216
+ int insert(OrderPO po);
217
+ int update(OrderPO po);
218
+ }
219
+ ```
220
+
221
+ - `findById` 返回 domain 实体,不返回 `Optional`(不存在则抛异常——领域层决定不存在语义)
222
+ - 查询方法名具领域语义:`findActiveOrdersByCustomerId`,非 `selectByCondition`
223
+ - 领域查询接口(`find*`)在 domain 层定义,具体实现(含 SQL)在 infrastructure 层
224
+ - 纯查询投影(非 domain 实体)走 CQRS Query 路径,不经过 Repository
225
+
226
+ ## Domain Event
227
+
228
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
229
+
230
+ 领域事件定义在 domain 层,事件处理在 infrastructure 层:
231
+
232
+ ```java
233
+ // domain/model/event/OrderCompletedEvent.java — record,不可变
234
+ public record OrderCompletedEvent(
235
+ OrderId orderId,
236
+ LocalDateTime completedAt
237
+ ) {}
238
+
239
+ // domain/service/EventPublisher.java — Port 接口,零框架依赖
240
+ public interface EventPublisher {
241
+ void publish(Object event);
242
+ }
243
+
244
+ // infrastructure/event/SpringEventPublisherAdapter.java
245
+ @Component
246
+ public class SpringEventPublisherAdapter implements EventPublisher {
247
+ private final ApplicationEventPublisher publisher;
248
+
249
+ public SpringEventPublisherAdapter(ApplicationEventPublisher publisher) {
250
+ this.publisher = publisher;
251
+ }
252
+
253
+ @Override
254
+ public void publish(Object event) {
255
+ publisher.publishEvent(event);
256
+ }
257
+ }
258
+ ```
259
+
260
+ - 命名规范:`{Entity}{PastParticiple}Event`(如 `OrderCompletedEvent`)
261
+ - 事件定义用 `record`,不可变,统一在 `domain/model/event` 包
262
+ - Application Service 在事务提交后调用 `eventPublisher.publish(event)`
263
+ - 事件处理类(Event Handler)在 infrastructure 层,使用 `@EventListener` 或消息队列
264
+
265
+ ## Factory
266
+
267
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
268
+
269
+ 复杂领域对象创建逻辑归 Factory,不放在构造函数中:
270
+
271
+ ```java
272
+ // domain/model/OrderFactory.java — 复杂初始化
273
+ public class OrderFactory {
274
+ public static Order createNew(CustomerRequest request, Customer customer) {
275
+ // 复杂初始化逻辑:校验、组装、生成 ID
276
+ var id = OrderId.generate();
277
+ var invoices = new ArrayList<Invoice>();
278
+ return new Order(id, customer, request, invoices);
279
+ }
280
+ }
281
+ ```
282
+
283
+ - 简单对象用静态工厂方法 `of(...)`:`OrderId.of("xxx")`
284
+ - 复杂组装用 Domain Factory(domain 层),不依赖外部技术
285
+ - 涉及外部数据/技术实现的创建用 Application Factory(application 层),调用 Port 获取数据后创建
286
+
287
+ ## Specification
288
+
289
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
290
+
291
+ Specification 将业务规则封装为可组合的谓词对象,用于判定候选对象是否满足特定条件:
292
+
293
+ ```java
294
+ // domain/model/spec/Specification.java
295
+ public interface Specification<T> {
296
+ boolean isSatisfiedBy(T candidate);
297
+
298
+ default Specification<T> and(Specification<T> other) {
299
+ return new AndSpecification<>(this, other);
300
+ }
301
+
302
+ default Specification<T> or(Specification<T> other) {
303
+ return new OrSpecification<>(this, other);
304
+ }
305
+
306
+ default Specification<T> not() {
307
+ return new NotSpecification<>(this);
308
+ }
309
+ }
310
+ ```
311
+
312
+ 组合实现:
313
+
314
+ ```java
315
+ // domain/model/spec/AndSpecification.java
316
+ public record AndSpecification<T>(Specification<T> left, Specification<T> right) implements Specification<T> {
317
+ @Override
318
+ public boolean isSatisfiedBy(T candidate) {
319
+ return left.isSatisfiedBy(candidate) && right.isSatisfiedBy(candidate);
320
+ }
321
+ }
322
+
323
+ // domain/model/spec/OrSpecification.java
324
+ public record OrSpecification<T>(Specification<T> left, Specification<T> right) implements Specification<T> {
325
+ @Override
326
+ public boolean isSatisfiedBy(T candidate) {
327
+ return left.isSatisfiedBy(candidate) || right.isSatisfiedBy(candidate);
328
+ }
329
+ }
330
+
331
+ // domain/model/spec/NotSpecification.java
332
+ public record NotSpecification<T>(Specification<T> target) implements Specification<T> {
333
+ @Override
334
+ public boolean isSatisfiedBy(T candidate) {
335
+ return !target.isSatisfiedBy(candidate);
336
+ }
337
+ }
338
+ ```
339
+
340
+ 使用场景:
341
+
342
+ - **领域层业务规则校验**:组合多个原子规则判定实体状态是否满足条件,避免 if-else 散落在 Service 中
343
+ - **Repository 查询过滤**:将 Specification 作为 Repository 查询参数,使查询条件可复用、可组合
344
+
345
+ ```java
346
+ // 原子规则实现
347
+ public class HighValueOrderSpec implements Specification<Order> {
348
+ private static final BigDecimal HIGH_VALUE_THRESHOLD = new BigDecimal("50000000");
349
+ @Override
350
+ public boolean isSatisfiedBy(Order order) {
351
+ return order.getTotalAmount().compareTo(HIGH_VALUE_THRESHOLD) >= 0;
352
+ }
353
+ }
354
+
355
+ public class OverdueOrderSpec implements Specification<Order> {
356
+ @Override
357
+ public boolean isSatisfiedBy(Order order) {
358
+ return order.hasOverdueItems();
359
+ }
360
+ }
361
+
362
+ // 组合规则 + Repository 查询
363
+ public class OrderService {
364
+ private final OrderRepository repository;
365
+
366
+ public List<Order> findHighRiskOrders() {
367
+ var highValue = new HighValueOrderSpec();
368
+ var overdue = new OverdueOrderSpec();
369
+ return repository.findSatisfying(highValue.or(overdue));
370
+ }
371
+ }
372
+ ```
373
+
374
+ - 原子规则类以 `Spec` 后缀命名,放在 `domain/model/spec` 包
375
+ - 组合通过接口默认方法链式调用,无需额外工厂
376
+ - 入参为领域实体或值对象,不在 Specification 中引入基础设施依赖
377
+
378
+ ## Anti-Corruption Layer
379
+
380
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
381
+
382
+ 防腐层(ACL)隔离外部模型与领域模型:
383
+
384
+ ```
385
+ infrastructure/acl/
386
+ ├── ExternalSearchClient.java ← 外部 API 调用
387
+ ├── ExternalResponseConverter.java ← 外部模型 → 领域模型转换
388
+ └── OrderExternalConverter.java ← 输出方向:领域模型 → 外部模型
389
+ ```
390
+
391
+ - ACL 位于 `infrastructure/acl` 包
392
+ - 输入方向:ACL 将外部模型(第三方 API、遗留系统、旧数据库)转换为领域模型
393
+ - 输出方向:ACL 将领域模型转换为外部模型
394
+ - 约束:领域模型不依赖外部模型,ACL 转换方向仅为 infrastructure → domain
395
+
396
+ 六边形视角下,ACL 属 driven adapter(出站适配器)中的转换组件,方向约束同"adapter → 内核"。
397
+
398
+ **正反对照——外部系统名不得上浮到内核与 interfaces 层**:
399
+
400
+ ```java
401
+ // 错误:application/interfaces 层出现外部系统名
402
+ public class SapCustomerService {
403
+ public SapCustomerResponse queryFromErp(String sapOrderNo) {
404
+ // 外部系统名进入接口/方法/DTO 命名
405
+ }
406
+ }
407
+
408
+ // 正确:内核侧接口/DTO 用领域语义命名
409
+ public interface SearchPort { // domain 定义的 Port,领域语义命名
410
+ SearchResultDto search(SearchQuery query);
411
+ }
412
+
413
+ // 正确:外部系统名仅出现在 infrastructure/acl 包(实现类、转换类)
414
+ public class SearchProviderClient { // infrastructure/acl 实现类
415
+ private final ExternalSearchClient externalSearchClient; // 外部 API 调用下沉在 acl 包内
416
+ }
417
+ ```
418
+
419
+ ## 核心规则
420
+
421
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
422
+
423
+ | # | 规则 | 违反后果 |
424
+ |---|------|---------|
425
+ | 1 | Domain 层零框架依赖(不 import Spring、MyBatis、Spring AI、infrastructure、interfaces 的任何类) | ArchUnit 编译/测试失败 |
426
+ | 2 | 依赖方向不可逆(infrastructure 不得依赖 interfaces) | 循环依赖、架构腐化 |
427
+ | 3 | Interface 层不直接依赖 Infrastructure 层 | 架构违规 |
428
+ | 4 | 依赖注入使用构造器注入,禁止 `@Autowired`/`@Resource` 字段注入 | 测试困难、隐式依赖 |
429
+ | 5 | 值对象使用 `final` 字段,无 setter | 可变状态 bug |
430
+ | 6 | 枚举类型统一在 Domain 层定义 | 层级混乱 |
431
+ | 7 | 每个包必须有 `package-info.java` | 包文档缺失 |
432
+ | 8 | Domain 实体为纯 POJO,不继承任何框架基类(如 MyBatisPlus 的 BaseEntity) | 破坏零框架依赖约束 |
433
+ | 9 | interfaces 层不直接暴露 domain 实体,须经 assembler 转为 DTO | 层级泄露、API 契约与内部模型耦合 |
434
+ | 10 | 领域异常类(BusinessException 及其子类、ErrorCode)统一放在 `domain/exception` 包 | 异常分散在各层导致循环依赖 |
435
+ | 11 | Command 方法禁止返回 domain 实体,应返回 `void` 或 `CommandResult` | 层间耦合、副作用隐患 |
436
+ | 12 | Query 方法禁止修改状态,返回值必须是 DTO 或投影,禁止返回 Entity/PO | 读写混淆、CQRS 失效 |
437
+ | 13 | 禁止贫血 domain 实体——实体须包含行为方法,setter 不得用于业务状态变更 | 领域逻辑散落在 Service 中 |
438
+ | 14 | 聚合根须维护聚合内一致性,禁止外部直接修改子实体属性 | 聚合边界失效、数据不一致 |
439
+ | 15 | 跨聚合仅通过 ID 引用,禁止持有其他聚合的对象引用 | 聚合边界模糊、事务扩散 |
440
+ | 16 | Repository 禁止向 domain 层暴露 PO 或持久化语义(save/update/delete) | 领域层泄漏技术细节 |
441
+ | 17 | Domain Event 在 domain 层定义(`domain/model/event`),infrastructure 层实现 handler | 领域层依赖事件框架 |
442
+ | 18 | ACL 只允许 infrastructure → domain 方向,领域模型不依赖外部模型 | 外部模型污染领域层 |
443
+ | 19 | 外部系统命名禁止上浮——application 接口方法、DTO 类名/字段名、interfaces 层 DTO 禁止出现外部系统名(第三方/遗留系统/中间件名),须用领域语义命名;外部系统名仅限 infrastructure(ACL/适配器/配置) | 接口契约污染、架构腐化 |
444
+ | 20 | 命名须体现语义并遵循统一语言——类/方法/字段命名与术语表一致,禁止泛化命名(如 process/handle/data)掩盖真实意图,禁止同名不同义造成混淆 | 可读性下降、概念混淆 |
445
+ | 21 | 禁止另起一套逻辑——同类能力已有既有实现时须复用或扩展,确需平行引入(新旧并存)时须附带既有实现的迁移方案 | 同类能力多套方案并存、技术债累积 |
446
+
447
+ **声明**:上表同时适用于四层与六边形两种风格。六边形风格下"domain"指内核(domain + application 合并语义),多数规则表述不变——规则 1(内核零框架依赖)、规则 2(依赖方向不可逆)、规则 3、规则 8、规则 9、规则 16、规则 18、规则 19、规则 20、规则 21 在两种风格下均一致。仅 Port 定义位置相关条目注明差异:规则 17 的领域事件契约仍在内核(domain/model/event)定义、事件 handler 实现仍在 infrastructure;Repository、EventPublisher、OrderGenerationPort 等 Port 接口在四层下固定定义于 domain,六边形下可为 domain(driven port)或 application(driving port),但全项目须一致。
448
+
449
+ ## Port / Adapter 模式
450
+
451
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
452
+
453
+ Port 接口是内核(domain + application)定义的纯业务契约,Adapter 是技术适配组件,按方向分两类。
454
+
455
+ **driven port / driven adapter(出站)**:port 由 domain 定义,adapter 在 infrastructure 实现。
456
+
457
+ \`\`\`java
458
+ // domain/service/OrderGenerationPort.java — driven port,零框架依赖
459
+ public interface OrderGenerationPort {
460
+ OrderInfo generate(OrderData data);
461
+ }
462
+
463
+ // infrastructure/llm/LlmOrderGenAdapter.java — driven adapter(出站)实现
464
+ @Component
465
+ public class LlmOrderGenAdapter implements OrderGenerationPort {
466
+ // 内部使用 Spring AI ChatModel
467
+ }
468
+ \`\`\`
469
+
470
+ **driving port / driving adapter(入站)**:port 由 application 定义,adapter 在 interfaces 实现。
471
+
472
+ \`\`\`java
473
+ // application/service/OrderService.java — driving port,用例入口
474
+ public interface OrderService {
475
+ CommandResult createOrder(CreateOrderCommand cmd);
476
+ }
477
+
478
+ // driving port 由 application 层应用服务实现(use case,同 CQRS 章节 CreateOrderService 模式),经 Spring 注入到 driving adapter
479
+
480
+ // interfaces/controller/OrderController.java — driving adapter(入站)调用端口
481
+ @RestController
482
+ public class OrderController {
483
+ private final OrderService orderService; // driving port,由 Spring 注入 application 层应用服务实现
484
+
485
+ public OrderController(OrderService orderService) {
486
+ this.orderService = orderService;
487
+ }
488
+
489
+ @PostMapping("/orders")
490
+ public CommandResult createOrder(@RequestBody CreateOrderCommand cmd) {
491
+ return orderService.createOrder(cmd);
492
+ }
493
+ }
494
+ \`\`\`
495
+
496
+ 四层分层下两类分别落在 interfaces 与 infrastructure;六边形下即 driving adapter 与 driven adapter。
497
+
498
+ ## 共性能力基础设施化
499
+
500
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
501
+
502
+ 应统一拦截/封装到 Infrastructure 层或框架级能力的横向逻辑,不得分散在各 Controller/Service 中逐点调用。
503
+
504
+ ### 适用场景
505
+
506
+ | 类别 | 示例 | 上收方式 |
507
+ |------|------|---------|
508
+ | 横切关注点 | 鉴权·审计·日志·限流·幂等·事务 | Filter / Interceptor / AOP(@Around/@Before/@After) |
509
+ | 共性策略约束(全局) | 文件类型·大小限制、权限规则、脱敏规则 | 先判是否全局(跨多接口/模块),若是 → 放入 Infrastructure 层统一 Filter 或 @ControllerAdvice;若是单模块 → 控制在 Application Service 门面 |
510
+ | 重复集成封装 | 外部 API 调用、序列化/转换、连接管理 | 公共 Client/Adapter 基类,一次封装全局复用 |
511
+ | 散落的全局配置 | 超时·重试·线程池·白名单 | 统一在 application.yml / @ConfigurationProperties 集中管理 |
512
+
513
+ ### 判据
514
+
515
+ 同一逻辑在 ≥2 处独立实现、属横向共性需求(非单点业务上下文特有)、新增场景漏调度即失效 → 必须基础设施化。
516
+
517
+ ## Spring DI
518
+
519
+ > 概念见 ddd-architecture,以下为 Java 实现示例。
520
+
521
+ \`\`\`java
522
+ // 正确:构造器注入
523
+ @RestController
524
+ public class OrderController {
525
+ private final OrderService orderService;
526
+ public OrderController(OrderService orderService) {
527
+ this.orderService = orderService;
528
+ }
529
+ }
530
+
531
+ // 错误:字段注入
532
+ @Autowired private OrderService orderService;
533
+ ```
@@ -0,0 +1,110 @@
1
+ ---
2
+ name: java-dev-practices
3
+ description: Java 开发实践规范——构建命令、代码质量工具、测试策略、提交规范、Spring Boot 配置、开发流程。不定义质量规则,质量规则由各质量维度 skill 覆盖。仅在 Java 后端项目使用。
4
+ capabilities: ["dev-practices", "tech-stack-java"]
5
+ ---
6
+
7
+ > **项目规范优先**:本 skill 所列约定为推荐标准。若项目已有明确规范且与本 skill 不一致,以项目规范为准。
8
+
9
+ ## 构建命令
10
+
11
+ ```bash
12
+ mvn verify # 全量验证(单次覆盖全部质量检查)
13
+ mvn spotless:apply # 自动格式化
14
+ mvn compile # 编译
15
+ mvn test # 运行测试
16
+ ```
17
+
18
+ - `mvn verify` 为全量验证命令,单次执行即覆盖编译、测试、spotless:check、pmd:check、JaCoCo 覆盖率。构建成败以 `mvn verify -q; echo "BUILD_STATUS=$?"` 的退出码为唯一判据,不依赖肉眼从输出尾部寻找 BUILD SUCCESS/FAILURE 行(`-q` 静默模式抑制 INFO 级 BUILD 行,输出过长时尾部亦不可靠)
19
+ - 确认结果时禁止重复执行同一构建命令,单次执行已覆盖全量质量检查;修复后复验属正常重跑
20
+ - 需要抽查输出细节时使用非 `-q` 形态 + `grep -E "Tests run|ERROR|jacoco|spotless|pmd"` 提取关键行,禁止仅以 `tail`/`head` 截断输出导致结论行丢失后重跑
21
+
22
+ ## 代码质量工具
23
+
24
+ **Spotless**(Palantir Java Format):
25
+ - 提交前执行 `mvn spotless:apply` 格式化,`mvn spotless:check` 必须通过
26
+ - 配置在 pom.xml `spotless-maven-plugin`
27
+
28
+ **PMD**:
29
+ - 规则集定义按项目级 pmd-rules.xml
30
+
31
+ **SonarLint**:IDE 建议安装 SonarLint 插件,尽量修复提示问题
32
+
33
+ ## 测试规范
34
+
35
+ **命名规范**:
36
+ - 测试类:`{ClassName}Test`(如 `OrderServiceTest`)
37
+ - 测试方法:`test{MethodName}`(如 `testCreateOrder`)
38
+
39
+ **分层策略**:
40
+ - Domain service 测试用纯 JUnit,零 Spring 依赖(domain 层本就无框架依赖)
41
+ - 优先切片测试 + `@Import` 组装所需 Bean,避免滥用全量 `@SpringBootTest`(启动慢、依赖环境)
42
+ - 仅跨多层集成测试时才用 `@SpringBootTest` + `@ActiveProfiles("test")`
43
+
44
+ **测试数据库**:
45
+ - 默认 H2 内存库(`MODE=PostgreSQL` 兼容模式)
46
+ - 配置见 `src/test/resources/application-test.yml`
47
+
48
+ **WireMock**:
49
+ - Stub 位置:`src/test/resources/mock/mappings/`
50
+ - 响应体位置:`__files/`
51
+ - 用于模拟外部 HTTP 服务
52
+
53
+ **ArchUnit**:
54
+ - 验收 Domain 层零框架依赖
55
+ - 验收层间依赖方向(interfaces → application → domain ← infrastructure)
56
+ - 依赖:`archunit-junit5`
57
+
58
+ **测试数据**:
59
+ - XLSX 测试文件 → `src/test/resources/`
60
+ - 配置文件 → `application-test.yml`
61
+
62
+ ## 提交规范
63
+
64
+ 使用 [Conventional Commits](https://www.conventionalcommits.org/):
65
+ ```
66
+ feat(domain): 新增 Xxx 值对象
67
+ fix(infra): 修复 N+1 查询问题
68
+ refactor(app): 重构 XxxService
69
+ test(domain): 补充 DomainRuleEngine 测试
70
+ docs: 更新 AGENTS.md
71
+ chore: 升级依赖版本
72
+ ```
73
+
74
+ 提交粒度:每个独立子任务至少一个 commit;修复审查反馈时 commit message 引用审查报告问题编号。
75
+
76
+ ## 新功能开发
77
+
78
+ - 编写单元测试覆盖全部验收条件,测试先行
79
+ - 实现代码使测试通过,保持最小实现
80
+ - 重构消除重复、改善可读性,测试须持续通过
81
+ - 通过代码质量检查(spotless:check + pmd:check)
82
+ - 完整测试套件通过
83
+
84
+ ## Bug 修复
85
+
86
+ - 从问题表象逐层追溯根因,基于事实定位系统性根因
87
+ - 修复方案针对根因而非表象
88
+ - 编写回归测试覆盖该场景
89
+
90
+ ## 调试
91
+
92
+ - 使用日志框架输出,禁止直接输出到标准输出
93
+ - 任务完成前清理所有仅为调试目的添加的日志
94
+ - 生产环境可用的日志使用 info 级别并标注业务含义
95
+
96
+ ## Spring Boot 启动与配置
97
+
98
+ **启动命令**:`mvn spring-boot:run` 或 `java -jar`
99
+
100
+ **健康检查**:`/actuator/health`(需引入 actuator starter)
101
+
102
+ **配置文件分层**:
103
+ - `application.yml` — 公共配置
104
+ - `application-dev.yml` — 开发环境
105
+ - `application-prod.yml` — 生产环境
106
+ - `application-test.yml` — 测试环境
107
+
108
+ **文件上传**:`spring.servlet.multipart.max-file-size: 20MB`,Controller 层须做文件类型白名单校验
109
+
110
+ **CORS**:开发环境允许前端跨域