Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 2 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,29 +305,9 @@ spring:
password: ${DATABASE_PASSWORD}
```

## Troubleshooting
## References

### Common Issues

**JWT Secret Too Short**

```
Error: JWT secret must be at least 64 bytes for HS512
Solution: Generate proper length secrets using the KeyGenerator utility
```

**Database Connection Issues**

```
Check: DATABASE_URL, DATABASE_USERNAME, DATABASE_PASSWORD in .env
Verify: PostgreSQL is running and accessible
```

**Port Already in Use**

```
Change port in application.yml or stop conflicting services
```
- [Implementing Domain Driven Design with Spring](https://github.com/maciejwalkowiak/implementing-ddd-with-spring-talk)

## License

Expand Down
2 changes: 1 addition & 1 deletion auto/test
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env sh

export SPRING_PROFILES_ACTIVE=test
./gradlew test --stacktrace jacocoTestCoverageVerification
./gradlew test jacocoTestCoverageVerification
110 changes: 2 additions & 108 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -183,111 +183,5 @@ tasks.test {
outputs.cacheIf { true }
}

// Test coverage: jacoco
jacoco {
toolVersion = "0.8.14"
}

tasks.jacocoTestReport {
dependsOn(tasks.test)
reports {
xml.required.set(true) // For CI/CD integration
html.required.set(true) // For human-readable reports
csv.required.set(false)
}

classDirectories.setFrom(
files(classDirectories.files.map {
fileTree(it) {
exclude(
// Infrastructure - config and cross-cutting concerns
"**/infrastructure/config/**",
"**/infrastructure/security/**",
"**/infrastructure/resolver/**",
"**/infrastructure/persistence/**",
"**/infrastructure/adapter/**",
// DTOs, requests, responses, mappers (data carriers)
"**/dto/**",
"**/request/**",
"**/response/**",
"**/mapper/**",
// Domain value objects and events
"**/domain/model/*Id.class",
"**/domain/model/*Name.class",
"**/domain/model/*Role.class",
"**/domain/event/**",
// Shared kernel and local utilities
"**/shared/**",
// Interfaces layer (controllers, REST)
"**/interfaces/rest/**",
"**/interfaces/grpc/**",
// Application entry point
"**/*Application*",
// Generated code
"**/proto/**",
"**/generated/**"
)
}
})
)
}
tasks.jacocoTestCoverageVerification {
dependsOn(tasks.jacocoTestReport)
violationRules {
rule {
limit {
minimum = "0.80".toBigDecimal()
}
}
rule {
element = "CLASS"
includes = listOf(
"org.nkcoder.auth.application.service.*",
"org.nkcoder.user.application.service.*"
)
limit {
minimum = "0.80".toBigDecimal()
}
}
classDirectories.setFrom(
// Same exclusions as jacocoTestReport
files(classDirectories.files.map {
fileTree(it) {
exclude(
// Infrastructure - config and cross-cutting concerns
"**/infrastructure/config/**",
"**/infrastructure/security/**",
"**/infrastructure/resolver/**",
"**/infrastructure/persistence/**",
"**/infrastructure/adapter/**",
// DTOs, requests, responses, mappers (data carriers)
"**/dto/**",
"**/request/**",
"**/response/**",
"**/mapper/**",
// Domain value objects and events
"**/domain/model/*Id.class",
"**/domain/model/*Name.class",
"**/domain/model/*Role.class",
"**/domain/event/**",
// Shared kernel and local utilities
"**/shared/**",
// Interfaces layer (controllers, REST)
"**/interfaces/rest/**",
"**/interfaces/grpc/**",
// Application entry point
"**/*Application*",
// Generated code
"**/proto/**",
"**/generated/**"
)
}
})
)
}
}
tasks.check {
dependsOn(tasks.jacocoTestCoverageVerification)
}


// Test coverage configuration (JaCoCo)
apply(from = "gradle/jacoco.gradle.kts")
109 changes: 109 additions & 0 deletions gradle/jacoco.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* JaCoCo test coverage configuration.
*
* This file configures code coverage reporting and verification thresholds.
* Apply this script in build.gradle.kts with: apply(from = "gradle/jacoco.gradle.kts")
*/

// JaCoCo plugin configuration
configure<JacocoPluginExtension> {
toolVersion = "0.8.14"
}

// Shared exclusion patterns for classes that don't need coverage
val jacocoExclusions = listOf(
// Top-level infrastructure config (Spring wiring, no business logic)
"**/infrastructure/config/**",
"**/infrastructure/resolver/**",
// DTOs, commands, requests, responses (data carriers, no logic)
"**/dto/**",
"**/request/**",
"**/response/**",
"**/entity/**",
// Mappers (simple transformations)
"**/mapper/**",
// Domain value objects (simple wrappers with no business logic)
"**/domain/model/*Id.class",
"**/domain/model/*Role.class",
"**/domain/model/TokenFamily.class",
"**/domain/model/TokenPair.class",
"**/domain/model/HashedPassword.class",
// Domain events (data carriers)
"**/domain/event/**",
// Domain repository interfaces (just interfaces, no implementation)
"**/domain/repository/**",
// Domain service interfaces (PasswordEncoder, TokenGenerator - just interfaces)
"**/domain/service/PasswordEncoder.class",
"**/domain/service/TokenGenerator*.class",
// Shared kernel (framework utilities)
"**/shared/**",
// Application entry point
"**/*Application.class",
// Generated code (protobuf, grpc)
"**/proto/**",
"**/generated/**"
)

// Classes that require strict 80% coverage (core business logic)
val strictCoverageClasses = listOf(
// Application services - orchestration logic
"org.nkcoder.user.application.service.*",
// Domain services - business logic
"org.nkcoder.user.domain.service.AuthenticationService",
"org.nkcoder.user.domain.service.TokenRotationService",
// Domain model - core business rules
"org.nkcoder.user.domain.model.User",
"org.nkcoder.user.domain.model.RefreshToken",
"org.nkcoder.user.domain.model.Email",
"org.nkcoder.user.domain.model.UserName",
// Infrastructure - repository persistence
"org.nkcoder.user.infrastructure.persistence.repository",
)

tasks.named<JacocoReport>("jacocoTestReport") {
dependsOn(tasks.named("test"))
reports {
xml.required.set(true) // For CI/CD integration
html.required.set(true) // For human-readable reports
csv.required.set(false)
}

classDirectories.setFrom(
files(classDirectories.files.map {
fileTree(it) {
exclude(jacocoExclusions)
}
})
)
}

tasks.named<JacocoCoverageVerification>("jacocoTestCoverageVerification") {
dependsOn(tasks.named("jacocoTestReport"))
violationRules {
// Global minimum
rule {
limit {
minimum = "0.80".toBigDecimal()
}
}
// Strict requirements for core business logic (domain + application layers)
rule {
element = "CLASS"
includes = strictCoverageClasses
limit {
minimum = "0.90".toBigDecimal()
}
}
classDirectories.setFrom(
files(classDirectories.files.map {
fileTree(it) {
exclude(jacocoExclusions)
}
})
)
}
}

tasks.named("check") {
dependsOn(tasks.named("jacocoTestCoverageVerification"))
}

This file was deleted.

19 changes: 0 additions & 19 deletions src/main/java/org/nkcoder/auth/domain/event/UserLoggedInEvent.java

This file was deleted.

This file was deleted.

7 changes: 0 additions & 7 deletions src/main/java/org/nkcoder/auth/domain/model/AuthRole.java

This file was deleted.

Loading
Loading