android-sdd 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.
Files changed (176) hide show
  1. package/dist/index.js +143 -0
  2. package/package.json +27 -0
  3. package/skills/Android Ecosystem/Baseline Profile Generator/SKILL.md +277 -0
  4. package/skills/Android Ecosystem/Glance/SKILL.md +315 -0
  5. package/skills/Android Platform/Configuration/SKILL.md +201 -0
  6. package/skills/Android Platform/Filesystem/SKILL.md +216 -0
  7. package/skills/Android Platform/Lifecycle/SKILL.md +233 -0
  8. package/skills/Android Platform/Manifest/SKILL.md +226 -0
  9. package/skills/Android Platform/Process Death Recovery/SKILL.md +214 -0
  10. package/skills/Android Platform/Resources/SKILL.md +234 -0
  11. package/skills/Android Platform/SavedStateHandle/SKILL.md +217 -0
  12. package/skills/Android Platform/State Restoration/SKILL.md +210 -0
  13. package/skills/Architecture/Bounded Context/SKILL.md +207 -0
  14. package/skills/Architecture/Clean Architecture/SKILL.md +229 -0
  15. package/skills/Architecture/Domain Modeling/SKILL.md +236 -0
  16. package/skills/Architecture/Entity Design/SKILL.md +243 -0
  17. package/skills/Architecture/Feature Isolation/SKILL.md +216 -0
  18. package/skills/Architecture/MVI/SKILL.md +224 -0
  19. package/skills/Architecture/MVVM/SKILL.md +198 -0
  20. package/skills/Architecture/Modularization/SKILL.md +194 -0
  21. package/skills/Architecture/Offline First/SKILL.md +249 -0
  22. package/skills/Architecture/Repository Pattern/SKILL.md +216 -0
  23. package/skills/Architecture/Side Effect Management/SKILL.md +278 -0
  24. package/skills/Architecture/State Management/SKILL.md +229 -0
  25. package/skills/Architecture/Unidirectional Data Flow/SKILL.md +196 -0
  26. package/skills/Architecture/Use Case Design/SKILL.md +244 -0
  27. package/skills/Architecture/Value Object/SKILL.md +226 -0
  28. package/skills/Build Infrastructure/Build Orchestration/SKILL.md +257 -0
  29. package/skills/Build Infrastructure/Dependency Compatibility Resolver/SKILL.md +259 -0
  30. package/skills/Build Infrastructure/Environment Validator/SKILL.md +311 -0
  31. package/skills/Build System/Build Cache/SKILL.md +233 -0
  32. package/skills/Build System/Build Flavor Strategy/SKILL.md +171 -0
  33. package/skills/Build System/Build Variant/SKILL.md +215 -0
  34. package/skills/Build System/Convention Plugin/SKILL.md +288 -0
  35. package/skills/Build System/Dependency Management/SKILL.md +261 -0
  36. package/skills/Build System/Gradle/SKILL.md +284 -0
  37. package/skills/Build System/Incremental Build/SKILL.md +199 -0
  38. package/skills/Build System/KAPT/SKILL.md +198 -0
  39. package/skills/Build System/KSP/SKILL.md +263 -0
  40. package/skills/Build System/Module Dependency Graph Validation/SKILL.md +223 -0
  41. package/skills/Build System/Specialized/C++/SKILL.md +308 -0
  42. package/skills/Build System/Specialized/JNI/SKILL.md +306 -0
  43. package/skills/Build System/Specialized/NDK/SKILL.md +264 -0
  44. package/skills/Build System/Version Catalog/SKILL.md +304 -0
  45. package/skills/Concurrency/Background Processing/SKILL.md +185 -0
  46. package/skills/Concurrency/Channel/SKILL.md +207 -0
  47. package/skills/Concurrency/Coroutine/SKILL.md +200 -0
  48. package/skills/Concurrency/Flow/SKILL.md +179 -0
  49. package/skills/Concurrency/Mutex Strategy/SKILL.md +185 -0
  50. package/skills/Concurrency/SharedFlow/SKILL.md +171 -0
  51. package/skills/Concurrency/StateFlow/SKILL.md +175 -0
  52. package/skills/Concurrency/Structured Concurrency/SKILL.md +197 -0
  53. package/skills/Concurrency/Synchronization Policy/SKILL.md +192 -0
  54. package/skills/Core Language/Annotation Processing/SKILL.md +224 -0
  55. package/skills/Core Language/DSL/SKILL.md +186 -0
  56. package/skills/Core Language/Extension Functions Design/SKILL.md +191 -0
  57. package/skills/Core Language/Immutability/SKILL.md +156 -0
  58. package/skills/Core Language/KMP/SKILL.md +182 -0
  59. package/skills/Core Language/Kotlin/SKILL.md +187 -0
  60. package/skills/Core Language/Reactive State Management/SKILL.md +228 -0
  61. package/skills/Core Language/Reactive Streams/SKILL.md +235 -0
  62. package/skills/Core Language/Serialization/SKILL.md +191 -0
  63. package/skills/Data Layer/Cache Strategy/SKILL.md +261 -0
  64. package/skills/Data Layer/Conflict Resolution/SKILL.md +248 -0
  65. package/skills/Data Layer/DAO/SKILL.md +225 -0
  66. package/skills/Data Layer/DTO Mapping/SKILL.md +269 -0
  67. package/skills/Data Layer/DataStore/SKILL.md +264 -0
  68. package/skills/Data Layer/Database Versioning Strategy/SKILL.md +215 -0
  69. package/skills/Data Layer/Encrypted Database/SKILL.md +212 -0
  70. package/skills/Data Layer/File Storage/SKILL.md +247 -0
  71. package/skills/Data Layer/Indexing/SKILL.md +184 -0
  72. package/skills/Data Layer/Key-Value Store Strategy/SKILL.md +185 -0
  73. package/skills/Data Layer/Merge Strategy/SKILL.md +240 -0
  74. package/skills/Data Layer/Migration/SKILL.md +243 -0
  75. package/skills/Data Layer/Paging/SKILL.md +264 -0
  76. package/skills/Data Layer/Proto DataStore/SKILL.md +250 -0
  77. package/skills/Data Layer/Room/SKILL.md +244 -0
  78. package/skills/Data Layer/SQLite/SKILL.md +255 -0
  79. package/skills/Data Layer/Sync Engine/SKILL.md +268 -0
  80. package/skills/Dependency Injection/Dagger/SKILL.md +283 -0
  81. package/skills/Dependency Injection/Hilt/SKILL.md +345 -0
  82. package/skills/Dependency Injection/Koin/SKILL.md +282 -0
  83. package/skills/Developer Experience/Detekt/SKILL.md +272 -0
  84. package/skills/Developer Experience/Lint Rule/SKILL.md +281 -0
  85. package/skills/Google Ecosystem/Analytics/SKILL.md +281 -0
  86. package/skills/Google Ecosystem/Crashlytics/SKILL.md +234 -0
  87. package/skills/Google Ecosystem/Firebase/SKILL.md +200 -0
  88. package/skills/Google Ecosystem/Firebase Messaging/SKILL.md +266 -0
  89. package/skills/Media/Audio/SKILL.md +257 -0
  90. package/skills/Media/Camera/SKILL.md +229 -0
  91. package/skills/Media/CameraX/SKILL.md +295 -0
  92. package/skills/Media/ExoPlayer/SKILL.md +258 -0
  93. package/skills/Media/Video/SKILL.md +228 -0
  94. package/skills/Meta Skills/Domain Error Model/SKILL.md +238 -0
  95. package/skills/Meta Skills/Error Handling/SKILL.md +255 -0
  96. package/skills/Meta Skills/Error Mapping/SKILL.md +232 -0
  97. package/skills/Meta Skills/Failure Strategy/SKILL.md +294 -0
  98. package/skills/Meta Skills/Migration Strategy/SKILL.md +305 -0
  99. package/skills/Meta Skills/User Friendly Errors/SKILL.md +334 -0
  100. package/skills/Navigation/Deep Navigation/SKILL.md +209 -0
  101. package/skills/Navigation/Navigation/SKILL.md +215 -0
  102. package/skills/Navigation/Nested Navigation/SKILL.md +214 -0
  103. package/skills/Networking/API Contract/SKILL.md +220 -0
  104. package/skills/Networking/Authentication/SKILL.md +210 -0
  105. package/skills/Networking/Certificate Pinning/SKILL.md +167 -0
  106. package/skills/Networking/Fallback Strategy/SKILL.md +182 -0
  107. package/skills/Networking/Ktor/SKILL.md +219 -0
  108. package/skills/Networking/Multipart Upload/SKILL.md +213 -0
  109. package/skills/Networking/OkHttp/SKILL.md +193 -0
  110. package/skills/Networking/REST/SKILL.md +178 -0
  111. package/skills/Networking/Rate Limiting/SKILL.md +170 -0
  112. package/skills/Networking/Retrofit/SKILL.md +241 -0
  113. package/skills/Networking/Retry-Backoff/SKILL.md +181 -0
  114. package/skills/Networking/Server-Sent Events (SSE)/SKILL.md +196 -0
  115. package/skills/Networking/WebSocket/SKILL.md +224 -0
  116. package/skills/Observability/Crash Reporting/SKILL.md +219 -0
  117. package/skills/Observability/Logging/SKILL.md +168 -0
  118. package/skills/Observability/Metrics/SKILL.md +227 -0
  119. package/skills/Observability/Structured Logging/SKILL.md +234 -0
  120. package/skills/Performance/ANR Prevention/SKILL.md +192 -0
  121. package/skills/Performance/Allocation Optimization/SKILL.md +179 -0
  122. package/skills/Performance/App Startup/SKILL.md +183 -0
  123. package/skills/Performance/Baseline Profile/SKILL.md +205 -0
  124. package/skills/Performance/Battery Optimization/SKILL.md +192 -0
  125. package/skills/Performance/Benchmark/SKILL.md +182 -0
  126. package/skills/Performance/Bitmap Optimization/SKILL.md +178 -0
  127. package/skills/Performance/Compose Optimization/SKILL.md +187 -0
  128. package/skills/Performance/Heap Management/SKILL.md +184 -0
  129. package/skills/Performance/Macrobenchmark/SKILL.md +214 -0
  130. package/skills/Performance/Memory Leak Prevention/SKILL.md +218 -0
  131. package/skills/Performance/Rendering Performance/SKILL.md +205 -0
  132. package/skills/Performance/Startup Optimization/SKILL.md +219 -0
  133. package/skills/Security/Biometric/SKILL.md +224 -0
  134. package/skills/Security/Certificate Transparency/SKILL.md +158 -0
  135. package/skills/Security/Cryptography/SKILL.md +244 -0
  136. package/skills/Security/Encrypted Storage/SKILL.md +273 -0
  137. package/skills/Security/Frida Detection/SKILL.md +230 -0
  138. package/skills/Security/Hook Detection/SKILL.md +197 -0
  139. package/skills/Security/Keystore/SKILL.md +272 -0
  140. package/skills/Security/Network Security Config/SKILL.md +186 -0
  141. package/skills/Security/Obfuscation/SKILL.md +226 -0
  142. package/skills/Security/Proguard/SKILL.md +202 -0
  143. package/skills/Security/R8/SKILL.md +234 -0
  144. package/skills/Security/Reverse Engineering Resistance/SKILL.md +267 -0
  145. package/skills/Security/Root Detection/SKILL.md +220 -0
  146. package/skills/Security/Secure Networking/SKILL.md +220 -0
  147. package/skills/System Integration/AlarmManager/SKILL.md +182 -0
  148. package/skills/System Integration/App Widget/SKILL.md +182 -0
  149. package/skills/System Integration/Deep Link/SKILL.md +187 -0
  150. package/skills/System Integration/Foreground Service/SKILL.md +212 -0
  151. package/skills/System Integration/Notification/SKILL.md +237 -0
  152. package/skills/System Integration/WorkManager/SKILL.md +256 -0
  153. package/skills/System Integration/clipboard/SKILL.md +155 -0
  154. package/skills/System Integration/share-intent/SKILL.md +182 -0
  155. package/skills/Testing/Compose Testing/SKILL.md +296 -0
  156. package/skills/Testing/Espresso/SKILL.md +292 -0
  157. package/skills/Testing/Fake Data/SKILL.md +245 -0
  158. package/skills/Testing/Integration Testing/SKILL.md +288 -0
  159. package/skills/Testing/Mocking/SKILL.md +229 -0
  160. package/skills/Testing/Snapshot Testing/SKILL.md +259 -0
  161. package/skills/Testing/UI Testing/SKILL.md +293 -0
  162. package/skills/Testing/Unit Testing/SKILL.md +309 -0
  163. package/skills/UI System/Bottom Sheet Patterns/SKILL.md +279 -0
  164. package/skills/UI System/Compose/SKILL.md +296 -0
  165. package/skills/UI System/Compose Animation/SKILL.md +281 -0
  166. package/skills/UI System/Compose Multiplatform/SKILL.md +261 -0
  167. package/skills/UI System/Compose Navigation/SKILL.md +255 -0
  168. package/skills/UI System/Compose Performance/SKILL.md +274 -0
  169. package/skills/UI System/Design System/SKILL.md +217 -0
  170. package/skills/UI System/Empty State Strategy/SKILL.md +208 -0
  171. package/skills/UI System/Keyboard Navigation/SKILL.md +214 -0
  172. package/skills/UI System/Loading Strategy/SKILL.md +254 -0
  173. package/skills/UI System/Material 3/SKILL.md +279 -0
  174. package/skills/UI System/RTL/SKILL.md +179 -0
  175. package/src/index.ts +182 -0
  176. package/tsconfig.json +19 -0
