@relipa/ai-flow-kit 0.0.5 → 0.0.6

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.
@@ -20,6 +20,27 @@ keywords: review, code review, approve, summary, checklist
20
20
  - ✅ `superpowers:verification-before-completion` has run — tests pass
21
21
  - ✅ `impact-analysis` skill has run
22
22
 
23
+ ## Mode Selection
24
+
25
+ Check `mode` in `.aiflow/context/current.json`:
26
+
27
+ | Mode | Impact Analysis | Review Checklist | summary.md |
28
+ |------|----------------|-----------------|-----------|
29
+ | `fast` | Quick scan — reason from diff only | 3 items | Short format |
30
+ | `full` | Full grep scan across codebase | 10 items | Full format |
31
+
32
+ ### Fast Track Impact Analysis (mode: fast)
33
+ Assess impact by reasoning about the changed files only:
34
+ 1. List each file you modified
35
+ 2. For each file: "Does this file have callers/dependents outside the ticket scope?"
36
+ 3. If yes → list them and assign impact level
37
+ 4. DO NOT run grep on the full codebase
38
+
39
+ ### Fast Track Review Checklist (mode: fast)
40
+ - [ ] All tests pass
41
+ - [ ] No hardcoded credentials or secrets
42
+ - [ ] No SQL injection risk in new queries
43
+
23
44
  ---
24
45
 
25
46
  ## Process
