@eltonssouza/development-utility-kit 1.0.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.
- package/.claude/agents/analyst.md +198 -0
- package/.claude/agents/backend-developer.md +126 -0
- package/.claude/agents/brain-keeper.md +229 -0
- package/.claude/agents/code-reviewer.md +181 -0
- package/.claude/agents/database-engineer.md +94 -0
- package/.claude/agents/devops-engineer.md +141 -0
- package/.claude/agents/frontend-developer.md +97 -0
- package/.claude/agents/gate-keeper.md +118 -0
- package/.claude/agents/migrator.md +291 -0
- package/.claude/agents/mobile-developer.md +80 -0
- package/.claude/agents/n8n-specialist.md +94 -0
- package/.claude/agents/product-owner.md +115 -0
- package/.claude/agents/qa-engineer.md +232 -0
- package/.claude/agents/release-engineer.md +204 -0
- package/.claude/agents/scaffold.md +87 -0
- package/.claude/agents/security-engineer.md +199 -0
- package/.claude/agents/sprint-runner.md +44 -0
- package/.claude/agents/stack-resolver.md +84 -0
- package/.claude/agents/tech-lead.md +182 -0
- package/.claude/agents/update-template.md +54 -0
- package/.claude/agents/ux-designer.md +118 -0
- package/.claude/settings.json +44 -0
- package/.claude/skills/README.md +332 -0
- package/.claude/skills/active-project/SKILL.md +129 -0
- package/.claude/skills/api-integration-test/SKILL.md +64 -0
- package/.claude/skills/auto-test-guard/SKILL.md +237 -0
- package/.claude/skills/auto-test-guard/resources/backend-tests.md +20 -0
- package/.claude/skills/auto-test-guard/resources/e2e-tests.md +24 -0
- package/.claude/skills/auto-test-guard/resources/execution-report.md +49 -0
- package/.claude/skills/auto-test-guard/resources/frontend-tests.md +18 -0
- package/.claude/skills/auto-test-guard/resources/initial-setup.md +108 -0
- package/.claude/skills/auto-test-guard/resources/run-suite.md +48 -0
- package/.claude/skills/auto-test-guard/resources/senior-gate.md +19 -0
- package/.claude/skills/brain-keeper/SKILL.md +60 -0
- package/.claude/skills/brain-keeper/obsidian/app.json +9 -0
- package/.claude/skills/brain-keeper/obsidian/appearance.json +4 -0
- package/.claude/skills/brain-keeper/obsidian/core-plugins.json +20 -0
- package/.claude/skills/brain-keeper/obsidian/daily-notes.json +5 -0
- package/.claude/skills/brain-keeper/obsidian/graph.json +32 -0
- package/.claude/skills/brain-keeper/obsidian/snippets/folder-colors.css +90 -0
- package/.claude/skills/brain-keeper/obsidian/templates.json +5 -0
- package/.claude/skills/brain-keeper/templates/README.md +51 -0
- package/.claude/skills/brain-keeper/templates/adr.md +40 -0
- package/.claude/skills/brain-keeper/templates/bug.md +35 -0
- package/.claude/skills/brain-keeper/templates/daily.md +38 -0
- package/.claude/skills/brain-keeper/templates/feature.md +62 -0
- package/.claude/skills/brain-keeper/templates/meeting.md +34 -0
- package/.claude/skills/brain-keeper/templates/tech-debt.md +21 -0
- package/.claude/skills/caveman/SKILL.md +187 -0
- package/.claude/skills/create-stack-pack/SKILL.md +281 -0
- package/.claude/skills/grill-me/SKILL.md +79 -0
- package/.claude/skills/honcho-memory/SKILL.md +207 -0
- package/.claude/skills/honcho-memory/docs/api-endpoints-verified.md +75 -0
- package/.claude/skills/honcho-memory/hooks/on-prompt-submit.js +221 -0
- package/.claude/skills/honcho-memory/hooks/on-stop.js +193 -0
- package/.claude/skills/honcho-memory/lib/honcho-client.js +363 -0
- package/.claude/skills/honcho-memory/lib/memory-injector.js +93 -0
- package/.claude/skills/honcho-memory/package.json +32 -0
- package/.claude/skills/honcho-memory/scripts/cli.js +370 -0
- package/.claude/skills/honcho-memory/scripts/setup.js +109 -0
- package/.claude/skills/honcho-memory/tests/t001-api-endpoints-verified.test.js +89 -0
- package/.claude/skills/honcho-memory/tests/t002-structure.test.js +97 -0
- package/.claude/skills/honcho-memory/tests/t003-honcho-client.test.js +162 -0
- package/.claude/skills/honcho-memory/tests/t004-soft-delete.test.js +259 -0
- package/.claude/skills/honcho-memory/tests/t005-memory-injector.test.js +175 -0
- package/.claude/skills/honcho-memory/tests/t006-on-prompt-submit.test.js +215 -0
- package/.claude/skills/honcho-memory/tests/t007-on-stop.test.js +165 -0
- package/.claude/skills/honcho-memory/tests/t008-cli.test.js +214 -0
- package/.claude/skills/honcho-memory/tests/t009-setup.test.js +232 -0
- package/.claude/skills/honcho-memory/tests/t010-skill-md.test.js +114 -0
- package/.claude/skills/honcho-memory/tests/t011-settings-hooks.test.js +105 -0
- package/.claude/skills/honcho-memory/tests/t012-docs-update.test.js +106 -0
- package/.claude/skills/honcho-memory/tests/t013-smoke-e2e.test.js +90 -0
- package/.claude/skills/pair-debug/SKILL.md +288 -0
- package/.claude/skills/prd-ready-check/SKILL.md +58 -0
- package/.claude/skills/project-manager/SKILL.md +167 -0
- package/.claude/skills/quality-standards/SKILL.md +201 -0
- package/.claude/skills/quick-feature/SKILL.md +264 -0
- package/.claude/skills/run-sprint/SKILL.md +342 -0
- package/.claude/skills/scaffold/SKILL.md +58 -0
- package/.claude/skills/stack-discovery/SKILL.md +159 -0
- package/.claude/skills/test-coverage-auditor/SKILL.md +59 -0
- package/.claude/skills/to-issues/SKILL.md +163 -0
- package/.claude/skills/to-prd/SKILL.md +130 -0
- package/.claude/skills/update-template/SKILL.md +254 -0
- package/.claude/stacks/CODEOWNERS +30 -0
- package/.claude/stacks/README.md +88 -0
- package/.claude/stacks/_template.md +116 -0
- package/.claude/stacks/java/spring-boot-3.md +376 -0
- package/.claude/stacks/java/spring-boot-4.md +438 -0
- package/.claude/stacks/typescript/angular-18.md +420 -0
- package/.claude/stacks/typescript/angular-19.md +397 -0
- package/.claude/stacks/typescript/angular-21.md +494 -0
- package/CLAUDE.md +453 -0
- package/README.md +391 -0
- package/bin/cli.js +773 -0
- package/bin/lib/backup.js +62 -0
- package/bin/lib/detect-stack.js +476 -0
- package/bin/lib/help.js +233 -0
- package/bin/lib/identity.js +108 -0
- package/bin/lib/local-dir.js +69 -0
- package/bin/lib/manifest.js +236 -0
- package/bin/lib/sync-all.js +394 -0
- package/bin/lib/version-check.js +398 -0
- package/dashboard/db.js +199 -0
- package/dashboard/package.json +22 -0
- package/dashboard/public/app.js +709 -0
- package/dashboard/public/content/docs/agents-reference.en.md +911 -0
- package/dashboard/public/content/docs/architecture-overview.en.md +260 -0
- package/dashboard/public/content/docs/autonomy-matrix.en.md +186 -0
- package/dashboard/public/content/docs/git-flow.en.md +525 -0
- package/dashboard/public/content/docs/honcho-memory.en.md +394 -0
- package/dashboard/public/content/docs/hooks-reference.en.md +420 -0
- package/dashboard/public/content/docs/pipeline.en.md +400 -0
- package/dashboard/public/content/docs/quality-gate.en.md +315 -0
- package/dashboard/public/content/docs/skills-reference.en.md +500 -0
- package/dashboard/public/content/docs/stack-rules.en.md +362 -0
- package/dashboard/public/content/docs/troubleshooting.en.md +637 -0
- package/dashboard/public/content/manifest.json +102 -0
- package/dashboard/public/content/manual/backend.en.md +1138 -0
- package/dashboard/public/content/manual/existing-project.en.md +831 -0
- package/dashboard/public/content/manual/frontend.en.md +1065 -0
- package/dashboard/public/content/manual/fullstack.en.md +1508 -0
- package/dashboard/public/content/manual/mobile.en.md +866 -0
- package/dashboard/public/index.html +108 -0
- package/dashboard/public/style.css +610 -0
- package/dashboard/public/vendor/marked.min.js +69 -0
- package/dashboard/rtk.js +143 -0
- package/dashboard/server-app.js +403 -0
- package/dashboard/server.js +104 -0
- package/dashboard/test/sprint1.test.js +406 -0
- package/dashboard/test/sprint2.test.js +571 -0
- package/dashboard/test/sprint3.test.js +560 -0
- package/package.json +33 -0
- package/scripts/hooks/subagent-telemetry.sh +14 -0
- package/scripts/hooks/telemetry-writer.js +250 -0
- package/scripts/latest-versions.json +56 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
stack: <lang>/<framework> # e.g. java/spring-boot-3, python/django, go/gin
|
|
3
|
+
versions_covered: "<range>" # e.g. "3.0.x — 3.4.x", "5.0.x — 5.1.x"
|
|
4
|
+
last_validated: <YYYY-MM-DD> # date of last validation in real project
|
|
5
|
+
validated_against: "<description>" # e.g. "projeto-x v1.2 (Java 21 + SB 3.2.5)"
|
|
6
|
+
status: active # active | deprecated | archived
|
|
7
|
+
pack_owner: "@<github-handle>" # e.g. "@elton"
|
|
8
|
+
security_review: <YYYY-MM-DD> # date of last security-focused review
|
|
9
|
+
next_review_due: <YYYY-MM-DD> # security_review + 12 months
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# <Stack name + version>
|
|
13
|
+
|
|
14
|
+
<Intro 1-3 lines: what this pack covers, when to use it vs alternative pack/version.>
|
|
15
|
+
|
|
16
|
+
## 1. When to use this pack
|
|
17
|
+
|
|
18
|
+
- Project declares `Primary stack: <X>` in `## Project Identity`.
|
|
19
|
+
- Build manifest (`pom.xml` / `package.json` / `pyproject.toml` / `go.mod` / etc.) declares versions within `versions_covered`.
|
|
20
|
+
- (Optional) Greenfield/legacy guidance — when to prefer next-major pack instead.
|
|
21
|
+
|
|
22
|
+
## 2. Stack baseline (what this pack assumes)
|
|
23
|
+
|
|
24
|
+
| Component | Version range | Notes |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| <language> | <range> | <notes — LTS, EOL dates> |
|
|
27
|
+
| <framework> | <range> | <key feature for this major> |
|
|
28
|
+
| <build tool> | <range> | <Maven Wrapper, npm, etc.> |
|
|
29
|
+
| <test framework> | <range> | <what to avoid — e.g. never H2 as Postgres> |
|
|
30
|
+
| <observability> | <stack> | <Micrometer, OpenTelemetry, etc.> |
|
|
31
|
+
|
|
32
|
+
## 3. Project structure
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
<tree of canonical folder layout for this stack>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 4. Code patterns
|
|
39
|
+
|
|
40
|
+
### <Pattern name 1 — e.g. DTOs>
|
|
41
|
+
<Real compilable snippet showing the canonical pattern + 1-line rule.>
|
|
42
|
+
|
|
43
|
+
### <Pattern name 2 — e.g. Error handling>
|
|
44
|
+
<Snippet + rule.>
|
|
45
|
+
|
|
46
|
+
### <Pattern name 3, 4, 5...>
|
|
47
|
+
|
|
48
|
+
## 5. Testing
|
|
49
|
+
|
|
50
|
+
### Unit
|
|
51
|
+
<Snippet + framework versions + rules.>
|
|
52
|
+
|
|
53
|
+
### Integration
|
|
54
|
+
<Snippet — REAL test pattern, not pseudocode.>
|
|
55
|
+
|
|
56
|
+
### <Other test types if relevant — slice, contract, mutation, e2e>
|
|
57
|
+
|
|
58
|
+
## 6. Build & run commands
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
<exact commands a dev would run — build, test, run, lint, coverage>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 7. Security (per ADR-007 + ADR-027 — MANDATORY section)
|
|
65
|
+
|
|
66
|
+
### 7.1 Authentication & Authorization
|
|
67
|
+
<Stack-specific auth: framework class names, hashing, MFA hooks>
|
|
68
|
+
|
|
69
|
+
### 7.2 CORS
|
|
70
|
+
<Snippet — never `*` in prod>
|
|
71
|
+
|
|
72
|
+
### 7.3 Validation & input sanitization
|
|
73
|
+
<SQL injection, XSS, path traversal — stack-specific mitigation>
|
|
74
|
+
|
|
75
|
+
### 7.4 Secrets management
|
|
76
|
+
<Env vars, vault, never in committed files>
|
|
77
|
+
|
|
78
|
+
### 7.5 Rate limiting
|
|
79
|
+
<Library + config snippet for public endpoints>
|
|
80
|
+
|
|
81
|
+
### 7.6 OWASP Top 10 mapping
|
|
82
|
+
|
|
83
|
+
| OWASP | Mitigation in this stack |
|
|
84
|
+
|---|---|
|
|
85
|
+
| A01 Broken Access Control | <stack-specific> |
|
|
86
|
+
| A02 Cryptographic Failures | <stack-specific> |
|
|
87
|
+
| A03 Injection | <stack-specific> |
|
|
88
|
+
| A04 Insecure Design | <stack-specific> |
|
|
89
|
+
| A05 Security Misconfiguration | <stack-specific> |
|
|
90
|
+
| A06 Vulnerable Components | <CVE scanner + Renovate/Dependabot> |
|
|
91
|
+
| A07 Auth Failures | <rate limit + account lock + MFA> |
|
|
92
|
+
| A08 Data Integrity | <signature verification, supply chain, SBOM> |
|
|
93
|
+
| A09 Logging Failures | <structured logs + correlation ID + no PII> |
|
|
94
|
+
| A10 SSRF | <allowlist for outbound, validate URLs> |
|
|
95
|
+
|
|
96
|
+
### 7.7 LGPD / GDPR / compliance specifics (if applicable)
|
|
97
|
+
<PII tagging, soft-delete, data subject access, encryption at rest>
|
|
98
|
+
|
|
99
|
+
## 8. Anti-patterns (block in code-review)
|
|
100
|
+
|
|
101
|
+
| ❌ Bad | ✅ Good | Why |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| <bad pattern> | <good replacement> | <reason> |
|
|
104
|
+
| ... | ... | ... |
|
|
105
|
+
|
|
106
|
+
## 9. Migration hints — <this version> → <next major>
|
|
107
|
+
|
|
108
|
+
<Short list of breaking changes when migrating. Points to `migrator` agent.>
|
|
109
|
+
|
|
110
|
+
## 10. References
|
|
111
|
+
|
|
112
|
+
- ADR-007 (Senior+ gate thresholds)
|
|
113
|
+
- ADR-026 (Generic agents + packs architecture)
|
|
114
|
+
- ADR-027 (Pack governance)
|
|
115
|
+
- <Official framework migration guide URLs>
|
|
116
|
+
- <OWASP / compliance references>
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
---
|
|
2
|
+
stack: java/spring-boot-3
|
|
3
|
+
versions_covered: "3.0.x — 3.4.x"
|
|
4
|
+
last_validated: 2026-05-27
|
|
5
|
+
validated_against: "sandbox — Java 21 LTS + Spring Boot 3.2.5"
|
|
6
|
+
status: active
|
|
7
|
+
pack_owner: "@elton"
|
|
8
|
+
security_review: 2026-05-27
|
|
9
|
+
next_review_due: 2027-05-27
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Java 17/21 + Spring Boot 3.x
|
|
13
|
+
|
|
14
|
+
Knowledge pack for projects on Java 17 (minimum) or Java 21 LTS + Spring Boot 3.x. Covers projects in production that have not yet migrated to Java 25 + Spring Boot 4 (covered by `spring-boot-4.md`).
|
|
15
|
+
|
|
16
|
+
## 1. When to use this pack
|
|
17
|
+
|
|
18
|
+
- Project declares `Primary stack: Java 17 + Spring Boot 3.x` or `Java 21 + Spring Boot 3.x` in `## Project Identity`.
|
|
19
|
+
- `pom.xml` declares `<java.version>17|21</java.version>` and `<spring-boot.version>3.0.x — 3.4.x</spring-boot.version>`.
|
|
20
|
+
- Greenfield: prefer `spring-boot-4.md` (Java 25 + SB 4). This pack is for **maintained legacy**.
|
|
21
|
+
|
|
22
|
+
## 2. Stack baseline (what this pack assumes)
|
|
23
|
+
|
|
24
|
+
| Component | Version range | Notes |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| Java | 17 (min) / 21 (LTS preferred) | Java 17 ELS until 2029; 21 LTS until 2031 |
|
|
27
|
+
| Spring Boot | 3.0.x – 3.4.x | 3.0 = jakarta migration cutoff; 3.2 = RestClient + Virtual Threads |
|
|
28
|
+
| Jakarta EE | 9+ (jakarta.* namespace) | NEVER mix with javax.* |
|
|
29
|
+
| JPA / Hibernate | Hibernate 6.x (jakarta.persistence) | Schema validation via Flyway/Liquibase, never Hibernate auto |
|
|
30
|
+
| Spring Security | 6.x | SecurityFilterChain Bean (WebSecurityConfigurerAdapter removed) |
|
|
31
|
+
| Validation | Jakarta Validation 3.x | `jakarta.validation.constraints.*` |
|
|
32
|
+
| Tomcat / Jetty / Undertow | 10.1+ (Servlet 6.0) | Tomcat default |
|
|
33
|
+
| Build | Maven 3.9+ or Gradle 8.5+ | Maven Wrapper / Gradle Wrapper committed |
|
|
34
|
+
| Tests | JUnit 5.10+, Mockito 5.x, Testcontainers 1.20+ | Never H2 as Postgres stand-in |
|
|
35
|
+
| Observability | Micrometer Observation API + Prometheus | Tracing via OpenTelemetry W3C |
|
|
36
|
+
|
|
37
|
+
## 3. Project structure (DDD)
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
backend/
|
|
41
|
+
├── src/main/java/com/<company>/<project>/
|
|
42
|
+
│ ├── domain/ ← pure POJOs, value objects, domain services, repository PORTS (interfaces)
|
|
43
|
+
│ ├── application/ ← use cases (1 public method each), record DTOs req/res, mappers
|
|
44
|
+
│ ├── infrastructure/ ← JPA adapters, JpaRepository, RestClient adapters, security, config
|
|
45
|
+
│ └── web/ ← @RestController, @ControllerAdvice, filters
|
|
46
|
+
├── src/main/resources/
|
|
47
|
+
│ ├── application.yml
|
|
48
|
+
│ ├── application-{dev,prod}.yml
|
|
49
|
+
│ └── db/migration/V<ts>__<verb>_<subject>.sql ← Flyway migrations
|
|
50
|
+
└── src/test/java/com/<company>/<project>/
|
|
51
|
+
├── <pkg>...Test.java ← unit (JUnit + Mockito)
|
|
52
|
+
└── <pkg>...IT.java ← integration (Testcontainers)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 4. Code patterns
|
|
56
|
+
|
|
57
|
+
### DTOs as records (req/res separated)
|
|
58
|
+
|
|
59
|
+
```java
|
|
60
|
+
// application/dto/CreateProductRequest.java
|
|
61
|
+
public record CreateProductRequest(
|
|
62
|
+
@NotBlank @Size(max = 120) String name,
|
|
63
|
+
@NotNull @Positive BigDecimal price,
|
|
64
|
+
@NotNull @PositiveOrZero Integer stock
|
|
65
|
+
) {}
|
|
66
|
+
|
|
67
|
+
// application/dto/ProductResponse.java
|
|
68
|
+
public record ProductResponse(
|
|
69
|
+
UUID id, String name, BigDecimal price, Integer stock, Instant createdAt
|
|
70
|
+
) {}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Rule**: never expose JPA `@Entity` to controllers. Mapper layer is explicit (`ProductMapper.toResponse(entity)`).
|
|
74
|
+
|
|
75
|
+
### Controller + ProblemDetail (RFC 9457)
|
|
76
|
+
|
|
77
|
+
```java
|
|
78
|
+
@RestController
|
|
79
|
+
@RequestMapping("/api/v1/products")
|
|
80
|
+
@RequiredArgsConstructor
|
|
81
|
+
public class ProductController {
|
|
82
|
+
private final CreateProductUseCase createUseCase;
|
|
83
|
+
|
|
84
|
+
@PostMapping
|
|
85
|
+
@ResponseStatus(HttpStatus.CREATED)
|
|
86
|
+
public ProductResponse create(@Valid @RequestBody CreateProductRequest req) {
|
|
87
|
+
return createUseCase.execute(req);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@RestControllerAdvice
|
|
92
|
+
public class GlobalExceptionHandler {
|
|
93
|
+
@ExceptionHandler(MethodArgumentNotValidException.class)
|
|
94
|
+
public ProblemDetail handleValidation(MethodArgumentNotValidException ex) {
|
|
95
|
+
var pd = ProblemDetail.forStatus(HttpStatus.UNPROCESSABLE_ENTITY);
|
|
96
|
+
pd.setTitle("Validation failed");
|
|
97
|
+
pd.setProperty("errors", ex.getBindingResult().getFieldErrors().stream()
|
|
98
|
+
.map(e -> Map.of("field", e.getField(), "msg", e.getDefaultMessage()))
|
|
99
|
+
.toList());
|
|
100
|
+
return pd;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Transactions
|
|
106
|
+
|
|
107
|
+
- `@Transactional(readOnly = true)` on query methods (avoids dirty-check overhead).
|
|
108
|
+
- `@Transactional` on commands. Propagation = REQUIRED (default). Explicit `REQUIRES_NEW` only with documented reason.
|
|
109
|
+
- Never `@Transactional` on controllers — keep on `application/` use cases.
|
|
110
|
+
|
|
111
|
+
### External calls (RestClient since SB 3.2)
|
|
112
|
+
|
|
113
|
+
```java
|
|
114
|
+
// infrastructure/adapter/PaymentGatewayAdapter.java
|
|
115
|
+
@Component
|
|
116
|
+
public class PaymentGatewayAdapter implements PaymentGateway {
|
|
117
|
+
private final RestClient client;
|
|
118
|
+
|
|
119
|
+
public PaymentGatewayAdapter(RestClient.Builder builder, AppProps props) {
|
|
120
|
+
this.client = builder
|
|
121
|
+
.baseUrl(props.paymentGatewayUrl())
|
|
122
|
+
.requestFactory(ClientHttpRequestFactoryBuilder.detect()
|
|
123
|
+
.build(ClientHttpRequestFactorySettings.defaults()
|
|
124
|
+
.withConnectTimeout(Duration.ofSeconds(3))
|
|
125
|
+
.withReadTimeout(Duration.ofSeconds(10))))
|
|
126
|
+
.build();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
@Override
|
|
130
|
+
@Retry(name = "payment-gateway")
|
|
131
|
+
@CircuitBreaker(name = "payment-gateway")
|
|
132
|
+
public PaymentResult charge(ChargeCommand cmd) {
|
|
133
|
+
try {
|
|
134
|
+
return client.post()
|
|
135
|
+
.uri("/charges")
|
|
136
|
+
.body(cmd)
|
|
137
|
+
.retrieve()
|
|
138
|
+
.body(PaymentResult.class);
|
|
139
|
+
} catch (RestClientResponseException e) {
|
|
140
|
+
throw new PaymentGatewayException("status=" + e.getStatusCode(), e);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Rules**: explicit timeout (connect + read), retry policy (Resilience4j), circuit breaker on external calls. Map foreign exceptions to domain exceptions.
|
|
147
|
+
|
|
148
|
+
### Pagination
|
|
149
|
+
|
|
150
|
+
```java
|
|
151
|
+
@GetMapping
|
|
152
|
+
public Page<ProductResponse> list(Pageable pageable) {
|
|
153
|
+
return service.findAll(pageable).map(ProductMapper::toResponse);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Client passes `?page=0&size=20&sort=name,asc`. Response wraps `content`, `totalElements`, `totalPages`, `number`, `size`.
|
|
158
|
+
|
|
159
|
+
## 5. Testing
|
|
160
|
+
|
|
161
|
+
### Unit (JUnit 5 + Mockito + AssertJ)
|
|
162
|
+
|
|
163
|
+
```java
|
|
164
|
+
@ExtendWith(MockitoExtension.class)
|
|
165
|
+
class CreateProductUseCaseTest {
|
|
166
|
+
@Mock ProductRepository repo;
|
|
167
|
+
@InjectMocks CreateProductUseCase useCase;
|
|
168
|
+
|
|
169
|
+
@Test
|
|
170
|
+
void rejectsNegativePrice() {
|
|
171
|
+
var cmd = new CreateProductCommand("widget", BigDecimal.valueOf(-1), 10);
|
|
172
|
+
assertThatThrownBy(() -> useCase.execute(cmd))
|
|
173
|
+
.isInstanceOf(BusinessRuleException.class)
|
|
174
|
+
.hasMessageContaining("price");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Integration (Testcontainers, NEVER H2)
|
|
180
|
+
|
|
181
|
+
```java
|
|
182
|
+
@SpringBootTest
|
|
183
|
+
@Testcontainers
|
|
184
|
+
@ActiveProfiles("test")
|
|
185
|
+
class ProductRepositoryIT {
|
|
186
|
+
@Container
|
|
187
|
+
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");
|
|
188
|
+
|
|
189
|
+
@DynamicPropertySource
|
|
190
|
+
static void props(DynamicPropertyRegistry r) {
|
|
191
|
+
r.add("spring.datasource.url", postgres::getJdbcUrl);
|
|
192
|
+
r.add("spring.datasource.username", postgres::getUsername);
|
|
193
|
+
r.add("spring.datasource.password", postgres::getPassword);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
@Autowired ProductRepository repo;
|
|
197
|
+
// ...
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Web slice (@WebMvcTest)
|
|
202
|
+
|
|
203
|
+
```java
|
|
204
|
+
@WebMvcTest(ProductController.class)
|
|
205
|
+
class ProductControllerTest {
|
|
206
|
+
@Autowired MockMvc mvc;
|
|
207
|
+
@MockBean CreateProductUseCase useCase;
|
|
208
|
+
|
|
209
|
+
@Test
|
|
210
|
+
void returns422OnInvalidPayload() throws Exception {
|
|
211
|
+
mvc.perform(post("/api/v1/products")
|
|
212
|
+
.contentType(MediaType.APPLICATION_JSON)
|
|
213
|
+
.content("{}"))
|
|
214
|
+
.andExpect(status().isUnprocessableEntity())
|
|
215
|
+
.andExpect(jsonPath("$.title").value("Validation failed"));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Mutation (PIT)
|
|
221
|
+
|
|
222
|
+
Target ≥ 70% on `domain/` + `application/`. Run via:
|
|
223
|
+
```bash
|
|
224
|
+
./mvnw pitest:mutationCoverage
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## 6. Build & run commands
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
./mvnw clean verify # full build + tests + coverage
|
|
231
|
+
./mvnw spring-boot:run # local dev (port 8080)
|
|
232
|
+
./mvnw spring-boot:run -Dspring-boot.run.profiles=dev
|
|
233
|
+
./mvnw spring-boot:test-run # with hot-reload (devtools)
|
|
234
|
+
./mvnw spotbugs:check # static analysis
|
|
235
|
+
./mvnw org.owasp:dependency-check-maven:check # CVE scan
|
|
236
|
+
./mvnw pitest:mutationCoverage # mutation testing
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## 7. Security (per ADR-007 + ADR-027)
|
|
240
|
+
|
|
241
|
+
### 7.1 Authentication & Authorization
|
|
242
|
+
|
|
243
|
+
- **Spring Security 6** with `SecurityFilterChain` Bean (NEVER `WebSecurityConfigurerAdapter` — removed).
|
|
244
|
+
- **JWT validation** via `spring-boot-starter-oauth2-resource-server` for stateless APIs.
|
|
245
|
+
- **`@PreAuthorize`** on controller methods or use cases. Avoid URL-based authorization for fine-grained rules.
|
|
246
|
+
- **Password hashing**: `BCryptPasswordEncoder(strength = 12)`. NEVER MD5/SHA1.
|
|
247
|
+
|
|
248
|
+
```java
|
|
249
|
+
@Configuration
|
|
250
|
+
@EnableMethodSecurity
|
|
251
|
+
public class SecurityConfig {
|
|
252
|
+
@Bean
|
|
253
|
+
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
|
254
|
+
return http
|
|
255
|
+
.csrf(csrf -> csrf.disable()) // stateless API; enable for stateful UI
|
|
256
|
+
.cors(Customizer.withDefaults())
|
|
257
|
+
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
|
258
|
+
.authorizeHttpRequests(auth -> auth
|
|
259
|
+
.requestMatchers("/api/v1/auth/**", "/actuator/health").permitAll()
|
|
260
|
+
.anyRequest().authenticated()
|
|
261
|
+
)
|
|
262
|
+
.oauth2ResourceServer(oauth -> oauth.jwt(Customizer.withDefaults()))
|
|
263
|
+
.headers(h -> h
|
|
264
|
+
.contentSecurityPolicy(csp -> csp.policyDirectives("default-src 'self'"))
|
|
265
|
+
.httpStrictTransportSecurity(hsts -> hsts.maxAgeInSeconds(31536000).includeSubDomains(true))
|
|
266
|
+
.frameOptions(f -> f.deny())
|
|
267
|
+
)
|
|
268
|
+
.build();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### 7.2 CORS
|
|
274
|
+
|
|
275
|
+
NEVER `*` in production. Explicit list:
|
|
276
|
+
|
|
277
|
+
```java
|
|
278
|
+
@Bean
|
|
279
|
+
public CorsConfigurationSource corsConfigurationSource() {
|
|
280
|
+
var config = new CorsConfiguration();
|
|
281
|
+
config.setAllowedOrigins(List.of("https://app.example.com"));
|
|
282
|
+
config.setAllowedMethods(List.of("GET","POST","PUT","DELETE","OPTIONS"));
|
|
283
|
+
config.setAllowedHeaders(List.of("Authorization","Content-Type"));
|
|
284
|
+
config.setAllowCredentials(true);
|
|
285
|
+
config.setMaxAge(3600L);
|
|
286
|
+
var source = new UrlBasedCorsConfigurationSource();
|
|
287
|
+
source.registerCorsConfiguration("/api/**", config);
|
|
288
|
+
return source;
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### 7.3 Validation & input sanitization
|
|
293
|
+
|
|
294
|
+
- **All `@RequestBody`** must be `@Valid`. ProblemDetail returns 422 on violation.
|
|
295
|
+
- **HTML/XSS**: sanitize via OWASP Java HTML Sanitizer if rendering user input back. Never trust client.
|
|
296
|
+
- **SQL injection**: NEVER concatenate. Use `@Query` with named params or Specifications.
|
|
297
|
+
- **Path traversal**: validate file paths against allowlist; reject `..` sequences.
|
|
298
|
+
|
|
299
|
+
### 7.4 Secrets management
|
|
300
|
+
|
|
301
|
+
- NEVER in `application.properties` or `application.yml` committed to git.
|
|
302
|
+
- Use environment variables (`spring.datasource.password=${DB_PASSWORD}`) or Spring Cloud Config + Vault.
|
|
303
|
+
- Local dev: `application-local.yml` in `.gitignore` OR `~/.secrets/<project>.env`.
|
|
304
|
+
- Production: Vault, AWS Secrets Manager, Azure Key Vault.
|
|
305
|
+
|
|
306
|
+
### 7.5 Rate limiting
|
|
307
|
+
|
|
308
|
+
For public endpoints (login, signup, password reset) — Bucket4j:
|
|
309
|
+
|
|
310
|
+
```java
|
|
311
|
+
@Component
|
|
312
|
+
public class RateLimitFilter extends OncePerRequestFilter {
|
|
313
|
+
private final Bucket bucket = Bucket.builder()
|
|
314
|
+
.addLimit(Bandwidth.classic(10, Refill.intervally(10, Duration.ofMinutes(1))))
|
|
315
|
+
.build();
|
|
316
|
+
// applies on /api/v1/auth/*
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### 7.6 OWASP coverage (Top 10)
|
|
321
|
+
|
|
322
|
+
| OWASP | Mitigation in this stack |
|
|
323
|
+
|---|---|
|
|
324
|
+
| A01 Broken Access Control | `@PreAuthorize` + IDOR check (always validate principal owns resource) |
|
|
325
|
+
| A02 Cryptographic Failures | BCrypt 12; JWT signed RS256 (never HS256 in distributed system); HTTPS only |
|
|
326
|
+
| A03 Injection | JPA parameterized queries; never `String.format` SQL; input validation |
|
|
327
|
+
| A04 Insecure Design | Threat model + ADR for new bounded contexts |
|
|
328
|
+
| A05 Security Misconfiguration | SecurityFilterChain explicit; headers via `.headers()`; `/actuator/*` restricted |
|
|
329
|
+
| A06 Vulnerable Components | OWASP dependency-check in CI; Renovate/Dependabot bumps |
|
|
330
|
+
| A07 Auth Failures | Rate limit on auth; `@Lock` on user account after N failures; MFA where critical |
|
|
331
|
+
| A08 Data Integrity | JWT signature; Maven artifact checksums; supply chain via SBOM |
|
|
332
|
+
| A09 Logging Failures | Structured JSON logs + correlation ID via MDC; AUDIT topic separated; PII never logged |
|
|
333
|
+
| A10 SSRF | Allowlist of outbound hosts in `application.yml`; RestClient validates URL against list |
|
|
334
|
+
|
|
335
|
+
### 7.7 LGPD specifics (if applicable)
|
|
336
|
+
|
|
337
|
+
- Identify PII fields (email, CPF, phone) and tag with `@JsonIgnore` on logging serializers.
|
|
338
|
+
- Right to deletion: implement soft-delete + audit log of deletion request.
|
|
339
|
+
- Data subject access: endpoint to export user's data in machine-readable format.
|
|
340
|
+
- Encryption at rest for sensitive columns (e.g. via JPA `AttributeConverter` + AES-256-GCM).
|
|
341
|
+
|
|
342
|
+
## 8. Anti-patterns (block in code-review)
|
|
343
|
+
|
|
344
|
+
| ❌ Bad | ✅ Good | Why |
|
|
345
|
+
|---|---|---|
|
|
346
|
+
| `@Entity` returned from controller | `@Entity` → mapper → `record Response` | Decouples API contract from DB |
|
|
347
|
+
| `javax.validation.constraints.*` | `jakarta.validation.constraints.*` | SB 3 uses jakarta namespace |
|
|
348
|
+
| `WebSecurityConfigurerAdapter` | `SecurityFilterChain` Bean | Removed in Spring Security 6 |
|
|
349
|
+
| `RestTemplate` for new code | `RestClient` (SB 3.2+) | Modern, fluent, supports interception |
|
|
350
|
+
| `H2` in tests | `Testcontainers` Postgres | H2 has different SQL dialect |
|
|
351
|
+
| `@Autowired` field injection | Constructor injection (`@RequiredArgsConstructor`) | Testable, immutable, final fields |
|
|
352
|
+
| `var` in method signature | Full type in signature | Public API contract should be explicit |
|
|
353
|
+
| `// TODO` committed | `docs/brain/architecture/tech-debt.md` | Trackable |
|
|
354
|
+
| `log.info(token)` | `log.info("token=***")` redaction | Never log credentials/PII |
|
|
355
|
+
| `password.equals(input)` | `passwordEncoder.matches(input, hash)` | Timing-safe + hashed comparison |
|
|
356
|
+
|
|
357
|
+
## 9. Migration hints — Spring Boot 3.x → 4.x
|
|
358
|
+
|
|
359
|
+
When migrating a project from this pack to `spring-boot-4.md`:
|
|
360
|
+
|
|
361
|
+
- Java 17/21 → 25 (LTS). Check libs for Java 25 compatibility.
|
|
362
|
+
- Spring Boot 3.x → 4.0: review breaking changes in `spring-boot-migrator-3.0-to-4.0.md` (official docs).
|
|
363
|
+
- `RestClient` API may evolve — review docs.
|
|
364
|
+
- ProblemDetail enhancements (more fields, MDC integration).
|
|
365
|
+
- Native compilation maturity (Spring Boot 4 + GraalVM 23+).
|
|
366
|
+
- Use `migrator` agent — it knows both packs and proposes ADR per major cross.
|
|
367
|
+
|
|
368
|
+
## 10. References
|
|
369
|
+
|
|
370
|
+
- ADR-007 (Senior+ gate thresholds — apply to projects using this pack)
|
|
371
|
+
- ADR-026 (Generic agents + packs architecture)
|
|
372
|
+
- ADR-027 (This pack's governance — frontmatter, security review)
|
|
373
|
+
- Spring Boot 3.x release notes: https://github.com/spring-projects/spring-boot/wiki
|
|
374
|
+
- Spring Security 6 migration: https://docs.spring.io/spring-security/reference/6.0/migration.html
|
|
375
|
+
- OWASP Top 10 (2021): https://owasp.org/Top10/
|
|
376
|
+
- Jakarta EE migration guide: https://www.eclipse.org/community/eclipse_newsletter/2022/march/1.php
|