@leejungkiin/awkit 1.0.6 → 1.0.8
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/VERSION +1 -1
- package/core/GEMINI.md.bak +168 -181
- package/package.json +2 -2
- package/schemas/brain-snapshot.json +167 -0
- package/skills/CATALOG.md +70 -0
- package/skills/beads-manager/SKILL.md +20 -1
- package/skills/memory-sync/SKILL.md +20 -2
- package/skills/nm-memory-audit/SKILL.md +157 -0
- package/skills/nm-memory-evolution/SKILL.md +202 -0
- package/skills/nm-memory-intake/SKILL.md +135 -0
- package/skills/nm-memory-sync/SKILL.md +184 -0
- package/skills/orchestrator/SKILL.md +41 -50
- package/skills/schemas/brain-snapshot.json +167 -0
- package/skills/skills/nm-memory-audit/SKILL.md +157 -0
- package/skills/skills/nm-memory-evolution/SKILL.md +202 -0
- package/skills/skills/nm-memory-intake/SKILL.md +135 -0
- package/skills/skills/nm-memory-sync/SKILL.md +184 -0
- package/skills/smali-to-kotlin/phase-0-discovery.md +128 -0
- package/skills/smali-to-kotlin/phase-1-architecture.md +166 -0
- package/skills/smali-to-kotlin/phase-2-blueprint-ui.md +347 -0
- package/skills/smali-to-kotlin/phase-2-blueprint.md +228 -0
- package/skills/smali-to-kotlin/phase-3-build.md +248 -0
- package/skills/smali-to-kotlin/phase-3-logic-build.md +268 -0
- package/skills/smali-to-kotlin/templates/app-map.md +101 -0
- package/skills/smali-to-kotlin/templates/architecture.md +142 -0
- package/skills/smali-to-kotlin/templates/blueprint.md +145 -0
- package/skills/smali-to-swift/phase-0-discovery.md +137 -0
- package/skills/smali-to-swift/phase-1-architecture.md +168 -0
- package/skills/smali-to-swift/phase-2-blueprint-ui.md +348 -0
- package/skills/smali-to-swift/phase-2-blueprint.md +173 -0
- package/skills/smali-to-swift/phase-3-build.md +257 -0
- package/skills/smali-to-swift/phase-3-logic-build.md +312 -0
- package/skills/smali-to-swift/templates/app-map.md +82 -0
- package/skills/smali-to-swift/templates/architecture.md +97 -0
- package/skills/smali-to-swift/templates/blueprint.md +82 -0
- package/skills/workflows/nm-import.md +73 -0
- package/skills/workflows/nm-recall.md +67 -0
- package/skills/workflows/nm-snapshot.md +69 -0
- package/workflows/_uncategorized/nm-import.md +73 -0
- package/workflows/_uncategorized/nm-recall.md +67 -0
- package/workflows/_uncategorized/nm-snapshot.md +69 -0
- package/workflows/_uncategorized/reverse-android-build.md +222 -0
- package/workflows/_uncategorized/reverse-android-design.md +139 -0
- package/workflows/_uncategorized/reverse-android-discover.md +150 -0
- package/workflows/_uncategorized/reverse-android-scan.md +158 -0
- package/workflows/_uncategorized/reverse-android.md +143 -0
- package/workflows/_uncategorized/reverse-ios-build.md +240 -0
- package/workflows/_uncategorized/reverse-ios-design.md +112 -0
- package/workflows/_uncategorized/reverse-ios-discover.md +120 -0
- package/workflows/_uncategorized/reverse-ios-scan.md +155 -0
- package/workflows/_uncategorized/reverse-ios.md +152 -0
- package/workflows/mobile/reverse-android-build.md +119 -79
- package/workflows/mobile/reverse-android-design.md +10 -7
- package/workflows/mobile/reverse-android.md +52 -46
- package/workflows/mobile/reverse-ios-build.md +161 -50
- package/workflows/mobile/reverse-ios-design.md +10 -1
- package/workflows/mobile/reverse-ios.md +49 -37
- package/skills/adaptive-language/SKILL.md +0 -189
- package/skills/ambient-brain/SKILL.md +0 -314
- package/skills/ambient-brain/brain-router.md +0 -185
- package/skills/ambient-brain/brain-templates.md +0 -201
- package/skills/context-help/SKILL.md +0 -180
- package/skills/error-translator/SKILL.md +0 -153
- package/skills/session-restore/SKILL.md +0 -240
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# 📐 Phase 2: Blueprint (Block View — per feature)
|
|
2
|
+
|
|
3
|
+
> **Zoom Level:** 2 — Feature Detail
|
|
4
|
+
> **Goal:** Design contracts, interfaces, and state for ONE specific feature.
|
|
5
|
+
> **Input:** Architecture Blueprint (Phase 1) + user's chosen feature.
|
|
6
|
+
> **Output:** Feature Blueprint with code signatures. **NO implementation bodies yet.**
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## ⛔ OUTPUT RULE
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
✅ ALLOWED: Interface/protocol signatures, data class definitions, sealed classes
|
|
14
|
+
✅ ALLOWED: Retrofit interface with @GET/@POST annotations (no body)
|
|
15
|
+
✅ ALLOWED: UiState sealed class, Event sealed class
|
|
16
|
+
❌ BLOCKED: Function body implementations (use TODO() or // ... )
|
|
17
|
+
❌ BLOCKED: Full ViewModel logic, full Composable implementations
|
|
18
|
+
⚠️ EXCEPTION: Simple data class fields are OK (they ARE the contract)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 📋 Sub-steps (per feature)
|
|
24
|
+
|
|
25
|
+
### 2.1: Deep Smali Reading
|
|
26
|
+
|
|
27
|
+
Read the Smali/Java files specifically for the chosen feature.
|
|
28
|
+
|
|
29
|
+
**What to extract:**
|
|
30
|
+
- Class hierarchy (extends, implements)
|
|
31
|
+
- Field declarations → model properties
|
|
32
|
+
- Method signatures → API contracts
|
|
33
|
+
- String constants → URLs, keys, messages
|
|
34
|
+
- Control flow → business rules (document, don't code)
|
|
35
|
+
|
|
36
|
+
**Smali Reading Quick Ref:**
|
|
37
|
+
```
|
|
38
|
+
.field → class fields (properties)
|
|
39
|
+
.method → method start
|
|
40
|
+
.end method → method end
|
|
41
|
+
invoke-virtual → instance method call
|
|
42
|
+
invoke-static → static method call
|
|
43
|
+
const-string → string literal
|
|
44
|
+
new-instance → object creation
|
|
45
|
+
if-eqz/if-nez → conditional branches
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2.2: Domain Model Contracts
|
|
49
|
+
|
|
50
|
+
Define data classes with exact field mapping:
|
|
51
|
+
|
|
52
|
+
```kotlin
|
|
53
|
+
// Domain model
|
|
54
|
+
data class User(
|
|
55
|
+
val id: String,
|
|
56
|
+
val fullName: String,
|
|
57
|
+
val email: String,
|
|
58
|
+
val avatarUrl: String?,
|
|
59
|
+
val isVerified: Boolean
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
// DTO (from API)
|
|
63
|
+
@Serializable
|
|
64
|
+
data class UserDto(
|
|
65
|
+
@SerialName("user_id") val userId: String,
|
|
66
|
+
@SerialName("full_name") val fullName: String,
|
|
67
|
+
@SerialName("email") val email: String,
|
|
68
|
+
@SerialName("avatar_url") val avatarUrl: String?,
|
|
69
|
+
@SerialName("is_verified") val isVerified: Boolean
|
|
70
|
+
)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 2.3: Repository Contract
|
|
74
|
+
|
|
75
|
+
Define interfaces (NO implementation):
|
|
76
|
+
|
|
77
|
+
```kotlin
|
|
78
|
+
interface AuthRepository {
|
|
79
|
+
suspend fun login(email: String, password: String): Result<User>
|
|
80
|
+
suspend fun register(name: String, email: String, password: String): Result<User>
|
|
81
|
+
suspend fun logout()
|
|
82
|
+
fun isLoggedIn(): Flow<Boolean>
|
|
83
|
+
fun getCurrentUser(): Flow<User?>
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 2.4: API Contract
|
|
88
|
+
|
|
89
|
+
Define Retrofit interface:
|
|
90
|
+
|
|
91
|
+
```kotlin
|
|
92
|
+
interface AuthApi {
|
|
93
|
+
@POST("auth/login")
|
|
94
|
+
suspend fun login(@Body request: LoginRequest): LoginResponse
|
|
95
|
+
|
|
96
|
+
@POST("auth/register")
|
|
97
|
+
suspend fun register(@Body request: RegisterRequest): RegisterResponse
|
|
98
|
+
|
|
99
|
+
@GET("auth/me")
|
|
100
|
+
suspend fun getCurrentUser(@Header("Authorization") token: String): UserDto
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 2.5: UseCase Signatures
|
|
105
|
+
|
|
106
|
+
```kotlin
|
|
107
|
+
class LoginUseCase(private val authRepo: AuthRepository) {
|
|
108
|
+
suspend operator fun invoke(email: String, password: String): Result<User>
|
|
109
|
+
// Implementation: TODO()
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 2.6: UI State Design
|
|
114
|
+
|
|
115
|
+
This is CRITICAL — design UiState + Events BEFORE coding the ViewModel:
|
|
116
|
+
|
|
117
|
+
```kotlin
|
|
118
|
+
// State
|
|
119
|
+
data class LoginUiState(
|
|
120
|
+
val email: String = "",
|
|
121
|
+
val password: String = "",
|
|
122
|
+
val isLoading: Boolean = false,
|
|
123
|
+
val error: String? = null,
|
|
124
|
+
val isPasswordVisible: Boolean = false
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
// Events (one-time actions)
|
|
128
|
+
sealed interface LoginEvent {
|
|
129
|
+
data class NavigateToHome(val user: User) : LoginEvent
|
|
130
|
+
data class ShowSnackbar(val message: String) : LoginEvent
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Actions (user interactions)
|
|
134
|
+
sealed interface LoginAction {
|
|
135
|
+
data class UpdateEmail(val email: String) : LoginAction
|
|
136
|
+
data class UpdatePassword(val password: String) : LoginAction
|
|
137
|
+
data object TogglePasswordVisibility : LoginAction
|
|
138
|
+
data object Submit : LoginAction
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 2.7: UI Wireframe
|
|
143
|
+
|
|
144
|
+
Describe the screen layout in structured text (NOT code):
|
|
145
|
+
|
|
146
|
+
```markdown
|
|
147
|
+
### LoginScreen Wireframe
|
|
148
|
+
┌──────────────────────┐
|
|
149
|
+
│ [App Logo] │
|
|
150
|
+
│ │
|
|
151
|
+
│ ┌──────────────────┐ │
|
|
152
|
+
│ │ Email TextField │ │
|
|
153
|
+
│ └──────────────────┘ │
|
|
154
|
+
│ ┌──────────────────┐ │
|
|
155
|
+
│ │ Password Field 👁│ │
|
|
156
|
+
│ └──────────────────┘ │
|
|
157
|
+
│ │
|
|
158
|
+
│ [═══ Login Button ══]│
|
|
159
|
+
│ │
|
|
160
|
+
│ Forgot Password? │
|
|
161
|
+
│ Don't have account?│
|
|
162
|
+
│ Register │
|
|
163
|
+
└──────────────────────┘
|
|
164
|
+
|
|
165
|
+
Behaviors:
|
|
166
|
+
- Email: validate format on focus lost
|
|
167
|
+
- Password: toggle visibility icon
|
|
168
|
+
- Button: disabled when loading, show progress
|
|
169
|
+
- Error: Snackbar at bottom
|
|
170
|
+
- Success: Navigate to HomeScreen
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 📊 Output: Feature Blueprint
|
|
176
|
+
|
|
177
|
+
Present a clean summary:
|
|
178
|
+
|
|
179
|
+
```markdown
|
|
180
|
+
## 📐 Blueprint: [Feature Name]
|
|
181
|
+
|
|
182
|
+
### Smali Analysis Summary
|
|
183
|
+
- Files analyzed: [list]
|
|
184
|
+
- Key observations: [patterns, encryption, special logic]
|
|
185
|
+
|
|
186
|
+
### Contracts
|
|
187
|
+
- Domain Models: [list with field count]
|
|
188
|
+
- Repository Interface: [method signatures]
|
|
189
|
+
- API Interface: [endpoint signatures]
|
|
190
|
+
- UseCases: [list]
|
|
191
|
+
|
|
192
|
+
### UI Design
|
|
193
|
+
- UiState: [field list]
|
|
194
|
+
- Events: [list]
|
|
195
|
+
- Actions: [list]
|
|
196
|
+
- Wireframe: [see above]
|
|
197
|
+
|
|
198
|
+
### Dependencies
|
|
199
|
+
- Depends on: [other features/modules]
|
|
200
|
+
- Depended by: [features that need this]
|
|
201
|
+
|
|
202
|
+
### Estimated Files
|
|
203
|
+
| File | Layer | Type |
|
|
204
|
+
|------|-------|------|
|
|
205
|
+
| User.kt | Domain/Model | Data class |
|
|
206
|
+
| AuthRepository.kt | Domain/Repository | Interface |
|
|
207
|
+
| AuthRepositoryImpl.kt | Data/Repository | Implementation |
|
|
208
|
+
| AuthApi.kt | Data/Remote | Retrofit interface |
|
|
209
|
+
| LoginUseCase.kt | Domain/UseCase | Class |
|
|
210
|
+
| LoginViewModel.kt | Presentation | ViewModel |
|
|
211
|
+
| LoginScreen.kt | Presentation | Composable |
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## ✅ Gate
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
"📐 Blueprint cho [Feature] xong. Anh xem contracts có ổn không?
|
|
220
|
+
Khi OK em sẽ bắt đầu implement (Phase 3)."
|
|
221
|
+
|
|
222
|
+
→ User approves → Proceed to Phase 3 (Implementation) for this feature
|
|
223
|
+
→ User wants changes → Adjust blueprint
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
*Phase 2: Blueprint — Contracts before code*
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# 🔨 Phase 3: Implementation (Ground View — per feature)
|
|
2
|
+
|
|
3
|
+
> **Zoom Level:** 3 — Code Implementation
|
|
4
|
+
> **Goal:** Write actual, production-quality code for ONE feature.
|
|
5
|
+
> **Input:** Approved Blueprint from Phase 2.
|
|
6
|
+
> **Output:** Complete implementation files.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## ✅ PREREQUISITES
|
|
11
|
+
|
|
12
|
+
Before writing ANY code, confirm:
|
|
13
|
+
- [ ] Phase 0 App Map exists and is approved
|
|
14
|
+
- [ ] Phase 1 Architecture Blueprint exists and is approved
|
|
15
|
+
- [ ] Phase 2 Feature Blueprint exists for THIS feature and is approved
|
|
16
|
+
- [ ] All contracts (interfaces, models, state) are defined in Blueprint
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 📋 Implementation Order (per feature)
|
|
21
|
+
|
|
22
|
+
### 3.1: Domain Layer
|
|
23
|
+
|
|
24
|
+
1. **Models** — data classes from Blueprint 2.2
|
|
25
|
+
2. **Repository interfaces** — from Blueprint 2.3
|
|
26
|
+
3. **UseCases** — implement invoke() with repository calls
|
|
27
|
+
|
|
28
|
+
```kotlin
|
|
29
|
+
class LoginUseCase @Inject constructor(
|
|
30
|
+
private val authRepository: AuthRepository
|
|
31
|
+
) {
|
|
32
|
+
suspend operator fun invoke(email: String, password: String): Result<User> {
|
|
33
|
+
return authRepository.login(email, password)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 3.2: Data Layer
|
|
39
|
+
|
|
40
|
+
1. **DTOs** — @Serializable data classes matching API JSON
|
|
41
|
+
2. **API interfaces** — Retrofit with correct annotations
|
|
42
|
+
3. **Room entities + DAOs** (if applicable)
|
|
43
|
+
4. **DataStore** setup (if applicable)
|
|
44
|
+
5. **Repository implementation** — offline-first pattern:
|
|
45
|
+
|
|
46
|
+
```kotlin
|
|
47
|
+
class AuthRepositoryImpl @Inject constructor(
|
|
48
|
+
private val api: AuthApi,
|
|
49
|
+
private val tokenStore: TokenDataStore
|
|
50
|
+
) : AuthRepository {
|
|
51
|
+
|
|
52
|
+
override suspend fun login(email: String, password: String): Result<User> {
|
|
53
|
+
return runCatching {
|
|
54
|
+
val response = api.login(LoginRequest(email, password))
|
|
55
|
+
tokenStore.saveToken(response.accessToken)
|
|
56
|
+
response.user.toDomain()
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
override fun isLoggedIn(): Flow<Boolean> {
|
|
61
|
+
return tokenStore.tokenFlow.map { it.isNotEmpty() }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 3.3: DI Module
|
|
67
|
+
|
|
68
|
+
```kotlin
|
|
69
|
+
@Module
|
|
70
|
+
@InstallIn(SingletonComponent::class)
|
|
71
|
+
abstract class RepositoryModule {
|
|
72
|
+
@Binds
|
|
73
|
+
abstract fun bindAuthRepository(impl: AuthRepositoryImpl): AuthRepository
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 3.4: ViewModel
|
|
78
|
+
|
|
79
|
+
Implement using UiState + Events from Blueprint:
|
|
80
|
+
|
|
81
|
+
```kotlin
|
|
82
|
+
@HiltViewModel
|
|
83
|
+
class LoginViewModel @Inject constructor(
|
|
84
|
+
private val loginUseCase: LoginUseCase
|
|
85
|
+
) : ViewModel() {
|
|
86
|
+
|
|
87
|
+
private val _uiState = MutableStateFlow(LoginUiState())
|
|
88
|
+
val uiState = _uiState.asStateFlow()
|
|
89
|
+
|
|
90
|
+
private val _events = MutableSharedFlow<LoginEvent>()
|
|
91
|
+
val events = _events.asSharedFlow()
|
|
92
|
+
|
|
93
|
+
fun onAction(action: LoginAction) {
|
|
94
|
+
when (action) {
|
|
95
|
+
is LoginAction.UpdateEmail -> _uiState.update { it.copy(email = action.email) }
|
|
96
|
+
is LoginAction.UpdatePassword -> _uiState.update { it.copy(password = action.password) }
|
|
97
|
+
LoginAction.TogglePasswordVisibility -> _uiState.update { it.copy(isPasswordVisible = !it.isPasswordVisible) }
|
|
98
|
+
LoginAction.Submit -> login()
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private fun login() {
|
|
103
|
+
viewModelScope.launch {
|
|
104
|
+
_uiState.update { it.copy(isLoading = true, error = null) }
|
|
105
|
+
loginUseCase(uiState.value.email, uiState.value.password)
|
|
106
|
+
.onSuccess { user -> _events.emit(LoginEvent.NavigateToHome(user)) }
|
|
107
|
+
.onFailure { e -> _uiState.update { it.copy(error = e.message, isLoading = false) } }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 3.5: Compose Screen
|
|
114
|
+
|
|
115
|
+
```kotlin
|
|
116
|
+
@Composable
|
|
117
|
+
fun LoginScreen(
|
|
118
|
+
viewModel: LoginViewModel = hiltViewModel(),
|
|
119
|
+
onNavigateToHome: () -> Unit
|
|
120
|
+
) {
|
|
121
|
+
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
|
122
|
+
|
|
123
|
+
LaunchedEffect(Unit) {
|
|
124
|
+
viewModel.events.collect { event ->
|
|
125
|
+
when (event) {
|
|
126
|
+
is LoginEvent.NavigateToHome -> onNavigateToHome()
|
|
127
|
+
is LoginEvent.ShowSnackbar -> { /* snackbar */ }
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Compose UI from Blueprint wireframe
|
|
133
|
+
Scaffold { padding ->
|
|
134
|
+
Column(
|
|
135
|
+
modifier = Modifier
|
|
136
|
+
.fillMaxSize()
|
|
137
|
+
.padding(padding)
|
|
138
|
+
.padding(24.dp),
|
|
139
|
+
horizontalAlignment = Alignment.CenterHorizontally
|
|
140
|
+
) {
|
|
141
|
+
// Logo, TextFields, Button — matching wireframe
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 3.6: Resource Extraction (On-Demand)
|
|
148
|
+
|
|
149
|
+
**ONLY** extract resources used by this screen:
|
|
150
|
+
- Drawables referenced in layout XML
|
|
151
|
+
- Strings used in this Activity's Smali
|
|
152
|
+
- Colors and Dimens for this screen
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Find drawables used in layout
|
|
156
|
+
grep -o '@drawable/[a-z_]*' [apktool_dir]/res/layout/activity_login.xml | sort -u
|
|
157
|
+
|
|
158
|
+
# Find strings used in Activity smali
|
|
159
|
+
grep 'const-string.*R.string' [apktool_dir]/smali/.../LoginActivity.smali
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 🔒 CRYPTO UTILS (Special Handling)
|
|
165
|
+
|
|
166
|
+
If the feature involves encryption/hashing:
|
|
167
|
+
|
|
168
|
+
1. **Read Smali carefully** — exact algorithm, padding, encoding
|
|
169
|
+
2. **Implement in Kotlin** — preserve exact input/output
|
|
170
|
+
3. **Unit test IMMEDIATELY** — with known pairs from original app
|
|
171
|
+
|
|
172
|
+
```kotlin
|
|
173
|
+
object CryptoUtils {
|
|
174
|
+
fun hashMd5(input: String): String {
|
|
175
|
+
val md = MessageDigest.getInstance("MD5")
|
|
176
|
+
return md.digest(input.toByteArray())
|
|
177
|
+
.joinToString("") { "%02x".format(it) }
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// TEST (mandatory)
|
|
182
|
+
class CryptoUtilsTest {
|
|
183
|
+
@Test
|
|
184
|
+
fun `md5 matches original app output`() {
|
|
185
|
+
// Capture known pairs from running original app
|
|
186
|
+
assertEquals("expected_hash", CryptoUtils.hashMd5("known_input"))
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
> ⚠️ Crypto functions MUST produce identical output. Any mismatch breaks server communication.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## ✅ Checkpoint (After each feature)
|
|
196
|
+
|
|
197
|
+
```markdown
|
|
198
|
+
## ✅ Feature Complete: [Feature Name]
|
|
199
|
+
|
|
200
|
+
### Files created:
|
|
201
|
+
- domain/model/User.kt
|
|
202
|
+
- domain/repository/AuthRepository.kt
|
|
203
|
+
- domain/usecase/LoginUseCase.kt
|
|
204
|
+
- data/remote/api/AuthApi.kt
|
|
205
|
+
- data/remote/dto/LoginRequest.kt, LoginResponse.kt
|
|
206
|
+
- data/repository/AuthRepositoryImpl.kt
|
|
207
|
+
- presentation/screens/auth/LoginScreen.kt
|
|
208
|
+
- presentation/screens/auth/LoginViewModel.kt
|
|
209
|
+
- presentation/screens/auth/LoginUiState.kt
|
|
210
|
+
|
|
211
|
+
### Resources extracted:
|
|
212
|
+
- [only what was needed]
|
|
213
|
+
|
|
214
|
+
### Tests:
|
|
215
|
+
- [ ] Crypto utils verified
|
|
216
|
+
- [ ] API contract matches original
|
|
217
|
+
|
|
218
|
+
### ⏭️ Next Feature: [Name]
|
|
219
|
+
→ Return to Phase 2 (Blueprint) for this feature
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## 🔄 Loop
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
Phase 2 (Blueprint for Feature X) → Phase 3 (Build Feature X) → Checkpoint
|
|
228
|
+
↓
|
|
229
|
+
Phase 2 (Blueprint for Feature Y) → Phase 3 (Build Feature Y) → Checkpoint
|
|
230
|
+
↓
|
|
231
|
+
... (repeat for all features from Architecture Build Order)
|
|
232
|
+
↓
|
|
233
|
+
Final: Parity Check & Quality Gate
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## ✅ Final Parity Check (After all features)
|
|
239
|
+
|
|
240
|
+
1. **API Parity** — all endpoints match (headers, body, encoding)
|
|
241
|
+
2. **Data Parity** — crypto/hash output identical
|
|
242
|
+
3. **UI Parity** — screen-by-screen comparison
|
|
243
|
+
4. **Edge Cases** — empty states, errors, offline
|
|
244
|
+
5. **Build & Test** — `./gradlew assembleDebug && ./gradlew test && ./gradlew lint`
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
*Phase 3: Implementation — One feature at a time, guided by Blueprint*
|