@@ -1,88 +1,88 @@
1
- ## MANDATORY: Strict Gate Workflow
2
-
3
- > **Absolute Rule: Complete Gate N before entering Gate N+1.**
4
- > **Do not skip, shorten, or merge Gates.**
5
-
6
- You have superpowers. When a ticket context exists in `.aiflow/context/current.json`:
7
- - **Consult the "AI Skill Registry"** below to find instructions for each skill (`SKILL.md`).
8
- - **AUTO-START Gate 1 immediately** — do NOT wait for the developer to ask.
9
- - Read instructions and follow the gate sequence below — NO EXCEPTIONS.
10
-
11
- ---
12
-
13
- ### GATE 1 — AI Analyze Requirement (auto-start)
14
-
15
- **INVOKE:** `read-study-requirement` skill
16
-
17
- AI actively reads ticket + source code to understand the requirement:
18
- 1. Read `.aiflow/context/current.json` — ticket info
19
- 2. Read source code — architecture, related files, data flow
20
- 3. If anything is unclear — ask ONE question at a time, wait for reply
21
- 4. Output `plan/[ticket-id]/requirement.md` with:
22
- - Requirements summary, source code analysis
23
- - Proposed solution and approach
24
- - Impact analysis, effort estimate, testing plan
25
- 5. Display "GATE 1: Requirement doc ready" → wait for **APPROVED**
26
-
27
- > **Tip:** If auto-start doesn't trigger, the developer can start this gate by typing: **"start"**, **"Gate 1"** or **"Analyze ticket"**.
28
-
29
- DO NOT just check format — **understand the content and propose solutions**.
30
-
31
- > **Telemetry:** Run `aiflow gate 1 start --ticket [ticket-id]` when starting this gate (auto-start or when developer types "start"/"Gate 1").
32
- > Run `aiflow gate 1 approved --ticket [ticket-id]` immediately when APPROVED is received.
33
-
34
- ---
35
-
36
- ### GATE 2 — Implementation Plan (wait for APPROVED)
37
-
38
- **INVOKE:** `generate-spec` skill, then `superpowers:writing-plans`
39
-
40
- - Create a detailed TDD implementation plan based on the approved requirement.
41
- - Display: "GATE 2 PAUSED: type APPROVED to start coding".
42
- - CODE WILL NOT BE GENERATED until "APPROVED" is received.
43
-
44
- > **Telemetry:** Run `aiflow gate 2 start --ticket [ticket-id]` when starting this gate.
45
- > Run `aiflow gate 2 approved --ticket [ticket-id]` immediately when APPROVED is received.
46
-
47
- ---
48
-
49
- ### GATE 3 — Code Generation (TDD only)
50
-
51
- Only runs after Gate 2 has been APPROVED.
52
-
53
- **INVOKE:** `superpowers:test-driven-development`
54
- - Complex feature (3+ files): `superpowers:subagent-driven-development`
55
- - Write tests FIRST — run to confirm FAIL -> implement -> PASS.
56
- - Bug fix EXTRA: `superpowers:systematic-debugging` + `investigate-bug` skill first.
57
-
58
- > **Telemetry:** Run `aiflow gate 3 start --ticket [ticket-id]` when starting this gate.
59
-
60
- ---
61
-
62
- ### GATE 4 — AI Self-Review (wait for APPROVED)
63
-
64
- **INVOKE:** `review-plan` skill
65
-
66
- Mandatory order:
67
- 1. `superpowers:verification-before-completion` — all tests must PASS
68
- 2. `impact-analysis` skill — check for breaking changes
69
- 3. Tick `custom/rules/review-checklist.md`
70
- 4. Create `plan/[ticket-id]/summary.md`
71
-
72
- Then: "GATE 4 PAUSED: type APPROVED or BUG: [description]"
73
- - Coding bug -> fix -> repeat Gate 4.
74
- - Requirement bug -> return to Gate 1.
75
-
76
- > **Telemetry:** Run `aiflow gate 4 start --ticket [ticket-id]` when starting this gate.
77
- > Run `aiflow gate 4 approved --ticket [ticket-id]` immediately when APPROVED is received.
78
-
79
- ---
80
-
81
- ### GATE 5 — Peer Review and Done
82
-
83
- Only runs after Gate 4 has been APPROVED.
84
-
85
- **INVOKE:** `superpowers:requesting-code-review`
86
- Guide on creating a Pull Request with the ticket link.
87
-
88
- > **Telemetry:** Run `aiflow gate 5 start --ticket [ticket-id]` when starting this gate.
1
+ ## MANDATORY: Strict Gate Workflow
2
+
3
+ > **Absolute Rule: Complete Gate N before entering Gate N+1.**
4
+ > **Do not skip, shorten, or merge Gates.**
5
+
6
+ You have superpowers. When a ticket context exists in `.aiflow/context/current.json`:
7
+ - **Consult the "AI Skill Registry"** below to find instructions for each skill (`SKILL.md`).
8
+ - **AUTO-START Gate 1 immediately** — do NOT wait for the developer to ask.
9
+ - Read instructions and follow the gate sequence below — NO EXCEPTIONS.
10
+
11
+ ---
12
+
13
+ ### GATE 1 — AI Analyze Requirement (auto-start)
14
+
15
+ **INVOKE:** `read-study-requirement` skill
16
+
17
+ AI actively reads ticket + source code to understand the requirement:
18
+ 1. Read `.aiflow/context/current.json` — ticket info
19
+ 2. Read source code — architecture, related files, data flow
20
+ 3. If anything is unclear — ask ONE question at a time, wait for reply
21
+ 4. Output `plan/[ticket-id]/requirement.md` with:
22
+ - Requirements summary, source code analysis
23
+ - Proposed solution and approach
24
+ - Impact analysis, effort estimate, testing plan
25
+ 5. Display "GATE 1: Requirement doc ready" → wait for **APPROVED**
26
+
27
+ > **Tip:** If auto-start doesn't trigger, the developer can start this gate by typing: **"start"**, **"Gate 1"** or **"Analyze ticket"**.
28
+
29
+ DO NOT just check format — **understand the content and propose solutions**.
30
+
31
+ > **Telemetry:** Run `aiflow gate 1 start --ticket [ticket-id]` when starting this gate (auto-start or when developer types "start"/"Gate 1").
32
+ > Run `aiflow gate 1 approved --ticket [ticket-id]` immediately when APPROVED is received.
33
+
34
+ ---
35
+
36
+ ### GATE 2 — Implementation Plan (wait for APPROVED)
37
+
38
+ **INVOKE:** `generate-spec` skill, then `superpowers:writing-plans`
39
+
40
+ - Create a detailed TDD implementation plan based on the approved requirement.
41
+ - Display: "GATE 2 PAUSED: type APPROVED to start coding".
42
+ - CODE WILL NOT BE GENERATED until "APPROVED" is received.
43
+
44
+ > **Telemetry:** Run `aiflow gate 2 start --ticket [ticket-id]` when starting this gate.
45
+ > Run `aiflow gate 2 approved --ticket [ticket-id]` immediately when APPROVED is received.
46
+
47
+ ---
48
+
49
+ ### GATE 3 — Code Generation (TDD only)
50
+
51
+ Only runs after Gate 2 has been APPROVED.
52
+
53
+ **INVOKE:** `superpowers:test-driven-development`
54
+ - Complex feature (3+ files): `superpowers:subagent-driven-development`
55
+ - Write tests FIRST — run to confirm FAIL -> implement -> PASS.
56
+ - Bug fix EXTRA: `superpowers:systematic-debugging` + `investigate-bug` skill first.
57
+
58
+ > **Telemetry:** Run `aiflow gate 3 start --ticket [ticket-id]` when starting this gate.
59
+
60
+ ---
61
+
62
+ ### GATE 4 — AI Self-Review (wait for APPROVED)
63
+
64
+ **INVOKE:** `review-plan` skill
65
+
66
+ Mandatory order:
67
+ 1. `superpowers:verification-before-completion` — all tests must PASS
68
+ 2. `impact-analysis` skill — check for breaking changes
69
+ 3. Tick `custom/rules/review-checklist.md`
70
+ 4. Create `plan/[ticket-id]/summary.md`
71
+
72
+ Then: "GATE 4 PAUSED: type APPROVED or BUG: [description]"
73
+ - Coding bug -> fix -> repeat Gate 4.
74
+ - Requirement bug -> return to Gate 1.
75
+
76
+ > **Telemetry:** Run `aiflow gate 4 start --ticket [ticket-id]` when starting this gate.
77
+ > Run `aiflow gate 4 approved --ticket [ticket-id]` immediately when APPROVED is received.
78
+
79
+ ---
80
+
81
+ ### GATE 5 — Peer Review and Done
82
+
83
+ Only runs after Gate 4 has been APPROVED.
84
+
85
+ **INVOKE:** `superpowers:requesting-code-review`
86
+ Guide on creating a Pull Request with the ticket link.
87
+
88
+ > **Telemetry:** Run `aiflow gate 5 start --ticket [ticket-id]` when starting this gate.
@@ -2,6 +2,8 @@
2
2
 
