All authors

Claude Skills by HoangNguyen0403
github.com/HoangNguyen04031,434 skills30 installs1,975 views
- Brainstorm FeatureSDLC intake that turns a rough idea into an approved BRD-lite brief (Why lane) or delivery contract (Direction lane) at docs/brd/brd-[slug].md, sized by SNC tier.Votes: 0GitHub stars: 549
- Code ReviewRun an AI-assisted PR code review using multi-layer lenses with confidence scoring.Votes: 0GitHub stars: 549
- Codebase ReviewReview an entire codebase for architecture, engineering health, and exploitable risk; generate a prioritized remediation plan, an evidence-anchored system knowledge document, or both.Votes: 0GitHub stars: 549
- Evals RunWorkflow skill for evals run.Votes: 0GitHub stars: 549
- Incident HotfixMitigate a production incident or urgent regression first, then route to root-cause remediation and a postmortem.Votes: 0GitHub stars: 549
- Review System DesignReview a system design someone else provided - screenshot, drawio, Mermaid, slides, doc, or IaC - by extracting it into a confirmed fact sheet, then scoring it on the nine axes.Votes: 0GitHub stars: 549
- System Design SessionRun an interactive system design session that turns a product goal into a sized, justified architecture with diagrams, ADRs, a scorecard, and a machine-readable handoff.Votes: 0GitHub stars: 549
- Uat SignoffWalk a business/UAT approver through a plain-language demo of a verified feature and capture business acceptance signoff.Votes: 0GitHub stars: 549
- Android Agp UpgradeAGP 9 provides built-in Kotlin support. The `org.jetbrains.kotlin.android` plugin is no longer needed, so explicitly applying it causes the plugin application failure after the upgrade. - Remove `org.jetbrains.kotlin.android` from the root and module `plugins` blocks, including its version declaration or alias. - Check Gradle, JDK, and Kotlin compatibility with the AGP 9 release. - If the project uses `kapt`, migrate supported processors to KSP; use `legacy-kapt` only for processors without K...Votes: 0GitHub stars: 549
- Android Agp Upgrade1. Check the current AGP version. If it is below 8.x, run Android Studio’s AGP Upgrade Assistant first. 2. Verify that the Gradle, JDK, and Kotlin versions are compatible with AGP 9’s release notes. 3. Update the build files to the latest stable AGP 9.x version. Also update related dependencies as needed: - KSP: version 2.3.6 or newer - Hilt: version 2.59.2 or newer 4. Migrate to AGP 9’s built-in Kotlin support. Remove the `org.jetbrains.kotlin.android` plugin and follow the built-in Kotlin m...Votes: 0GitHub stars: 549
- Android Agp UpgradeRun these checks from the project root: ```bash ./gradlew help ./gradlew build --dry-run ``` Both commands should succeed without configuration or plugin errors. Then verify that Android Studio completes Gradle IDE sync successfully. Also confirm the migration details: - The project uses a compatible Gradle, JDK, and Kotlin version. - `org.jetbrains.kotlin.android` has been removed where AGP 9 built-in Kotlin is used. - The new AGP DSL is applied correctly. - KSP is at least `2.3.6+` if used,...Votes: 0GitHub stars: 549
- Android ArchitecturePut the order-total business logic in a domain-layer `UseCase`, for example `CalculateOrderTotalUseCase`. - **UseCase/domain:** Pure Kotlin business rules such as item totals, discounts, tax, and rounding. It must not depend on Android or `Context`. - **Repository:** Retrieves or persists data and maps DTOs/data models to domain models; it should not own the order-calculation rules. - **ViewModel:** Calls the use case in response to UI events and exposes the result through a `StateFlow<UiStat...Votes: 0GitHub stars: 549
- Android ArchitectureSplit the app primarily by feature, with shared capabilities in core modules: ```text :app # DI root, Compose navigation, navigation guard :feature:login # Login UI/ViewModel and login-specific domain/data code :feature:products # Product-listing UI/ViewModel and product-specific code :feature:cart # Cart UI/ViewModel and cart-specific code :core:ui # Shared Compose design system :core:network # API client and network infrastructure :core:dat...Votes: 0GitHub stars: 549
- Android ArchitectureYes. A Composable should not call a repository directly. That couples presentation to data access, makes recomposition and lifecycle behavior harder to control, and makes the UI harder to test. Use unidirectional data flow instead: ```text Composable --events--> ViewModel --calls--> UseCase --> Repository Composable <--UiState-- ViewModel ``` The ViewModel should invoke the use case in response to UI events and expose a `StateFlow<UiState>`. The Composable should collect it with `collectAsSta...Votes: 0GitHub stars: 549
- Android Background WorkUse a `CoroutineWorker` scheduled with a unique `PeriodicWorkRequest`. WorkManager persists the request and can run it after the app process is killed or the app is closed. It is the right choice for deferrable server synchronization; execution is not an exact six-hour alarm because Android may defer work for Doze, battery, or other system conditions. ```kotlin class SyncWorker( appContext: Context, workerParams: WorkerParameters, ) : CoroutineWorker(appContext, workerParams) { override suspe...Votes: 0GitHub stars: 549
- Android Background WorkUse a **Foreground Service** for music playback. Playback is a user-visible, ongoing task, so it is one of the cases where a foreground service is appropriate. It keeps playback alive when the app UI is no longer visible and must show a persistent media notification with playback controls. WorkManager is not suitable for the playback loop: its work is deferrable and is not intended for continuous, latency-sensitive audio. Use WorkManager for related deferrable jobs such as uploading listening...Votes: 0GitHub stars: 549
- Android Background WorkMake the worker a `@HiltWorker` and mark its constructor `@AssistedInject`. WorkManager supplies `Context` and `WorkerParameters`; Hilt supplies the repository. ```kotlin @HiltWorker class SyncWorker @AssistedInject constructor( @Assisted appContext: Context, @Assisted workerParams: WorkerParameters, private val repository: SyncRepository, ) : CoroutineWorker(appContext, workerParams) { override suspend fun doWork(): Result = try { repository.sync() Result.success() } catch (error: IOExceptio...Votes: 0GitHub stars: 549
- Android Compose MigrationStart with one small, leaf XML layout rather than migrating the whole app. 1. **Identify the candidate.** Prefer a shallow layout with few custom Views and no complex `RecyclerView` adapter. 2. **Analyze the XML.** Inventory every View, layout relationship, data binding, click listener, style/color, and custom View. Mark custom Views that will need `AndroidView`. 3. **Create a View-to-Compose checklist and get approval.** For example: `TextView` → `Text`, `ImageView` → `Image`, `Button` → `Bu...Votes: 0GitHub stars: 549
- Android Compose MigrationFor incremental migration, keep the Fragment and replace one XML region with a `ComposeView`. If the XML already contains a Compose container, configure it in `onViewCreated`: ```kotlin override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.composeContent.apply { setViewCompositionStrategy( ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed ) setContent { AppTheme { DetailsScreen( state = viewModel.uiState.collectAs...Votes: 0GitHub stars: 549
- Android Compose MigrationUse `LazyColumn` for a vertically scrolling `RecyclerView` with `LinearLayoutManager`, and `LazyRow` for a horizontal one. Items are composed lazily instead of creating one large static layout. ```kotlin @Composable fun MessageList( messages: List<Message>, onMessageClick: (Message) -> Unit, ) { val listState = rememberLazyListState() LazyColumn( state = listState, modifier = Modifier.fillMaxSize(), contentPadding = PaddingValues(vertical = 8.dp), verticalArrangement = Arrangement.spacedBy(8....Votes: 0GitHub stars: 549
- Android ComposeCompose skips recomposition when a composable’s inputs are considered unchanged. Make that possible by: - Passing only the data and callbacks the child actually needs, rather than a broad mutable object or `ViewModel`. - Using stable or immutable UI models (`@Immutable` where appropriate) and stable callback references. - Hoisting state to the stateful screen and keeping the child stateless. - Using `remember` for values whose calculation does not need to repeat, and `derivedStateOf` for freq...Votes: 0GitHub stars: 549
- Android ComposeUsually, no. Keep the `ViewModel` at the stateful screen boundary. Collect its state there, send only the data needed for rendering to the child, and pass events down as lambdas. ```kotlin @Composable fun ProfileScreen(viewModel: ProfileViewModel) { val state by viewModel.uiState.collectAsStateWithLifecycle() ProfileContent( state = state, onSave = viewModel::save, onRetry = viewModel::retry, ) } @Composable fun ProfileContent( state: ProfileUiState, onSave: () -> Unit, onRetry: () -> Unit, )...Votes: 0GitHub stars: 549
- Android ComposeThe composition body may run many times, may be skipped, and may be restarted. A side effect placed there can therefore run more often than intended, run again after unrelated state changes, or be interrupted by recomposition. It also makes ordering and cancellation unclear. Use `LaunchedEffect` for coroutine-based one-shot or keyed work. Its key defines when the work is restarted, and Compose cancels the previous coroutine when the key leaves scope or changes. ```kotlin @Composable fun Detai...Votes: 0GitHub stars: 549
- Android ConcurrencyNo. Avoid `GlobalScope` in a `ViewModel`: it is not tied to the `ViewModel` lifecycle, so work can continue after the `ViewModel` is cleared and may leak or update stale state. Use `viewModelScope`, which cancels its children when the `ViewModel` is cleared: ```kotlin class ItemsViewModel( private val repository: ItemsRepository, ) : ViewModel() { fun loadItems() { viewModelScope.launch { repository.loadItems() } } } ``` Keep dispatcher selection injectable in the repository or use case rathe...Votes: 0GitHub stars: 549
- Android ConcurrencyInject a dispatcher provider instead of referencing `Dispatchers.IO` or another concrete dispatcher directly. ```kotlin interface DispatcherProvider { val main: CoroutineDispatcher val io: CoroutineDispatcher val default: CoroutineDispatcher } object DefaultDispatcherProvider : DispatcherProvider { override val main = Dispatchers.Main override val io = Dispatchers.IO override val default = Dispatchers.Default } class ItemsRepository( private val dispatchers: DispatcherProvider, ) { suspend fu...Votes: 0GitHub stars: 549
- Android ConcurrencyUse `StateFlow` for persistent UI state and `SharedFlow` for one-off events. `StateFlow` always has a current value and replays the latest state to a new subscriber: ```kotlin private val _uiState = MutableStateFlow(UiState()) val uiState: StateFlow<UiState> = _uiState.asStateFlow() ``` Use it for loading, content, and error state that the UI should be able to render after recreation. `SharedFlow` is appropriate for events such as navigation, a snackbar, or a toast: ```kotlin private val _eve...Votes: 0GitHub stars: 549
- Android DeploymentUse CI secrets/environment variables for the keystore path and passwords, and keep the keystore outside the repository. For example, in `app/build.gradle.kts`: ```kotlin import java.io.File val keystorePath = System.getenv("ANDROID_KEYSTORE_PATH") val keystorePassword = System.getenv("ANDROID_KEYSTORE_PASSWORD") val keyAlias = System.getenv("ANDROID_KEY_ALIAS") val keyPassword = System.getenv("ANDROID_KEY_PASSWORD") android { signingConfigs { create("release") { check(keystorePath != null) { ...Votes: 0GitHub stars: 549
- Android DeploymentEnable R8 only for the Release build in `app/build.gradle.kts`: ```kotlin android { buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } } ``` Build a release artifact and inspect the resulting size. Keep `proguard-rules.pro` minimal; prefer `@Keep` on classes or members used through reflection instead of broad wildcard keep rules. Do not make the Release build debuggable. For ...Votes: 0GitHub stars: 549
- Android DeploymentBuild the exact Release artifact with R8 enabled. The build produces the mapping file at: ```text app/build/outputs/mapping/release/mapping.txt ``` In Play Console, open the matching app release or version in App bundle explorer, go to its downloads/assets area, and upload that `mapping.txt` as the deobfuscation (ProGuard/R8 mapping) file. The mapping must come from the same build/version code as the uploaded APK or App Bundle; keep it archived with the release because a later mapping file ca...Votes: 0GitHub stars: 549
- Android Design SystemMove the raw color into the theme layer, assign it to a Material 3 semantic role, and read that role from `MaterialTheme` in the composable. ```kotlin // ui/theme/Color.kt package com.example.ui.theme import androidx.compose.ui.graphics.Color private val Purple40 = Color(0xFF6650A4) private val Purple80 = Color(0xFFD0BCFF) val LightColors = lightColorScheme( primary = Purple40, ) val DarkColors = darkColorScheme( primary = Purple80, ) ``` ```kotlin // ui/theme/Theme.kt @Composable fun AppThem...Votes: 0GitHub stars: 549
- Android Design SystemDefine typography in `ui/theme/Type.kt`, give the app’s text styles names through the Material 3 `Typography` slots, and consume those slots from `MaterialTheme`. ```kotlin // ui/theme/Type.kt package com.example.ui.theme import androidx.compose.material3.Typography import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.sp val AppTypography = Typography( headlineLarge = TextStyle( fontFamily = FontFamily.SansSerif, fontSize = ...Votes: 0GitHub stars: 549
- Android Design SystemKeep palette values in `Color.kt`, map semantic roles separately for light and dark schemes, and choose the scheme once in `Theme.kt`. Composables should only read `MaterialTheme.colorScheme`. ```kotlin // ui/theme/Color.kt private val BrandLight = Color(0xFF6750A4) private val BrandDark = Color(0xFFD0BCFF) private val OnBrandLight = Color(0xFFFFFFFF) private val OnBrandDark = Color(0xFF381E72) val LightColors = lightColorScheme( primary = BrandLight, onPrimary = OnBrandLight, ) val DarkColor...Votes: 0GitHub stars: 549
- Android DiInstall the module in `SingletonComponent` and scope the provider with `@Singleton`: ```kotlin @Module @InstallIn(SingletonComponent::class) object NetworkModule { @Provides @Singleton fun provideRetrofit(): Retrofit = Retrofit.Builder() .baseUrl("https://api.example.com/") .addConverterFactory(MoshiConverterFactory.create()) .build() @Provides @Singleton fun provideApi(retrofit: Retrofit): ProductApi = retrofit.create(ProductApi::class.java) } ``` Annotate the application with `@HiltAndroidA...Votes: 0GitHub stars: 549
- Android DiUse `@Binds` when an implementation already has an `@Inject` constructor and should be exposed as an interface or superclass. The module is abstract and the binding method has one parameter: ```kotlin interface ProductRepository class DefaultProductRepository @Inject constructor( private val api: ProductApi ) : ProductRepository @Module @InstallIn(SingletonComponent::class) abstract class RepositoryModule { @Binds @Singleton abstract fun bindProductRepository( implementation: DefaultProductRe...Votes: 0GitHub stars: 549
- Android DiFor a parameter known only when the ViewModel is created, use assisted injection rather than field injection: ```kotlin @HiltViewModel(assistedFactory = ProductViewModel.Factory::class) class ProductViewModel @AssistedInject constructor( private val repository: ProductRepository, @Assisted private val productId: String ) : ViewModel() { @AssistedFactory interface Factory { fun create(productId: String): ProductViewModel } } ``` Pass the runtime value through the generated assisted factory at ...Votes: 0GitHub stars: 549
- Android Edge To EdgeTarget SDK 35 enables edge-to-edge behavior, so a bottom-aligned button can draw under the navigation bar unless it applies insets. Enable edge-to-edge in each Activity before `setContent`: ```kotlin class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { App() } } } ``` If the button is part of a `Scaffold`, pass the Scaffold padding to the content instead of adding another inset source...Votes: 0GitHub stars: 549
- Android Edge To EdgeThe double padding occurs because two inset owners are handling the same bottom space when the IME opens: `Scaffold` consumes `WindowInsets.safeDrawing`, and `imePadding()` adds keyboard insets to that same content. The overlapping bottom inset is therefore applied twice. Choose one owner for the content. For example, keep Scaffold's inset handling and pass its `PaddingValues` through, without adding `imePadding()` to that same content: ```kotlin Scaffold( contentWindowInsets = WindowInsets.s...Votes: 0GitHub stars: 549
- Android Edge To EdgeApply the system-bar insets as the `LazyColumn`'s `contentPadding`, not as padding on its parent. This lets the first and last items scroll into the inset area without being clipped. Inside a `Scaffold`, pass through the Scaffold padding: ```kotlin Scaffold { innerPadding -> LazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = innerPadding, ) { items(items) { item -> ItemRow(item) } } } ``` If the list is outside a Scaffold, use the safe-drawing insets as its `contentPadding` (or a...Votes: 0GitHub stars: 549
- Android Legacy NavigationUse a single host activity with a `NavHostFragment`, define the destination argument in the XML graph, and enable the Navigation Safe Args plugin. ```xml <fragment android:id="@+id/productListFragment" android:name="com.example.ProductListFragment"> <action android:id="@+id/action_productListFragment_to_productDetailFragment" app:destination="@id/productDetailFragment" /> </fragment> <fragment android:id="@+id/productDetailFragment" android:name="com.example.ProductDetailFragment"> <argument ...Votes: 0GitHub stars: 549
- Android Legacy NavigationFor a large XML-based app, keep one host activity with one primary `NavHostFragment` and organize the graph into nested or included graphs, such as separate `nav_auth.xml` and `nav_main.xml` graphs. Nested graphs keep each feature’s destinations and actions readable while preserving a centralized `NavController`, back stack, SafeArgs contracts, and deep-link handling. Define explicit `<deepLink>` elements in the navigation graph rather than manifest intent filters. Use multiple `NavHostFragme...Votes: 0GitHub stars: 549
- Android Legacy Navigation`fragment.beginTransaction().replace(...).commit()` bypasses the Navigation Component. It leaves navigation destinations, back-stack behavior, SafeArgs data contracts, deep links, and lifecycle handling split between manual code and the navigation graph. That can produce inconsistent back navigation and makes flows harder to reason about. Define the destination and an action in the XML graph, then navigate through the `NavController`: ```kotlin findNavController().navigate( R.id.action_produc...Votes: 0GitHub stars: 549
- Android Legacy SecurityDo not enable JavaScript merely because the WebView loads a URL. Keep it disabled for arbitrary or untrusted user URLs; JavaScript increases the attack surface and can be dangerous if the page can reach privileged native bridges. If a trusted, allowlisted HTTPS site genuinely requires JavaScript, enable it only for that controlled WebView and do not expose broad native APIs through `@JavascriptInterface`. Restrict navigation with a `WebViewClient` (and use a tightly controlled `WebChromeClien...Votes: 0GitHub stars: 549
- Android Legacy SecurityDo not work around `FileUriExposedException` by disabling the check or continuing to use `Uri.fromFile()`. A `file://` URI exposes a filesystem path and is not an appropriate cross-application sharing mechanism. Use a narrowly scoped `FileProvider` and grant a temporary read permission: ```xml <!-- AndroidManifest.xml --> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <met...Votes: 0GitHub stars: 549
- Android Legacy SecurityTreat the entire incoming implicit Intent as untrusted. If the Activity is internal, make it `android:exported="false"` and use an explicit Intent instead. If it must receive a deep link or another external request, validate all of the following before performing any action: - Allow only the expected action, categories, MIME type, and data scheme/host/path. Reject unexpected or missing values; do not accept arbitrary `file://` data. - Read each extra with the expected type (`getStringExtra`, ...Votes: 0GitHub stars: 549
- Android Legacy State`launchWhenStarted` is deprecated for Flow collection. It suspends the collecting coroutine when the Fragment is stopped, but it does not provide the same structured start/stop behavior for the upstream Flow and can keep resources or producers active unnecessarily. In a Fragment, collect against the **view lifecycle** with `repeatOnLifecycle`: ```kotlin override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewLifecycleOwner.lifecy...Votes: 0GitHub stars: 549
- Android Legacy State`observe(this, ...)` observes with the Fragment's lifecycle, which can remain active after the Fragment's view has been destroyed. When the LiveData emits while navigating back or while the Fragment is stopped, the callback may access a dead ViewBinding or other destroyed view state, causing the crash. Observe from `onViewCreated` with `viewLifecycleOwner`: ```kotlin override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.d...Votes: 0GitHub stars: 549
- Android Legacy StateUse `StateFlow` for new code. It gives the ViewModel a coroutine-native, lifecycle-independent state holder with a current value, works naturally with other Flow operators, and can be collected using structured lifecycle-aware coroutines. Expose an immutable `StateFlow` from the ViewModel: ```kotlin private val _uiState = MutableStateFlow(UiState()) val uiState: StateFlow<UiState> = _uiState.asStateFlow() ``` Collect it in the Fragment using the **view lifecycle** and `repeatOnLifecycle`: ```...Votes: 0GitHub stars: 549
- Android Navigation 3Navigation 3 uses typed Kotlin values as routes instead of string patterns. A route with no arguments can be a `data object`; a route with arguments should be a `data class` whose properties hold those arguments. ```kotlin data object RouteHome data class RouteDetail(val id: String) data object RouteSettings ``` The argument is now a normal Kotlin property, so there is no `"detail/{id}"` placeholder, string interpolation, or `NavBackStackEntry` argument lookup. A route is created with the val...Votes: 0GitHub stars: 549
- Android Navigation 3Navigation 3 makes the back stack application state. Replace the `NavController` with a `mutableStateListOf<Any>`, replace `NavHost` with `NavDisplay`, and navigate by adding or removing typed route values. First define route values instead of string routes: ```kotlin data object RouteHome data class RouteDetail(val id: String) data object RouteLogin ``` Then render and mutate the list directly: ```kotlin @Composable fun AppNavigation(isLoggedIn: Boolean) { val backStack = remember(isLoggedIn...Votes: 0GitHub stars: 549
- Android Navigation 3Give each bottom-navigation tab its own `mutableStateListOf<Any>`. Switching tabs changes which list is supplied to `NavDisplay`, so each tab retains its independent navigation history. ```kotlin enum class Tab(val label: String, val startRoute: Any) { Home("Home", RouteHome), Search("Search", RouteSearch), Profile("Profile", RouteProfile) } data object RouteHome data object RouteSearch data object RouteProfile data class RouteDetail(val id: String) @Composable fun MainScreen() { val tabs = r...Votes: 0GitHub stars: 549