@leejungkiin/awkit 1.0.5 โ†’ 1.0.7

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.
@@ -0,0 +1,268 @@
1
+ # ๐Ÿ”จ Phase 3: Logic Build (Per Feature) โ€” Android
2
+
3
+ > **Zoom Level:** 3 โ€” Code Implementation
4
+ > **Goal:** Code logic behind the APPROVED UI shell for ONE feature.
5
+ > **Input:** Approved Blueprint + Working UI Shell from Phase 2.
6
+ > **Output:** Feature fully wired โ€” UI + logic connected.
7
+
8
+ ---
9
+
10
+ ## โœ… PREREQUISITES
11
+
12
+ Before writing ANY logic code, confirm:
13
+ - [ ] Phase 0 App Map: approved
14
+ - [ ] Phase 1 Architecture Blueprint: approved
15
+ - [ ] Phase 2 Contracts: approved for THIS feature
16
+ - [ ] Phase 2 UI Shell: approved, runs in Preview/device
17
+
18
+ > โš ๏ธ If UI is not approved yet, STOP. Go back to Phase 2.
19
+
20
+ ---
21
+
22
+ ## ๐Ÿ“‹ Implementation Order
23
+
24
+ ### 3.1: Domain Layer
25
+
26
+ Implement from contracts defined in Phase 2:
27
+
28
+ 1. **Models** โ€” data classes (already drafted in 2.2, now create actual files)
29
+ 2. **Repository interfaces** โ€” (already drafted in 2.3, create files)
30
+ 3. **UseCases** โ€” implement invoke() with repository calls
31
+
32
+ ```kotlin
33
+ class LoginUseCase @Inject constructor(
34
+ private val authRepository: AuthRepository
35
+ ) {
36
+ suspend operator fun invoke(email: String, password: String): Result<User> {
37
+ return authRepository.login(email, password)
38
+ }
39
+ }
40
+ ```
41
+
42
+ ### 3.2: Data Layer
43
+
44
+ 1. **DTOs** โ€” @Serializable data classes matching API JSON
45
+ 2. **API interfaces** โ€” Retrofit with correct annotations
46
+ 3. **Room entities + DAOs** (if applicable)
47
+ 4. **DataStore** setup (if applicable)
48
+ 5. **Repository implementation** โ€” offline-first pattern
49
+
50
+ ```kotlin
51
+ class AuthRepositoryImpl @Inject constructor(
52
+ private val api: AuthApi,
53
+ private val tokenStore: TokenDataStore
54
+ ) : AuthRepository {
55
+
56
+ override suspend fun login(email: String, password: String): Result<User> {
57
+ return runCatching {
58
+ val response = api.login(LoginRequest(email, password))
59
+ tokenStore.saveToken(response.accessToken)
60
+ response.user.toDomain()
61
+ }
62
+ }
63
+
64
+ override fun isLoggedIn(): Flow<Boolean> {
65
+ return tokenStore.tokenFlow.map { it.isNotEmpty() }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ### 3.3: DI Module
71
+
72
+ ```kotlin
73
+ @Module
74
+ @InstallIn(SingletonComponent::class)
75
+ abstract class RepositoryModule {
76
+ @Binds
77
+ abstract fun bindAuthRepository(impl: AuthRepositoryImpl): AuthRepository
78
+ }
79
+ ```
80
+
81
+ ### 3.4: ViewModel
82
+
83
+ Implement using UiState + Events + Actions from Phase 2.6:
84
+
85
+ ```kotlin
86
+ @HiltViewModel
87
+ class LoginViewModel @Inject constructor(
88
+ private val loginUseCase: LoginUseCase
89
+ ) : ViewModel() {
90
+
91
+ private val _uiState = MutableStateFlow(LoginUiState())
92
+ val uiState = _uiState.asStateFlow()
93
+
94
+ private val _events = MutableSharedFlow<LoginEvent>()
95
+ val events = _events.asSharedFlow()
96
+
97
+ fun onAction(action: LoginAction) {
98
+ when (action) {
99
+ is LoginAction.UpdateEmail -> _uiState.update { it.copy(email = action.email) }
100
+ is LoginAction.UpdatePassword -> _uiState.update { it.copy(password = action.password) }
101
+ LoginAction.TogglePasswordVisibility -> _uiState.update {
102
+ it.copy(isPasswordVisible = !it.isPasswordVisible)
103
+ }
104
+ LoginAction.Submit -> login()
105
+ }
106
+ }
107
+
108
+ private fun login() {
109
+ viewModelScope.launch {
110
+ _uiState.update { it.copy(isLoading = true, error = null) }
111
+ loginUseCase(uiState.value.email, uiState.value.password)
112
+ .onSuccess { user -> _events.emit(LoginEvent.NavigateToHome(user)) }
113
+ .onFailure { e -> _uiState.update { it.copy(error = e.message, isLoading = false) } }
114
+ }
115
+ }
116
+ }
117
+ ```
118
+
119
+ ### 3.5: Wire UI โ†” Logic โญ (NOT "code new UI")
120
+
121
+ > **This step does NOT create new UI.** The UI already exists from Phase 2.8.
122
+ > Only CONNECT the existing UI shell to the real ViewModel.
123
+
124
+ **Changes needed on the UI shell:**
125
+
126
+ ```kotlin
127
+ // Phase 2 code stays as the STATELESS "Content" composable (for Preview):
128
+ @Composable
129
+ fun LoginScreenContent(
130
+ uiState: LoginUiState = LoginUiState(),
131
+ onAction: (LoginAction) -> Unit = {}
132
+ ) {
133
+ // ... all UI code from Phase 2.8 โ€” DO NOT MODIFY
134
+ }
135
+
136
+ // ADD a NEW wrapper that wires ViewModel:
137
+ @Composable
138
+ fun LoginScreen(
139
+ viewModel: LoginViewModel = hiltViewModel(),
140
+ onNavigateToHome: () -> Unit
141
+ ) {
142
+ val uiState by viewModel.uiState.collectAsStateWithLifecycle()
143
+
144
+ LaunchedEffect(Unit) {
145
+ viewModel.events.collect { event ->
146
+ when (event) {
147
+ is LoginEvent.NavigateToHome -> onNavigateToHome()
148
+ is LoginEvent.ShowSnackbar -> { /* snackbar */ }
149
+ }
150
+ }
151
+ }
152
+
153
+ // Delegate to stateless content composable
154
+ LoginScreenContent(
155
+ uiState = uiState,
156
+ onAction = viewModel::onAction
157
+ )
158
+ }
159
+ ```
160
+
161
+ **Wire Checklist:**
162
+ - [ ] Replace hardcoded defaults โ†’ ViewModel state
163
+ - [ ] Connect UI actions โ†’ ViewModel.onAction()
164
+ - [ ] Bind navigation events
165
+ - [ ] Connect loading/error states
166
+ - [ ] Previews still work (they use the stateless Content composable)
167
+
168
+ ### 3.6: Integration Test โญ
169
+
170
+ Verify UI + logic end-to-end:
171
+
172
+ ```markdown
173
+ ### ๐Ÿงช Integration: [Feature]
174
+
175
+ Functional:
176
+ - [ ] API calls succeed, data displays on UI
177
+ - [ ] Loading state shows/hides at right time
178
+ - [ ] Error state displays correct message
179
+ - [ ] Navigation works as expected
180
+ - [ ] Form validation works
181
+
182
+ Data:
183
+ - [ ] Request format matches original app
184
+ - [ ] Response parses correctly
185
+ - [ ] Token/session stored properly
186
+ - [ ] Crypto output matches original (if applicable)
187
+
188
+ Edge Cases:
189
+ - [ ] Empty input handling
190
+ - [ ] Network error handling
191
+ - [ ] Back navigation
192
+ ```
193
+
194
+ ---
195
+
196
+ ## ๐Ÿ”’ CRYPTO UTILS (Special Handling)
197
+
198
+ If the feature involves encryption/hashing:
199
+
200
+ 1. Read Smali carefully โ€” exact algorithm, padding, encoding
201
+ 2. Implement in Kotlin โ€” preserve exact input/output
202
+ 3. Unit test IMMEDIATELY with known pairs
203
+
204
+ ```kotlin
205
+ object CryptoUtils {
206
+ fun hashMd5(input: String): String {
207
+ val md = MessageDigest.getInstance("MD5")
208
+ return md.digest(input.toByteArray())
209
+ .joinToString("") { "%02x".format(it) }
210
+ }
211
+ }
212
+
213
+ // MANDATORY test
214
+ class CryptoUtilsTest {
215
+ @Test
216
+ fun `md5 matches original app output`() {
217
+ assertEquals("expected_hash", CryptoUtils.hashMd5("known_input"))
218
+ }
219
+ }
220
+ ```
221
+
222
+ > โš ๏ธ Crypto functions MUST produce identical output. Any mismatch breaks server communication.
223
+
224
+ ---
225
+
226
+ ## โœ… Checkpoint
227
+
228
+ ```markdown
229
+ ## โœ… Feature Complete: [Feature Name]
230
+
231
+ ### Files created:
232
+ - domain/model/User.kt
233
+ - domain/repository/AuthRepository.kt
234
+ - domain/usecase/LoginUseCase.kt
235
+ - data/remote/api/AuthApi.kt
236
+ - data/remote/dto/LoginRequest.kt, LoginResponse.kt
237
+ - data/repository/AuthRepositoryImpl.kt
238
+ - di/RepositoryModule.kt
239
+ - presentation/screens/auth/LoginViewModel.kt
240
+ - presentation/screens/auth/LoginScreen.kt โ† wired (from Phase 2)
241
+ - presentation/screens/auth/LoginUiState.kt
242
+
243
+ ### Tests:
244
+ - [ ] Crypto utils verified (if applicable)
245
+ - [ ] API contract matches original
246
+ - [ ] UI + Logic e2e works
247
+
248
+ ### โญ๏ธ Next Feature: [Name]
249
+ โ†’ Return to Phase 2 (Blueprint + UI Design)
250
+ ```
251
+
252
+ ---
253
+
254
+ ## ๐Ÿ”„ Feature Loop
255
+
256
+ ```
257
+ Phase 2 (Blueprint + UI for Feature X) โ†’ GATE โ†’ Phase 3 (Logic for X) โ†’ Checkpoint
258
+ โ†“
259
+ Phase 2 (Blueprint + UI for Feature Y) โ†’ GATE โ†’ Phase 3 (Logic for Y) โ†’ Checkpoint
260
+ โ†“
261
+ ... (repeat for all features from Architecture Build Order)
262
+ โ†“
263
+ Phase 4: Final Parity Check & Quality Gate
264
+ ```
265
+
266
+ ---
267
+
268
+ *Phase 3: Logic Build โ€” Wire logic behind approved UI*