3
3
  You are an expert Java Spring Boot developer. Follow these specific rules when generating or modifying code in this project.
4
4
 
5
+ > **Code examples:** See `.rules/java/spring-boot-examples.md` — read it when generating code for a specific layer.
6
+
5
7
  ---
6
8
 
7
9
  ## Project Stack
@@ -63,25 +65,6 @@ com.company.project/
63
65
  - Use `ResponseEntity<T>` for explicit HTTP status control
64
66
  - Validate input with `\@Valid` + Bean Validation annotations
65
67
 
66
- ```java
67
- // ✅ Good
68
- \@PostMapping
69
- public ResponseEntity<UserResponse> createUser(
70
- \@Valid \@RequestBody CreateUserRequest request) {
71
- UserResponse response = userService.create(request);
72
- return ResponseEntity.status(HttpStatus.CREATED).body(response);
73
- }
74
-
75
- // ❌ Bad — business logic in controller
76
- \@PostMapping
77
- public ResponseEntity<User> createUser(\@RequestBody User user) {
78
- if (userRepository.existsByEmail(user.getEmail())) {
79
- throw new RuntimeException("Email exists");
80
- }
81
- return ResponseEntity.ok(userRepository.save(user));
82
- }
83
- ```
84
-
85
68
  ---
86
69
 
87
70
  ## Service Rules
