一键导入
implement-navigation
Describes and enforces the type-safe KMP navigation pattern. Use when adding new screens, routes, or navigation flows to the app.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Describes and enforces the type-safe KMP navigation pattern. Use when adding new screens, routes, or navigation flows to the app.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | implement-navigation |
| description | Describes and enforces the type-safe KMP navigation pattern. Use when adding new screens, routes, or navigation flows to the app. |
Navigation follows a wiring-layer pattern where feature modules expose Screen composables (which collect their own side effects) and the app module wires them to type-safe routes via NavGraphBuilder extensions.
Screen (feature module) ← ScreenNode (navigation wiring) ← RootNavGraph ← App.kt
receives state, creates ViewModel NavHost rememberNavController
onEvent, sideEffects, collects state
onNavigation handles onNavigation callback
collects side effects
| Concept | Description |
|---|---|
| Route | @Serializable object/data class. Co-located in its [Feature]Navigation.kt |
| navigateTo Extension | NavController.navigateTo*() extension, co-located with its route |
| ScreenNode | NavGraphBuilder extension that wires ViewModel → Screen for a given route |
| RootNavGraph | Single NavHost composable that registers all screen nodes |
| Side Effect Handling | Screen collects side effects internally via CollectSideEffect and delegates navigation to onNavigation callback. ScreenNode only handles onNavigation. |
@Serializable via kotlinx.serialization, no string-based routingnavigateTo*() + ScreenNode live in the same [Feature]Navigation.ktScreen composables only; navigation wiring lives in composeApp/navigation/onNavigationorg.jetbrains.androidx.navigation:navigation-composecomposeApp/src/commonMain/kotlin/.../
└── navigation/
├── RootNavGraph.kt → SetupRootNavGraph with NavHost
├── HomeNavigation.kt → HomeRoute + navigateToHome() + homeScreenNode()
├── [Feature]Navigation.kt → [Feature]Route + navigateTo[Feature]() + [feature]ScreenNode()
└── ...
Each [Feature]Navigation.kt file contains its route, navigateTo* extension, and screen node:
// [Feature]Navigation.kt
@Serializable
data object FeatureRoute
fun NavController.navigateToFeature(navOptions: NavOptions? = null) {
this.navigate(FeatureRoute, navOptions)
}
// With arguments
@Serializable
data class ProfileRoute(val userId: String)
fun NavController.navigateToProfile(userId: String, navOptions: NavOptions? = null) {
this.navigate(ProfileRoute(userId = userId), navOptions)
}
The ScreenNode creates the ViewModel, collects state, and passes everything to the Screen. The Screen handles side effects internally — the ScreenNode only provides the onNavigation callback.
// [Feature]Navigation.kt
fun NavGraphBuilder.[feature]ScreenNode(navController: NavController) {
composable<FeatureRoute> {
val viewModel = viewModel { FeatureViewModel() }
val state by collectViewState(viewModel.viewState)
FeatureScreen(
state = state,
onEvent = viewModel::onViewEvent,
sideEffects = viewModel.sideEffect,
onNavigation = { navigation ->
when (navigation) {
FeatureSideEffect.Navigation.NavigateBack ->
navController.popBackStack()
is FeatureSideEffect.Navigation.GoToDetail ->
navController.navigateToDetail(id = navigation.id)
}
},
)
}
}
With route arguments:
composable<FeatureRoute> { backStackEntry ->
val route = backStackEntry.toRoute<FeatureRoute>()
val viewModel = viewModel { FeatureViewModel(id = route.id) }
// ...
}
NavHost(navController, startDestination = HomeRoute) {
[feature]ScreenNode(navController)
}
Use the NavController extension from the corresponding [Feature]Navigation.kt:
navController.navigateToFeature()
navController.navigateToProfile(userId = "123")
navigateTo*() extension, and screen node in the same [Feature]Navigation.ktnavigateTo*() extensions instead of raw navController.navigate(Route)collectViewState() from :common:mvi for state collection in the ScreenNodesideEffects and onNavigation to the Screen — let the Screen collect side effects via CollectSideEffect[feature]ScreenNode(navController)composable {} inside feature modulesNavController to ViewModelsDeep audit of authentication and session management against OWASP MASVS-AUTH controls. Use when code touches login, logout, token storage, token refresh, biometrics, or Google Sign-In.
Generate a full OWASP MASVS v2 compliance checklist for Dividox with MASTG test mappings. Use before a release, for a compliance review, or when assessing overall security posture.
Deep audit of code quality and supply chain security against OWASP MASVS-CODE controls. Use when modifying libs.versions.toml dependencies, minSdk, R8/ProGuard rules, or input validation logic. This is the primary skill for Detekt-detectable issues.
Deep audit of cryptographic implementations against OWASP MASVS-CRYPTO controls. Use when code generates keys, encrypts/decrypts data, uses hashing, or touches AndroidKeyStore / iOS Keychain.
Generate a STRIDE threat model for Dividox mapped to MASVS controls with NowSecure risk tiering. Use when designing new features with a significant security surface, or for periodic threat reviews.
Deep audit of network communication security against OWASP MASVS-NETWORK controls. Use when code configures HTTP clients (Ktor, OkHttp), touches TLS, certificates, or network_security_config.xml.