autoworkflow 3.1.5 → 3.6.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 (124) hide show
  1. package/.claude/commands/analyze.md +19 -0
  2. package/.claude/commands/audit.md +26 -0
  3. package/.claude/commands/build.md +39 -0
  4. package/.claude/commands/commit.md +25 -0
  5. package/.claude/commands/fix.md +23 -0
  6. package/.claude/commands/plan.md +18 -0
  7. package/.claude/commands/suggest.md +23 -0
  8. package/.claude/commands/verify.md +18 -0
  9. package/.claude/hooks/post-bash-router.sh +20 -0
  10. package/.claude/hooks/post-commit.sh +140 -0
  11. package/.claude/hooks/post-edit.sh +190 -17
  12. package/.claude/hooks/pre-edit.sh +221 -0
  13. package/.claude/hooks/session-check.sh +90 -0
  14. package/.claude/settings.json +56 -6
  15. package/.claude/settings.local.json +5 -1
  16. package/.claude/skills/actix.md +337 -0
  17. package/.claude/skills/alembic.md +504 -0
  18. package/.claude/skills/angular.md +237 -0
  19. package/.claude/skills/api-design.md +187 -0
  20. package/.claude/skills/aspnet-core.md +377 -0
  21. package/.claude/skills/astro.md +245 -0
  22. package/.claude/skills/auth-clerk.md +327 -0
  23. package/.claude/skills/auth-firebase.md +367 -0
  24. package/.claude/skills/auth-nextauth.md +359 -0
  25. package/.claude/skills/auth-supabase.md +368 -0
  26. package/.claude/skills/axum.md +386 -0
  27. package/.claude/skills/blazor.md +456 -0
  28. package/.claude/skills/chi.md +348 -0
  29. package/.claude/skills/code-review.md +133 -0
  30. package/.claude/skills/csharp.md +296 -0
  31. package/.claude/skills/css-modules.md +325 -0
  32. package/.claude/skills/cypress.md +343 -0
  33. package/.claude/skills/debugging.md +133 -0
  34. package/.claude/skills/diesel.md +392 -0
  35. package/.claude/skills/django.md +301 -0
  36. package/.claude/skills/docker.md +319 -0
  37. package/.claude/skills/doctrine.md +473 -0
  38. package/.claude/skills/documentation.md +182 -0
  39. package/.claude/skills/dotnet.md +409 -0
  40. package/.claude/skills/drizzle.md +293 -0
  41. package/.claude/skills/echo.md +321 -0
  42. package/.claude/skills/eloquent.md +256 -0
  43. package/.claude/skills/emotion.md +426 -0
  44. package/.claude/skills/entity-framework.md +370 -0
  45. package/.claude/skills/express.md +316 -0
  46. package/.claude/skills/fastapi.md +329 -0
  47. package/.claude/skills/fastify.md +299 -0
  48. package/.claude/skills/fiber.md +315 -0
  49. package/.claude/skills/flask.md +322 -0
  50. package/.claude/skills/gin.md +342 -0
  51. package/.claude/skills/git.md +116 -0
  52. package/.claude/skills/github-actions.md +353 -0
  53. package/.claude/skills/go.md +377 -0
  54. package/.claude/skills/gorm.md +409 -0
  55. package/.claude/skills/graphql.md +478 -0
  56. package/.claude/skills/hibernate.md +379 -0
  57. package/.claude/skills/hono.md +306 -0
  58. package/.claude/skills/java.md +400 -0
  59. package/.claude/skills/jest.md +313 -0
  60. package/.claude/skills/jpa.md +282 -0
  61. package/.claude/skills/kotlin.md +347 -0
  62. package/.claude/skills/kubernetes.md +363 -0
  63. package/.claude/skills/laravel.md +414 -0
  64. package/.claude/skills/mcp-browser.md +320 -0
  65. package/.claude/skills/mcp-database.md +219 -0
  66. package/.claude/skills/mcp-fetch.md +241 -0
  67. package/.claude/skills/mcp-filesystem.md +204 -0
  68. package/.claude/skills/mcp-github.md +217 -0
  69. package/.claude/skills/mcp-memory.md +240 -0
  70. package/.claude/skills/mcp-search.md +218 -0
  71. package/.claude/skills/mcp-slack.md +262 -0
  72. package/.claude/skills/micronaut.md +388 -0
  73. package/.claude/skills/mongodb.md +319 -0
  74. package/.claude/skills/mongoose.md +355 -0
  75. package/.claude/skills/mysql.md +281 -0
  76. package/.claude/skills/nestjs.md +335 -0
  77. package/.claude/skills/nextjs-app-router.md +260 -0
  78. package/.claude/skills/nextjs-pages.md +172 -0
  79. package/.claude/skills/nuxt.md +202 -0
  80. package/.claude/skills/openapi.md +489 -0
  81. package/.claude/skills/performance.md +199 -0
  82. package/.claude/skills/php.md +398 -0
  83. package/.claude/skills/playwright.md +371 -0
  84. package/.claude/skills/postgresql.md +257 -0
  85. package/.claude/skills/prisma.md +293 -0
  86. package/.claude/skills/pydantic.md +304 -0
  87. package/.claude/skills/pytest.md +313 -0
  88. package/.claude/skills/python.md +272 -0
  89. package/.claude/skills/quarkus.md +377 -0
  90. package/.claude/skills/react.md +230 -0
  91. package/.claude/skills/redis.md +391 -0
  92. package/.claude/skills/refactoring.md +143 -0
  93. package/.claude/skills/remix.md +246 -0
  94. package/.claude/skills/rest-api.md +490 -0
  95. package/.claude/skills/rocket.md +366 -0
  96. package/.claude/skills/rust.md +341 -0
  97. package/.claude/skills/sass.md +380 -0
  98. package/.claude/skills/sea-orm.md +382 -0
  99. package/.claude/skills/security.md +167 -0
  100. package/.claude/skills/sequelize.md +395 -0
  101. package/.claude/skills/spring-boot.md +416 -0
  102. package/.claude/skills/sqlalchemy.md +269 -0
  103. package/.claude/skills/sqlx-rust.md +408 -0
  104. package/.claude/skills/state-jotai.md +346 -0
  105. package/.claude/skills/state-mobx.md +353 -0
  106. package/.claude/skills/state-pinia.md +431 -0
  107. package/.claude/skills/state-redux.md +337 -0
  108. package/.claude/skills/state-tanstack-query.md +434 -0
  109. package/.claude/skills/state-zustand.md +340 -0
  110. package/.claude/skills/styled-components.md +403 -0
  111. package/.claude/skills/svelte.md +238 -0
  112. package/.claude/skills/sveltekit.md +207 -0
  113. package/.claude/skills/symfony.md +437 -0
  114. package/.claude/skills/tailwind.md +279 -0
  115. package/.claude/skills/terraform.md +394 -0
  116. package/.claude/skills/testing-library.md +371 -0
  117. package/.claude/skills/trpc.md +426 -0
  118. package/.claude/skills/typeorm.md +368 -0
  119. package/.claude/skills/vitest.md +330 -0
  120. package/.claude/skills/vue.md +202 -0
  121. package/.claude/skills/warp.md +365 -0
  122. package/README.md +163 -52
  123. package/package.json +1 -1
  124. package/system/triggers.md +256 -17