@@ -93,59 +76,16 @@ public ResponseEntity<User> createUser(\@RequestBody User user) {
93
76
  - Throw specific custom exceptions, not generic `RuntimeException`
94
77
  - Never return an Entity — always convert to DTO via Mapper
95
78
 
96
- ```java
97
- // ✅ Good
98
- public interface UserService {
99
- UserResponse create(CreateUserRequest request);
100
- UserResponse findById(Long id);
101
- }
102
-
103
- \@Service
104
- \@RequiredArgsConstructor
105
- public class UserServiceImpl implements UserService {
106
-
107
- private final UserRepository userRepository;
108
- private final UserMapper userMapper;
109
-
110
- \@Override
111
- \@Transactional
112
- public UserResponse create(CreateUserRequest request) {
113
- if (userRepository.existsByEmail(request.getEmail())) {
114
- throw new DuplicateEmailException(request.getEmail());
115
- }
116
- User user = userMapper.toEntity(request);
117
- User saved = userRepository.save(user);
118
- return userMapper.toResponse(saved);
119
- }
120
- }
121
- ```
122
-
123
79
  ---
124
80
 
125
81
  ## Repository Rules
126
82
 
127
- - Extend `JpaRepository<Entity, ID>` or `JpaRepository` with Specification
83
+ - Extend `JpaRepository<Entity, ID>`
128
84
  - Use **method name queries** for simple queries
129
85
  - Use `\@Query` (JPQL) for complex queries — avoid native SQL unless necessary
130
86
  - Never add business logic here
131
87
  - Use `\@EntityGraph` to solve N+1 problems
132
88
 
133
- ```java
134
- // ✅ Good
135
- public interface UserRepository extends JpaRepository<User, Long> {
136
-
137
- boolean existsByEmail(String email);
138
-
139
- Optional<User> findByEmailAndDeletedFalse(String email);
140
-
141
- \@Query("SELECT u FROM User u JOIN FETCH u.roles WHERE u.id = :id")
142
- Optional<User> findByIdWithRoles(\@Param("id") Long id);
143
- }
144
-
145
- // ❌ Bad — N+1 problem
146
- List<Order> findAll(); // If Order has \@ManyToOne User, this causes N+1
147
- ```
148
-
149
89
  ---
150
90
 
151
91
  ## Entity Rules
@@ -157,36 +97,6 @@ List<Order> findAll(); // If Order has \@ManyToOne User, this causes N+1
157
97
  - For soft delete: add `deleted` boolean + `deletedAt` timestamp
158
98
  - Extend `BaseEntity` for audit fields (`createdAt`, `updatedAt`)
159
99
 
160
- ```java
161
- // ✅ Good
162
- \@Entity
163
- \@Table(name = "users")
164
- \@Getter
165
- \@Setter
166
- \@NoArgsConstructor
167
- \@AllArgsConstructor
168
- \@Builder
169
- public class User extends BaseEntity {
170
-
171
- \@Id
172
- \@GeneratedValue(strategy = GenerationType.IDENTITY)
173
- private Long id;
174
-
175
- \@Column(name = "email", nullable = false, unique = true, length = 255)
176
- private String email;
177
-
178
- \@Column(name = "full_name", nullable = false, length = 100)
179
- private String fullName;
180
-
181
- \@Column(name = "deleted", nullable = false)
182
- \@Builder.Default
183
- private boolean deleted = false;
184
-
185
- \@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
186
- private List<Order> orders = new ArrayList<>();
187
- }
188
- ```
189
-
190
100
  ---
191
101
 
192
102
  ## DTO Rules
@@ -196,40 +106,6 @@ public class User extends BaseEntity {
196
106
  - Validate in the Request DTO with Bean Validation (`\@NotBlank`, `\@Email`, `\@NotNull`, `\@Size`)
197
107
  - Never expose internal fields (password hash, audit timestamps) in the Response DTO
198
108
 
199
- ```java
200
- // Request DTO
201
- \@Getter
202
- \@NoArgsConstructor
203
- \@AllArgsConstructor
204
- \@Builder
205
- public class CreateUserRequest {
206
-
207
- \@NotBlank(message = "Email is required")
208
- \@Email(message = "Invalid email format")
209
- private String email;
210
-
211
- \@NotBlank(message = "Full name is required")
212
- \@Size(min = 2, max = 100, message = "Full name must be 2-100 characters")
213
- private String fullName;
214
-
215
- \@NotBlank(message = "Password is required")
216
- \@Size(min = 8, message = "Password must be at least 8 characters")
217
- private String password;
218
- }
219
-
220
- // Response DTO
221
- \@Getter
222
- \@NoArgsConstructor
223
- \@AllArgsConstructor
224
- \@Builder
225
- public class UserResponse {
226
- private Long id;
227
- private String email;
228
- private String fullName;
229
- private LocalDateTime createdAt;
230
- }
231
- ```
232
-
233
109
  ---
234
110
 
235
111
  ## MapStruct Mapper Rules
@@ -238,23 +114,6 @@ public class UserResponse {
238
114
  - Define explicit mappings with `\@Mapping` when field names differ
239
115
  - Never do manual mapping (`new DTO(); dto.setField(entity.getField())`)
240
116
 
241
- ```java
242
- \@Mapper(componentModel = "spring")
243
- public interface UserMapper {
244
-
245
- \@Mapping(target = "createdAt", source = "createdAt")
246
- UserResponse toResponse(User user);
247
-
248
- \@Mapping(target = "id", ignore = true)
249
- \@Mapping(target = "deleted", ignore = true)
250
- \@Mapping(target = "createdAt", ignore = true)
251
- \@Mapping(target = "updatedAt", ignore = true)
252
- User toEntity(CreateUserRequest request);
253
-
254
- List<UserResponse> toResponseList(List<User> users);
255
- }
256
- ```
257
-
258
117
  ---
259
118
 
260
119
  ## Exception Handling
@@ -264,46 +123,6 @@ public interface UserMapper {
264
123
  - Return a consistent error response format
265
124
  - Never expose stack traces to the client
266
125
 
267
- ```java
268
- // Custom exception
269
- public class ResourceNotFoundException extends RuntimeException {
270
- public ResourceNotFoundException(String resource, Long id) {
271
- super(String.format("%s with id %d not found", resource, id));
272
- }
273
- }
274
-
275
- // Global handler
276
- \@RestControllerAdvice
277
- \@Slf4j
278
- public class GlobalExceptionHandler {
279
-
280
- \@ExceptionHandler(ResourceNotFoundException.class)
281
- public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
282
- log.warn("Resource not found: {}", ex.getMessage());
283
- return ResponseEntity.status(HttpStatus.NOT_FOUND)
284
- .body(ErrorResponse.of("NOT_FOUND", ex.getMessage()));
285
- }
286
-
287
- \@ExceptionHandler(MethodArgumentNotValidException.class)
288
- public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException ex) {
289
- List<String> errors = ex.getBindingResult()
290
- .getFieldErrors()
291
- .stream()
292
- .map(e -> e.getField() + ": " + e.getDefaultMessage())
293
- .toList();
294
- return ResponseEntity.status(HttpStatus.BAD_REQUEST)
295
- .body(ErrorResponse.of("VALIDATION_FAILED", errors.toString()));
296
- }
297
-
298
- \@ExceptionHandler(Exception.class)
299
- public ResponseEntity<ErrorResponse> handleGeneral(Exception ex) {
300
- log.error("Unexpected error", ex);
301
- return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
302
- .body(ErrorResponse.of("INTERNAL_ERROR", "An unexpected error occurred"));
303
- }
304
- }
305
- ```
306
-
307
126
  ---
308
127
 
309
128
  ## Testing Rules
@@ -314,104 +133,11 @@ public class GlobalExceptionHandler {
314
133
  - Test happy path + edge cases + exception scenarios
315
134
  - Use AssertJ: `assertThat(result).isEqualTo(expected)`
316
135
 
317
- ```java
318
- \@ExtendWith(MockitoExtension.class)
319
- class UserServiceImplTest {
320
-
321
- \@Mock
322
- private UserRepository userRepository;
323
-
324
- \@Mock
325
- private UserMapper userMapper;
326
-
327
- \@InjectMocks
328
- private UserServiceImpl userService;
329
-
330
- \@Test
331
- void create_shouldReturnUserResponse_whenEmailIsUnique() {
332
- // Arrange
333
- CreateUserRequest request = CreateUserRequest.builder()
334
- .email("test\@example.com")
335
- .fullName("Test User")
336
- .build();
337
- User user = User.builder().id(1L).email("test\@example.com").build();
338
- UserResponse expected = UserResponse.builder().id(1L).build();
339
-
340
- given(userRepository.existsByEmail(request.getEmail())).willReturn(false);
341
- given(userMapper.toEntity(request)).willReturn(user);
342
- given(userRepository.save(user)).willReturn(user);
343
- given(userMapper.toResponse(user)).willReturn(expected);
344
-
345
- // Act
346
- UserResponse result = userService.create(request);
347
-
348
- // Assert
349
- assertThat(result).isEqualTo(expected);
350
- verify(userRepository).save(user);
351
- }
352
-
353
- \@Test
354
- void create_shouldThrowDuplicateEmailException_whenEmailAlreadyExists() {
355
- CreateUserRequest request = CreateUserRequest.builder()
356
- .email("existing\@example.com").build();
357
- given(userRepository.existsByEmail(request.getEmail())).willReturn(true);
358
-
359
- assertThatThrownBy(() -> userService.create(request))
360
- .isInstanceOf(DuplicateEmailException.class);
361
- verify(userRepository, never()).save(any());
362
- }
363
- }
364
- ```
365
-
366
136
  ### Integration Tests (Controller layer)
367
137
  - Use `\@SpringBootTest` + `\@AutoConfigureMockMvc`
368
138
  - Test full HTTP flow with `MockMvc`
369
139
  - Use `\@Sql` or Testcontainers for database state
370
140
 
371
- ```java
372
- \@SpringBootTest
373
- \@AutoConfigureMockMvc
374
- class UserControllerIntegrationTest {
375
-
376
- \@Autowired
377
- private MockMvc mockMvc;
378
-
379
- \@Autowired
380
- private ObjectMapper objectMapper;
381
-
382
- \@Test
383
- void createUser_shouldReturn201_whenRequestIsValid() throws Exception {
384
- CreateUserRequest request = CreateUserRequest.builder()
385
- .email("test\@example.com")
386
- .fullName("Test User")
387
- .password("password123")
388
- .build();
389
-
390
- mockMvc.perform(post("/api/v1/users")
391
- .contentType(MediaType.APPLICATION_JSON)
392
- .content(objectMapper.writeValueAsString(request)))
393
- .andExpect(status().isCreated())
394
- .andExpect(jsonPath("$.email").value("test\@example.com"))
395
- .andExpect(jsonPath("$.id").isNumber());
396
- }
397
-
398
- \@Test
399
- void createUser_shouldReturn400_whenEmailIsInvalid() throws Exception {
400
- CreateUserRequest request = CreateUserRequest.builder()
401
- .email("not-an-email")
402
- .fullName("Test")
403
- .password("password123")
404
- .build();
405
-
406
- mockMvc.perform(post("/api/v1/users")
407
- .contentType(MediaType.APPLICATION_JSON)
408
- .content(objectMapper.writeValueAsString(request)))
409
- .andExpect(status().isBadRequest())
410
- .andExpect(jsonPath("$.code").value("VALIDATION_FAILED"));
411
- }
412
- }
413
- ```
414
-
415
141
  ---
416
142
 
417
143
  ## Naming Conventions
@@ -458,14 +184,6 @@ GET /api/v1/users/{id}/orders → 200 nested resource
458
184
  - Use `\@Transactional(readOnly = true)` on read-only service methods
459
185
  - For heavy read operations, consider projection interfaces
460
186
 
461
- ```java
462
- // ✅ Read-only transaction
463
- \@Transactional(readOnly = true)
464
- public Page<UserResponse> findAll(Pageable pageable) {
465
- return userRepository.findAll(pageable).map(userMapper::toResponse);
466
- }
467
- ```
468
-
469
187
  ---
470
188
 
471
189
  ## Security Rules
@@ -487,23 +205,6 @@ public Page<UserResponse> findAll(Pageable pageable) {
487
205
  - `log.error` — unexpected exceptions (always include `ex` as the second argument)
488
206
  - Never log sensitive data (password, credit card, token)
489
207
 
490
- ```java
491
- \@Slf4j
492
- \@Service
493
- public class UserServiceImpl implements UserService {
494
-
495
- public UserResponse findById(Long id) {
496
- log.info("Finding user by id: {}", id);
497
- return userRepository.findById(id)
498
- .map(userMapper::toResponse)
499
- .orElseThrow(() -> {
500
- log.warn("User not found: id={}", id);
501
- return new ResourceNotFoundException("User", id);
502
- });
503
- }
504
- }
505
- ```
506
-
507
208
  ---
508
209
 
509
210
  ## Common Anti-Patterns to Avoid