@@ -0,0 +1,225 @@
1
+ ---
2
+ name: dao
3
+ description: >
4
+ Room DAO design — queries, inserts, updates, deletes, transactions, and Flow.
5
+ Load this skill when writing DAO interfaces, designing SQL queries,
6
+ handling reactive queries with Flow, or performing batch operations.
7
+ ---
8
+
9
+ # DAO (Data Access Object)
10
+
11
+ ## Overview
12
+ A DAO is the interface through which the app accesses the Room database. It defines the contract between the app and the database — what queries to run, what data to return, and how writes happen. DAOs are generated at compile time and SQL is verified at compile time.
13
+
14
+ ---
15
+
16
+ ## Core Principles
17
+
18
+ - DAOs are **interfaces or abstract classes** — never concrete classes
19
+ - Use **Flow** for observable queries — use **suspend** for one-shot operations
20
+ - Prefer **upsert** over separate insert + update logic
21
+ - Keep queries **focused** — one query, one purpose
22
+ - Use **@Transaction** for operations that must be atomic
23
+
24
+ ---
25
+
26
+ ## Basic DAO Structure
27
+
28
+ ```kotlin
29
+ @Dao
30
+ interface UserDao {
31
+
32
+ // ✅ Observable query — Flow
33
+ @Query("SELECT * FROM users ORDER BY full_name ASC")
34
+ fun observeAll(): Flow<List<UserEntity>>
35
+
36
+ // ✅ Observable single item
37
+ @Query("SELECT * FROM users WHERE id = :id")
38
+ fun observeById(id: String): Flow<UserEntity?>
39
+
40
+ // ✅ One-shot query
41
+ @Query("SELECT * FROM users WHERE id = :id")
42
+ suspend fun getById(id: String): UserEntity?
43
+
44
+ // ✅ Upsert — insert or replace on conflict
45
+ @Upsert
46
+ suspend fun upsert(user: UserEntity)
47
+
48
+ @Upsert
49
+ suspend fun upsertAll(users: List<UserEntity>)
50
+
51
+ // ✅ Insert with conflict strategy
52
+ @Insert(onConflict = OnConflictStrategy.IGNORE)
53
+ suspend fun insertIfNotExists(user: UserEntity)
54
+
55
+ // ✅ Update
56
+ @Update
57
+ suspend fun update(user: UserEntity)
58
+
59
+ // ✅ Delete by entity
60
+ @Delete
61
+ suspend fun delete(user: UserEntity)
62
+
63
+ // ✅ Delete by ID
64
+ @Query("DELETE FROM users WHERE id = :id")
65
+ suspend fun deleteById(id: String)
66
+
67
+ // ✅ Delete all
68
+ @Query("DELETE FROM users")
69
+ suspend fun deleteAll()
70
+ }
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Filtered and Sorted Queries
76
+
77
+ ```kotlin
78
+ @Dao
79
+ interface UserDao {
80
+
81
+ // ✅ Filter by column
82
+ @Query("SELECT * FROM users WHERE status = :status ORDER BY full_name ASC")
83
+ fun observeByStatus(status: String): Flow<List<UserEntity>>
84
+
85
+ // ✅ Search with LIKE
86
+ @Query("SELECT * FROM users WHERE full_name LIKE '%' || :query || '%' OR email LIKE '%' || :query || '%'")
87
+ fun search(query: String): Flow<List<UserEntity>>
88
+
89
+ // ✅ Filter with IN clause
90
+ @Query("SELECT * FROM users WHERE id IN (:ids)")
91
+ suspend fun getByIds(ids: List<String>): List<UserEntity>
92
+
93
+ // ✅ Count
94
+ @Query("SELECT COUNT(*) FROM users WHERE status = :status")
95
+ fun observeCountByStatus(status: String): Flow<Int>
96
+
97
+ // ✅ Exists check
98
+ @Query("SELECT EXISTS(SELECT 1 FROM users WHERE email = :email)")
99
+ suspend fun existsByEmail(email: String): Boolean
100
+
101
+ // ✅ Pagination with LIMIT and OFFSET
102
+ @Query("SELECT * FROM users ORDER BY created_at DESC LIMIT :limit OFFSET :offset")
103
+ suspend fun getPage(limit: Int, offset: Int): List<UserEntity>
104
+ }
105
+ ```
106
+
107
+ ---
108
+
109
+ ## Joins and Relations
110
+
111
+ ```kotlin
112
+ @Dao
113
+ interface UserDao {
114
+
115
+ // ✅ Join query — returns a POJO (not entity)
116
+ @Query("""
117
+ SELECT u.*, o.id as order_id, o.total as order_total
118
+ FROM users u
119
+ INNER JOIN orders o ON u.id = o.user_id
120
+ WHERE u.id = :userId
121
+ """)
122
+ suspend fun getUserWithOrders(userId: String): UserWithOrdersEntity?
123
+
124
+ // ✅ @Transaction for relation queries
125
+ @Transaction
126
+ @Query("SELECT * FROM users WHERE id = :userId")
127
+ suspend fun getUserWithProfile(userId: String): UserWithProfileEntity?
128
+
129
+ // ✅ @Transaction for all @Relation queries
130
+ @Transaction
131
+ @Query("SELECT * FROM users")
132
+ fun observeAllWithOrders(): Flow<List<UserWithOrdersEntity>>
133
+ }
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Transactions
139
+
140
+ ```kotlin
141
+ @Dao
142
+ interface UserDao {
143
+
144
+ // ✅ @Transaction — atomic multi-step operation
145
+ @Transaction
146
+ suspend fun replaceAll(users: List<UserEntity>) {
147
+ deleteAll()
148
+ upsertAll(users)
149
+ }
150
+
151
+ @Transaction
152
+ suspend fun transferOrders(fromUserId: String, toUserId: String) {
153
+ updateOrderOwner(fromUserId, toUserId)
154
+ updateUserOrderCount(fromUserId)
155
+ updateUserOrderCount(toUserId)
156
+ }
157
+
158
+ @Query("UPDATE orders SET user_id = :toUserId WHERE user_id = :fromUserId")
159
+ suspend fun updateOrderOwner(fromUserId: String, toUserId: String)
160
+
161
+ @Query("UPDATE users SET order_count = (SELECT COUNT(*) FROM orders WHERE user_id = :userId) WHERE id = :userId")
162
+ suspend fun updateUserOrderCount(userId: String)
163
+ }
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Return Types Reference
169
+
170
+ | Operation | Return Type |
171
+ |-----------|------------|
172
+ | Observable query (list) | `Flow<List<Entity>>` |
173
+ | Observable query (single) | `Flow<Entity?>` |
174
+ | Observable count | `Flow<Int>` |
175
+ | One-shot query | `suspend fun`: `Entity?`, `List<Entity>` |
176
+ | Insert | `suspend fun`: `Long` (row id) or `Unit` |
177
+ | Upsert | `suspend fun`: `Unit` |
178
+ | Update | `suspend fun`: `Int` (rows affected) or `Unit` |
179
+ | Delete | `suspend fun`: `Int` (rows affected) or `Unit` |
180
+
181
+ ---
182
+
183
+ ## POJOs for Custom Queries
184
+
185
+ ```kotlin
186
+ // ✅ POJO for projection queries — not an @Entity
187
+ data class UserSummary(
188
+ val id: String,
189
+ @ColumnInfo(name = "full_name") val name: String,
190
+ @ColumnInfo(name = "order_count") val orderCount: Int
191
+ )
192
+
193
+ @Dao
194
+ interface UserDao {
195
+ @Query("""
196
+ SELECT u.id, u.full_name, COUNT(o.id) as order_count
197
+ FROM users u
198
+ LEFT JOIN orders o ON u.id = o.user_id
199
+ GROUP BY u.id
200
+ ORDER BY order_count DESC
201
+ """)
202
+ fun observeUserSummaries(): Flow<List<UserSummary>>
203
+ }
204
+ ```
205
+
206
+ ---
207
+
208
+ ## Anti-Patterns
209
+
210
+ - Returning entities directly from Repository — always map to domain models
211
+ - Using `LiveData` instead of `Flow` in new code — Flow is preferred
212
+ - Missing `@Transaction` on `@Relation` queries — causes inconsistent data reads
213
+ - Using `suspend` for observable queries — use `Flow` instead
214
+ - Writing business logic in SQL queries — keep queries data-focused
215
+ - Not using `@Upsert` when insert-or-update is needed — avoids conflict handling mistakes
216
+ - Large `IN` clauses with dynamic lists — SQLite has limits; batch if needed
217
+
218
+ ---
219
+
220
+ ## Related Skills
221
+ - `room` — Room database setup and configuration
222
+ - `migration` — schema changes and migrations
223
+ - `dto-mapping` — Entity ↔ Domain model mapping
224
+ - `repository-pattern` — Repository wrapping DAOs
225
+ - `coroutine` — Dispatchers.IO for DAO operations
@@ -0,0 +1,269 @@
1
+ ---
2
+ name: dto-mapping
3
+ description: >
4
+ DTO to domain model mapping patterns for Android.
5
+ Load this skill when writing mappers between API responses (DTOs),
6
+ database entities, and domain models — or when designing the data
7
+ layer boundary in a clean architecture project.
8
+ ---
9
+
10
+ # DTO Mapping
11
+
12
+ ## Overview
13
+ DTO (Data Transfer Object) mapping is the translation between data representations across layer boundaries. API responses (DTOs), database rows (Entities), and domain models are separate types — mapping between them keeps each layer independent and testable.
14
+
15
+ ---
16
+
17
+ ## Core Principles
18
+
19
+ - **Domain models are the language of business logic** — pure Kotlin, no framework annotations
20
+ - **DTOs mirror the API contract** — annotated with `@Serializable`, snake_case fields
21
+ - **Entities mirror the DB schema** — annotated with `@Entity`, `@ColumnInfo`
22
+ - Mapping always happens at the **repository layer** — never in ViewModel or UseCase
23
+ - Mappers are **pure functions** — no side effects, no dependencies
24
+
25
+ ---
26
+
27
+ ## Layer Boundaries
28
+
29
+ ```
30
+ Network (JSON) DTO @Serializable
31
+ ↓ mapper
32
+ Domain Layer Domain Model Pure Kotlin data class
33
+ ↓ mapper
34
+ Database (SQLite) Entity @Entity, @ColumnInfo
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Domain Model
40
+
41
+ ```kotlin
42
+ // ✅ Pure Kotlin — no framework dependencies
43
+ data class User(
44
+ val id: String,
45
+ val name: String,
46
+ val email: String,
47
+ val status: UserStatus,
48
+ val createdAt: Instant
49
+ )
50
+
51
+ enum class UserStatus { ACTIVE, INACTIVE, PENDING }
52
+ ```
53
+
54
+ ---
55
+
56
+ ## DTO (API Response)
57
+
58
+ ```kotlin
59
+ // ✅ Mirrors API contract — annotated for serialization
60
+ @Serializable
61
+ data class UserDto(
62
+ @SerialName("user_id") val id: String,
63
+ @SerialName("full_name") val name: String,
64
+ @SerialName("email_address") val email: String,
65
+ @SerialName("account_status") val status: String,
66
+ @SerialName("created_timestamp") val createdAt: Long
67
+ )
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Entity (Database Row)
73
+
74
+ ```kotlin
75
+ // ✅ Mirrors DB schema — annotated for Room
76
+ @Entity(tableName = "users")
77
+ data class UserEntity(
78
+ @PrimaryKey val id: String,
79
+ @ColumnInfo(name = "full_name") val name: String,
80
+ @ColumnInfo(name = "email") val email: String,
81
+ @ColumnInfo(name = "status") val status: String,
82
+ @ColumnInfo(name = "created_at") val createdAt: Long
83
+ )
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Mapper — Extension Functions (Simple)
89
+
90
+ ```kotlin
91
+ // ✅ Extension function mapper — concise for simple cases
92
+ fun UserDto.toDomain(): User = User(
93
+ id = id,
94
+ name = name,
95
+ email = email,
96
+ status = UserStatus.valueOf(status.uppercase()),
97
+ createdAt = Instant.ofEpochMilli(createdAt)
98
+ )
99
+
100
+ fun UserEntity.toDomain(): User = User(
101
+ id = id,
102
+ name = name,
103
+ email = email,
104
+ status = UserStatus.valueOf(status),
105
+ createdAt = Instant.ofEpochMilli(createdAt)
106
+ )
107
+
108
+ fun User.toEntity(): UserEntity = UserEntity(
109
+ id = id,
110
+ name = name,
111
+ email = email,
112
+ status = status.name,
113
+ createdAt = createdAt.toEpochMilli()
114
+ )
115
+
116
+ fun User.toDto(): UserDto = UserDto(
117
+ id = id,
118
+ name = name,
119
+ email = email,
120
+ status = status.name.lowercase(),
121
+ createdAt = createdAt.toEpochMilli()
122
+ )
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Mapper — Class-Based (Testable, Injectable)
128
+
129
+ ```kotlin
130
+ // ✅ Class mapper — preferred when mapping has dependencies or is complex
131
+ class UserMapper @Inject constructor(
132
+ private val clock: Clock = Clock.systemUTC()
133
+ ) {
134
+ fun toDomain(dto: UserDto): User = User(
135
+ id = dto.id,
136
+ name = dto.name.trim(),
137
+ email = dto.email.lowercase(),
138
+ status = mapStatus(dto.status),
139
+ createdAt = Instant.ofEpochMilli(dto.createdAt)
140
+ )
141
+
142
+ fun toDomain(entity: UserEntity): User = User(
143
+ id = entity.id,
144
+ name = entity.name,
145
+ email = entity.email,
146
+ status = UserStatus.valueOf(entity.status),
147
+ createdAt = Instant.ofEpochMilli(entity.createdAt)
148
+ )
149
+
150
+ fun toEntity(domain: User): UserEntity = UserEntity(
151
+ id = domain.id,
152
+ name = domain.name,
153
+ email = domain.email,
154
+ status = domain.status.name,
155
+ createdAt = domain.createdAt.toEpochMilli()
156
+ )
157
+
158
+ private fun mapStatus(raw: String): UserStatus = when (raw.lowercase()) {
159
+ "active" -> UserStatus.ACTIVE
160
+ "inactive" -> UserStatus.INACTIVE
161
+ else -> UserStatus.PENDING
162
+ }
163
+ }
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Repository Using Mapper
169
+
170
+ ```kotlin
171
+ class UserRepository @Inject constructor(
172
+ private val userApi: UserApi,
173
+ private val userDao: UserDao,
174
+ private val userMapper: UserMapper
175
+ ) {
176
+
177
+ fun observeUsers(): Flow<List<User>> =
178
+ userDao.observeAll()
179
+ .map { entities -> entities.map(userMapper::toDomain) }
180
+
181
+ suspend fun refreshUsers() {
182
+ val dtos = userApi.getUsers()
183
+ val entities = dtos.map(userMapper::toEntity)
184
+ userDao.upsertAll(entities)
185
+ }
186
+
187
+ suspend fun createUser(user: User): User {
188
+ val dto = userApi.createUser(user.toDto())
189
+ val entity = userMapper.toEntity(userMapper.toDomain(dto))
190
+ userDao.upsert(entity)
191
+ return userMapper.toDomain(dto)
192
+ }
193
+ }
194
+ ```
195
+
196
+ ---
197
+
198
+ ## Handling Nullable / Missing Fields
199
+
200
+ ```kotlin
201
+ // ✅ Provide sensible defaults — never return null for required domain fields
202
+ fun UserDto.toDomain(): User = User(
203
+ id = id,
204
+ name = name.takeIf { it.isNotBlank() } ?: "Unknown",
205
+ email = email,
206
+ status = runCatching { UserStatus.valueOf(status.uppercase()) }
207
+ .getOrDefault(UserStatus.PENDING),
208
+ createdAt = if (createdAt > 0) Instant.ofEpochMilli(createdAt) else Instant.now()
209
+ )
210
+ ```
211
+
212
+ ---
213
+
214
+ ## Testing Mappers
215
+
216
+ ```kotlin
217
+ // ✅ Mappers are pure — easy to unit test without mocks
218
+ class UserMapperTest {
219
+
220
+ private val mapper = UserMapper()
221
+
222
+ @Test
223
+ fun `DTO maps to domain correctly`() {
224
+ val dto = UserDto(
225
+ id = "1",
226
+ name = "Ali Rezaei",
227
+ email = "ali@example.com",
228
+ status = "active",
229
+ createdAt = 1_700_000_000_000L
230
+ )
231
+
232
+ val domain = mapper.toDomain(dto)
233
+
234
+ assertEquals("1", domain.id)
235
+ assertEquals("Ali Rezaei", domain.name)
236
+ assertEquals(UserStatus.ACTIVE, domain.status)
237
+ }
238
+
239
+ @Test
240
+ fun `domain maps to entity and back`() {
241
+ val user = User("1", "Ali", "ali@example.com", UserStatus.ACTIVE, Instant.now())
242
+ val entity = mapper.toEntity(user)
243
+ val restored = mapper.toDomain(entity)
244
+
245
+ assertEquals(user.id, restored.id)
246
+ assertEquals(user.status, restored.status)
247
+ }
248
+ }
249
+ ```
250
+
251
+ ---
252
+
253
+ ## Anti-Patterns
254
+
255
+ - Using DTOs directly in ViewModel or Compose — couples UI to API contract
256
+ - Using Entities in domain or UI layer — couples business logic to DB schema
257
+ - Mapping in ViewModel — mapping belongs in repository/data layer
258
+ - Not handling unknown enum values — crashes when API adds a new status
259
+ - Giant mapper files — split by domain entity
260
+ - Returning `null` for required domain fields — use defaults or `Result<T>`
261
+
262
+ ---
263
+
264
+ ## Related Skills
265
+ - `serialization` — DTO serialization setup
266
+ - `room` — Entity design and Room setup
267
+ - `repository-pattern` — repository using mappers
268
+ - `entity-design` — designing domain entities
269
+ - `domain-modeling` — domain model design principles