@@ -0,0 +1,282 @@
1
+ # JPA Skill (Spring Data JPA)
2
+
3
+ ## Repository Interface
4
+ \`\`\`java
5
+ public interface UserRepository extends JpaRepository<User, String> {
6
+
7
+ // Derived query methods
8
+ Optional<User> findByEmail(String email);
9
+
10
+ List<User> findByIsActiveTrueOrderByCreatedAtDesc();
11
+
12
+ boolean existsByEmail(String email);
13
+
14
+ long countByIsActiveTrue();
15
+
16
+ // Query methods with @Query
17
+ @Query("SELECT u FROM User u WHERE u.isActive = true")
18
+ List<User> findActiveUsers();
19
+
20
+ @Query("SELECT u FROM User u LEFT JOIN FETCH u.posts WHERE u.id = :id")
21
+ Optional<User> findByIdWithPosts(@Param("id") String id);
22
+
23
+ @Query(value = "SELECT * FROM users WHERE email ILIKE %:query%", nativeQuery = true)
24
+ List<User> searchByEmail(@Param("query") String query);
25
+
26
+ // Modifying queries
27
+ @Modifying
28
+ @Query("UPDATE User u SET u.isActive = false WHERE u.id = :id")
29
+ int deactivateUser(@Param("id") String id);
30
+
31
+ @Modifying
32
+ @Query("DELETE FROM User u WHERE u.isActive = false AND u.createdAt < :date")
33
+ int deleteInactiveOlderThan(@Param("date") Instant date);
34
+
35
+ // Pagination
36
+ Page<User> findByIsActiveTrue(Pageable pageable);
37
+
38
+ Slice<User> findByRolesName(String roleName, Pageable pageable);
39
+ }
40
+ \`\`\`
41
+
42
+ ## Specifications (Dynamic Queries)
43
+ \`\`\`java
44
+ // Repository with Specification support
45
+ public interface UserRepository extends
46
+ JpaRepository<User, String>,
47
+ JpaSpecificationExecutor<User> {
48
+ }
49
+
50
+ // Specification definitions
51
+ public class UserSpecifications {
52
+
53
+ public static Specification<User> hasEmail(String email) {
54
+ return (root, query, cb) -> email == null ? null :
55
+ cb.equal(root.get("email"), email);
56
+ }
57
+
58
+ public static Specification<User> emailContains(String search) {
59
+ return (root, query, cb) -> search == null ? null :
60
+ cb.like(cb.lower(root.get("email")), "%" + search.toLowerCase() + "%");
61
+ }
62
+
63
+ public static Specification<User> isActive() {
64
+ return (root, query, cb) -> cb.isTrue(root.get("isActive"));
65
+ }
66
+
67
+ public static Specification<User> createdAfter(Instant date) {
68
+ return (root, query, cb) -> date == null ? null :
69
+ cb.greaterThan(root.get("createdAt"), date);
70
+ }
71
+
72
+ public static Specification<User> hasRole(String roleName) {
73
+ return (root, query, cb) -> {
74
+ if (roleName == null) return null;
75
+ Join<User, Role> roles = root.join("roles");
76
+ return cb.equal(roles.get("name"), roleName);
77
+ };
78
+ }
79
+ }
80
+
81
+ // Usage in service
82
+ public Page<User> searchUsers(UserSearchCriteria criteria, Pageable pageable) {
83
+ Specification<User> spec = Specification
84
+ .where(emailContains(criteria.getEmail()))
85
+ .and(isActive())
86
+ .and(createdAfter(criteria.getCreatedAfter()))
87
+ .and(hasRole(criteria.getRole()));
88
+
89
+ return userRepository.findAll(spec, pageable);
90
+ }
91
+ \`\`\`
92
+
93
+ ## Projections
94
+ \`\`\`java
95
+ // Interface-based projection (closed)
96
+ public interface UserSummary {
97
+ String getId();
98
+ String getEmail();
99
+ String getName();
100
+
101
+ // Computed value
102
+ @Value("#{\${target.firstName} + ' ' + \${target.lastName}}")
103
+ String getFullName();
104
+ }
105
+
106
+ // Class-based projection (DTO)
107
+ public record UserDto(String id, String email, String name) {}
108
+
109
+ // Dynamic projection
110
+ public interface UserRepository extends JpaRepository<User, String> {
111
+
112
+ // Returns different projections based on type parameter
113
+ <T> Optional<T> findById(String id, Class<T> type);
114
+
115
+ <T> List<T> findByIsActiveTrue(Class<T> type);
116
+
117
+ // Interface projection
118
+ List<UserSummary> findAllProjectedBy();
119
+
120
+ // DTO projection with JPQL
121
+ @Query("SELECT new com.example.dto.UserDto(u.id, u.email, u.name) FROM User u WHERE u.isActive = true")
122
+ List<UserDto> findActiveUserDtos();
123
+ }
124
+
125
+ // Usage
126
+ UserSummary summary = userRepository.findById("123", UserSummary.class).orElseThrow();
127
+ UserDto dto = userRepository.findById("123", UserDto.class).orElseThrow();
128
+ \`\`\`
129
+
130
+ ## Auditing
131
+ \`\`\`java
132
+ // Enable auditing
133
+ @Configuration
134
+ @EnableJpaAuditing
135
+ public class JpaConfig {
136
+
137
+ @Bean
138
+ public AuditorAware<String> auditorProvider() {
139
+ return () -> Optional.ofNullable(SecurityContextHolder.getContext())
140
+ .map(SecurityContext::getAuthentication)
141
+ .filter(Authentication::isAuthenticated)
142
+ .map(Authentication::getName);
143
+ }
144
+ }
145
+
146
+ // Auditable base entity
147
+ @MappedSuperclass
148
+ @EntityListeners(AuditingEntityListener.class)
149
+ public abstract class AuditableEntity {
150
+
151
+ @CreatedDate
152
+ @Column(name = "created_at", nullable = false, updatable = false)
153
+ private Instant createdAt;
154
+
155
+ @LastModifiedDate
156
+ @Column(name = "updated_at")
157
+ private Instant updatedAt;
158
+
159
+ @CreatedBy
160
+ @Column(name = "created_by", updatable = false)
161
+ private String createdBy;
162
+
163
+ @LastModifiedBy
164
+ @Column(name = "updated_by")
165
+ private String updatedBy;
166
+
167
+ // Getters...
168
+ }
169
+
170
+ // Entity extending auditable
171
+ @Entity
172
+ public class User extends AuditableEntity {
173
+ @Id
174
+ @GeneratedValue(strategy = GenerationType.UUID)
175
+ private String id;
176
+
177
+ private String email;
178
+ private String name;
179
+ }
180
+ \`\`\`
181
+
182
+ ## Query by Example
183
+ \`\`\`java
184
+ public interface UserRepository extends
185
+ JpaRepository<User, String>,
186
+ QueryByExampleExecutor<User> {
187
+ }
188
+
189
+ // Usage
190
+ User probe = new User();
191
+ probe.setIsActive(true);
192
+ probe.setEmail("@example.com");
193
+
194
+ ExampleMatcher matcher = ExampleMatcher.matching()
195
+ .withStringMatcher(ExampleMatcher.StringMatcher.ENDING)
196
+ .withIgnoreCase()
197
+ .withIgnoreNullValues();
198
+
199
+ Example<User> example = Example.of(probe, matcher);
200
+
201
+ List<User> users = userRepository.findAll(example);
202
+ \`\`\`
203
+
204
+ ## Custom Repository Implementation
205
+ \`\`\`java
206
+ // Custom repository interface
207
+ public interface UserRepositoryCustom {
208
+ List<User> findUsersWithComplexCriteria(UserSearchCriteria criteria);
209
+ void batchUpdateStatus(List<String> ids, boolean isActive);
210
+ }
211
+
212
+ // Implementation
213
+ public class UserRepositoryImpl implements UserRepositoryCustom {
214
+
215
+ @PersistenceContext
216
+ private EntityManager em;
217
+
218
+ @Override
219
+ public List<User> findUsersWithComplexCriteria(UserSearchCriteria criteria) {
220
+ CriteriaBuilder cb = em.getCriteriaBuilder();
221
+ CriteriaQuery<User> cq = cb.createQuery(User.class);
222
+ Root<User> user = cq.from(User.class);
223
+
224
+ List<Predicate> predicates = new ArrayList<>();
225
+ // Build predicates...
226
+
227
+ cq.where(predicates.toArray(new Predicate[0]));
228
+ return em.createQuery(cq).getResultList();
229
+ }
230
+
231
+ @Override
232
+ @Transactional
233
+ public void batchUpdateStatus(List<String> ids, boolean isActive) {
234
+ em.createQuery("UPDATE User u SET u.isActive = :status WHERE u.id IN :ids")
235
+ .setParameter("status", isActive)
236
+ .setParameter("ids", ids)
237
+ .executeUpdate();
238
+ }
239
+ }
240
+
241
+ // Main repository extends both
242
+ public interface UserRepository extends
243
+ JpaRepository<User, String>,
244
+ UserRepositoryCustom {
245
+ }
246
+ \`\`\`
247
+
248
+ ## Stream Results for Large Datasets
249
+ \`\`\`java
250
+ public interface UserRepository extends JpaRepository<User, String> {
251
+
252
+ @Query("SELECT u FROM User u WHERE u.isActive = true")
253
+ Stream<User> findAllActiveAsStream();
254
+ }
255
+
256
+ // Usage - must be in transaction
257
+ @Transactional(readOnly = true)
258
+ public void processAllUsers() {
259
+ try (Stream<User> stream = userRepository.findAllActiveAsStream()) {
260
+ stream.forEach(user -> {
261
+ // Process each user
262
+ // EntityManager clears automatically with @Modifying(clearAutomatically = true)
263
+ });
264
+ }
265
+ }
266
+ \`\`\`
267
+
268
+ ## ✅ DO
269
+ - Use derived query methods for simple queries
270
+ - Use \`@Query\` for complex queries
271
+ - Use Specifications for dynamic queries
272
+ - Use projections to fetch only needed fields
273
+ - Use \`@Transactional(readOnly = true)\` for read operations
274
+ - Use pagination for large result sets
275
+ - Use \`@EntityGraph\` or \`JOIN FETCH\` to avoid N+1
276
+
277
+ ## ❌ DON'T
278
+ - Don't return entities directly from controllers (use DTOs)
279
+ - Don't use \`findAll()\` without pagination on large tables
280
+ - Don't forget \`@Modifying\` on UPDATE/DELETE queries
281
+ - Don't use \`@Query\` with \`nativeQuery=true\` unless necessary
282
+ - Don't ignore the N+1 problem - use eager fetching strategically
@@ -0,0 +1,347 @@
1
+ # Kotlin Skill
2
+
3
+ ## Data Classes and Records
4
+ \`\`\`kotlin
5
+ // Immutable data class
6
+ data class User(
7
+ val id: String,
8
+ val email: String,
9
+ val name: String,
10
+ val isActive: Boolean = true,
11
+ val createdAt: Instant = Instant.now()
12
+ )
13
+
14
+ // With validation in init block
15
+ data class Email(val value: String) {
16
+ init {
17
+ require(value.contains("@")) { "Invalid email format" }
18
+ }
19
+ }
20
+
21
+ // Copy with modifications
22
+ val updatedUser = user.copy(name = "New Name", isActive = false)
23
+
24
+ // Destructuring
25
+ val (id, email, name) = user
26
+ users.forEach { (id, email) -> println("$id: $email") }
27
+ \`\`\`
28
+
29
+ ## Null Safety
30
+ \`\`\`kotlin
31
+ // Nullable types
32
+ var name: String? = null
33
+
34
+ // Safe call operator
35
+ val length = name?.length // Returns null if name is null
36
+
37
+ // Elvis operator
38
+ val displayName = user.name ?: "Anonymous"
39
+ val email = user.email ?: throw IllegalStateException("Email required")
40
+
41
+ // Safe cast
42
+ val result = obj as? String // Returns null if cast fails
43
+
44
+ // Not-null assertion (use sparingly!)
45
+ val length = name!!.length // Throws NPE if null
46
+
47
+ // let for null checks
48
+ user?.let {
49
+ sendEmail(it.email)
50
+ logAction(it.id)
51
+ }
52
+
53
+ // Early return with Elvis
54
+ fun process(user: User?): Result {
55
+ val u = user ?: return Result.failure("User required")
56
+ return processUser(u)
57
+ }
58
+
59
+ // Platform types (Java interop)
60
+ // Use @Nullable/@NotNull annotations or treat as nullable
61
+ fun handleJavaResult(result: String?) {
62
+ result?.let { process(it) }
63
+ }
64
+ \`\`\`
65
+
66
+ ## Sealed Classes and When
67
+ \`\`\`kotlin
68
+ // Sealed class for restricted hierarchies
69
+ sealed class Result<out T> {
70
+ data class Success<T>(val data: T) : Result<T>()
71
+ data class Error(val message: String, val cause: Throwable? = null) : Result<Nothing>()
72
+ data object Loading : Result<Nothing>()
73
+ }
74
+
75
+ // Exhaustive when (compiler ensures all cases handled)
76
+ fun handleResult(result: Result<User>): String = when (result) {
77
+ is Result.Success -> "Got user: \${result.data.name}"
78
+ is Result.Error -> "Error: \${result.message}"
79
+ is Result.Loading -> "Loading..."
80
+ }
81
+
82
+ // Sealed interface
83
+ sealed interface ApiResponse {
84
+ data class Success(val body: String) : ApiResponse
85
+ data class Error(val code: Int, val message: String) : ApiResponse
86
+ }
87
+
88
+ // When with complex conditions
89
+ fun describe(user: User) = when {
90
+ user.isActive && user.roles.contains("ADMIN") -> "Active Admin"
91
+ user.isActive -> "Active User"
92
+ else -> "Inactive"
93
+ }
94
+ \`\`\`
95
+
96
+ ## Scope Functions
97
+ \`\`\`kotlin
98
+ // let - transform nullable, use 'it'
99
+ val email = user?.email?.let { validateEmail(it) }
100
+
101
+ // run - execute block with 'this', return result
102
+ val result = user.run {
103
+ validate()
104
+ save()
105
+ toResponse()
106
+ }
107
+
108
+ // apply - configure object, return 'this'
109
+ val user = User().apply {
110
+ email = "test@example.com"
111
+ name = "Test"
112
+ isActive = true
113
+ }
114
+
115
+ // also - side effects, return 'this'
116
+ val user = createUser()
117
+ .also { log.info("Created user: \${it.id}") }
118
+ .also { metrics.increment("users.created") }
119
+
120
+ // with - operate on object, return result
121
+ val description = with(user) {
122
+ "User $name ($email) - Active: $isActive"
123
+ }
124
+
125
+ // takeIf / takeUnless
126
+ val activeUser = user.takeIf { it.isActive }
127
+ val inactiveUser = user.takeUnless { it.isActive }
128
+
129
+ // Chaining
130
+ val result = input
131
+ ?.takeIf { it.isNotBlank() }
132
+ ?.let { parse(it) }
133
+ ?.also { validate(it) }
134
+ ?: defaultValue
135
+ \`\`\`
136
+
137
+ ## Extension Functions
138
+ \`\`\`kotlin
139
+ // Add functions to existing types
140
+ fun String.toSlug(): String =
141
+ lowercase()
142
+ .replace(Regex("[^a-z0-9\\\\s-]"), "")
143
+ .replace(Regex("\\\\s+"), "-")
144
+
145
+ fun String.isValidEmail(): Boolean =
146
+ matches(Regex("^[A-Za-z0-9+_.-]+@(.+)$"))
147
+
148
+ // Extension on nullable type
149
+ fun String?.orEmpty(): String = this ?: ""
150
+
151
+ fun <T> List<T>?.orEmpty(): List<T> = this ?: emptyList()
152
+
153
+ // Extension properties
154
+ val String.firstWord: String
155
+ get() = split(" ").first()
156
+
157
+ // Generic extensions
158
+ fun <T> T.log(tag: String = "DEBUG"): T = also {
159
+ println("[$tag] $it")
160
+ }
161
+
162
+ // Scoped extensions
163
+ class UserService {
164
+ // Only available within UserService
165
+ private fun User.toResponse() = UserResponse(id, email, name)
166
+
167
+ fun getUser(id: String): UserResponse =
168
+ repository.findById(id).toResponse()
169
+ }
170
+ \`\`\`
171
+
172
+ ## Collections
173
+ \`\`\`kotlin
174
+ // Immutable by default
175
+ val list = listOf(1, 2, 3)
176
+ val set = setOf("a", "b", "c")
177
+ val map = mapOf("key1" to "value1", "key2" to "value2")
178
+
179
+ // Mutable when needed
180
+ val mutableList = mutableListOf(1, 2, 3)
181
+ mutableList.add(4)
182
+
183
+ // Transformations
184
+ val emails = users
185
+ .filter { it.isActive }
186
+ .map { it.email }
187
+ .distinct()
188
+ .sorted()
189
+
190
+ // Grouping
191
+ val byDomain = users.groupBy { it.email.substringAfter("@") }
192
+
193
+ // Aggregation
194
+ val totalAge = users.sumOf { it.age }
195
+ val averageAge = users.map { it.age }.average()
196
+ val oldest = users.maxByOrNull { it.age }
197
+
198
+ // Partition
199
+ val (active, inactive) = users.partition { it.isActive }
200
+
201
+ // Associate
202
+ val userById = users.associateBy { it.id }
203
+ val idToEmail = users.associate { it.id to it.email }
204
+
205
+ // Sequences for large collections (lazy evaluation)
206
+ val result = users.asSequence()
207
+ .filter { it.isActive }
208
+ .map { it.email }
209
+ .take(10)
210
+ .toList()
211
+
212
+ // Null-safe operations
213
+ val firstActive = users.firstOrNull { it.isActive }
214
+ val emails = users.mapNotNull { it.email } // Filters nulls
215
+ \`\`\`
216
+
217
+ ## Coroutines
218
+ \`\`\`kotlin
219
+ import kotlinx.coroutines.*
220
+
221
+ // Suspend function
222
+ suspend fun fetchUser(id: String): User = withContext(Dispatchers.IO) {
223
+ repository.findById(id)
224
+ }
225
+
226
+ // Launching coroutines
227
+ fun main() = runBlocking {
228
+ val job = launch {
229
+ delay(1000)
230
+ println("World!")
231
+ }
232
+ println("Hello,")
233
+ job.join()
234
+ }
235
+
236
+ // Async for concurrent operations
237
+ suspend fun fetchUserWithPosts(userId: String): UserWithPosts = coroutineScope {
238
+ val userDeferred = async { fetchUser(userId) }
239
+ val postsDeferred = async { fetchPosts(userId) }
240
+
241
+ UserWithPosts(
242
+ user = userDeferred.await(),
243
+ posts = postsDeferred.await()
244
+ )
245
+ }
246
+
247
+ // Error handling
248
+ suspend fun safeFetch(id: String): Result<User> = try {
249
+ Result.success(fetchUser(id))
250
+ } catch (e: Exception) {
251
+ Result.failure(e)
252
+ }
253
+
254
+ // Flow for streams
255
+ fun observeUsers(): Flow<User> = flow {
256
+ while (true) {
257
+ emit(fetchLatestUser())
258
+ delay(5000)
259
+ }
260
+ }.flowOn(Dispatchers.IO)
261
+
262
+ // Collecting flows
263
+ suspend fun collectUsers() {
264
+ observeUsers()
265
+ .filter { it.isActive }
266
+ .map { it.email }
267
+ .catch { e -> log.error("Error", e) }
268
+ .collect { email -> sendNotification(email) }
269
+ }
270
+
271
+ // StateFlow and SharedFlow
272
+ class UserViewModel {
273
+ private val _users = MutableStateFlow<List<User>>(emptyList())
274
+ val users: StateFlow<List<User>> = _users.asStateFlow()
275
+
276
+ fun loadUsers() {
277
+ viewModelScope.launch {
278
+ _users.value = repository.getUsers()
279
+ }
280
+ }
281
+ }
282
+ \`\`\`
283
+
284
+ ## Spring Boot with Kotlin
285
+ \`\`\`kotlin
286
+ @RestController
287
+ @RequestMapping("/api/v1/users")
288
+ class UserController(
289
+ private val userService: UserService // Constructor injection
290
+ ) {
291
+ @GetMapping
292
+ suspend fun listUsers(): List<UserResponse> =
293
+ userService.findAll()
294
+
295
+ @GetMapping("/{id}")
296
+ suspend fun getUser(@PathVariable id: String): UserResponse =
297
+ userService.findById(id)
298
+ ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
299
+
300
+ @PostMapping
301
+ suspend fun createUser(@Valid @RequestBody request: CreateUserRequest): ResponseEntity<UserResponse> {
302
+ val user = userService.create(request)
303
+ return ResponseEntity.created(URI.create("/api/v1/users/\${user.id}"))
304
+ .body(user)
305
+ }
306
+ }
307
+
308
+ @Service
309
+ class UserService(
310
+ private val userRepository: UserRepository
311
+ ) {
312
+ suspend fun findAll(): List<UserResponse> =
313
+ userRepository.findAll().map { it.toResponse() }
314
+
315
+ suspend fun findById(id: String): UserResponse? =
316
+ userRepository.findById(id)?.toResponse()
317
+
318
+ @Transactional
319
+ suspend fun create(request: CreateUserRequest): UserResponse {
320
+ val user = User(
321
+ email = request.email,
322
+ name = request.name,
323
+ passwordHash = passwordEncoder.encode(request.password)
324
+ )
325
+ return userRepository.save(user).toResponse()
326
+ }
327
+
328
+ private fun User.toResponse() = UserResponse(id, email, name, isActive)
329
+ }
330
+ \`\`\`
331
+
332
+ ## ✅ DO
333
+ - Use \`val\` by default, \`var\` only when necessary
334
+ - Use data classes for DTOs and value objects
335
+ - Use sealed classes for restricted type hierarchies
336
+ - Use scope functions appropriately (let, run, apply, also, with)
337
+ - Use \`?.let\` instead of null checks
338
+ - Use extension functions to enhance readability
339
+ - Use coroutines for async operations
340
+
341
+ ## ❌ DON'T
342
+ - Don't use \`!!\` without good reason (prefer safe calls)
343
+ - Don't use mutable collections when immutable suffice
344
+ - Don't use \`lateinit\` when nullable is appropriate
345
+ - Don't ignore nullability in Java interop
346
+ - Don't block coroutines with blocking calls (use \`withContext(Dispatchers.IO)\`)
347
+ - Don't use \`GlobalScope\` (prefer structured concurrency)