Files
recipe/.planning/phases/02.1-app-shell-navigation-search-foundation/02.1-04-SUMMARY.md

6.1 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, decisions, metrics
phase plan subsystem tags requires provides affects tech-stack key-files decisions metrics
02.1 04 navigation
kotlin
compose-multiplatform
navigation
navigation-compose
type-safe-routes
multi-back-stack
02.1-01
02.1-02
navigation/Routes.kt — 8 @Serializable route types (4 graphs + 4 home destinations)
navigation/BottomBarDestination.kt — enum binding routes ↔ string resources ↔ icons ↔ search visibility
navigation/RootNavHost.kt — single root NavHost with 4 nested navigation() sub-graphs
navigation/NavExtensions.kt — NavHostController.navigateToTab() with four-flag multi-back-stack incantation
9 new shared shell/search keys in strings.xml
composeApp/src/commonMain/composeResources/values/strings.xml (append-only — 9 new keys)
composeApp/src/commonTest/kotlin/dev/ulfrx/recipe/navigation/NavigationTest.kt (un-Ignored, real assertions)
added patterns
androidx.navigation.compose.NavHost / navigation / composable (typed routes via @Serializable)
androidx.navigation.navOptions DSL (used in tests)
Multi-back-stack tab navigation: popUpTo(graph.findStartDestination().id){saveState=true} + launchSingleTop + restoreState
Per-tab parent NavBackStackEntry retrieval for future Koin VM scoping (RESEARCH § Pattern 2)
created modified
composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/navigation/Routes.kt
composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/navigation/BottomBarDestination.kt
composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/navigation/RootNavHost.kt
composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/navigation/NavExtensions.kt
composeApp/src/commonMain/composeResources/values/strings.xml
composeApp/src/commonTest/kotlin/dev/ulfrx/recipe/navigation/NavigationTest.kt
Used Icons.AutoMirrored.Outlined.MenuBook (deprecation warning was fatal under -Werror)
TabHomePlaceholder uses BasicText from compose-foundation — avoids Material 1/3
NavigationTest uses navOptions{} DSL with public shouldXxx() accessors; fake-builder fallback was not needed
duration completed
~6m 2026-05-08

Phase 02.1 Plan 04: Navigation Foundation Summary

Type-safe navigation skeleton with 4 nested tab graphs (Planner/Recipes/Pantry/Shopping), a BottomBarDestination enum exposing routes/labels/icons/search visibility, and a navigateToTab extension that enforces the multi-back-stack four-flag contract — verified by 3 unit tests.

What Was Built

  • Routes.kt — 8 @Serializable data object types: PlannerGraph/PlannerHome, RecipesGraph/RecipesHome, PantryGraph/PantryHome, ShoppingGraph/ShoppingHome.
  • BottomBarDestination.kt — enum in D-03 order (Planner first as Default); only Recipes + Pantry have hasSearch=true/non-null searchPlaceholder. Bound to Icons.Outlined.{CalendarMonth,Inventory2,ShoppingCart} and Icons.AutoMirrored.Outlined.MenuBook.
  • RootNavHost.kt — single root NavHost(startDestination = PlannerGraph) containing four navigation<*Graph>(startDestination = *Home) blocks. Each composable<*Home> retrieves the parent graph's NavBackStackEntry via navController.getBackStackEntry(*Graph) (Pattern 2 wired and ready for plan 02.1-08 to consume with koinViewModel(viewModelStoreOwner = parent)). Renders private TabHomePlaceholder using BasicText — no Material dependency.
  • NavExtensions.ktfun NavHostController.navigateToTab(graphRoute: Any) applies popUpTo(graph.findStartDestination().id){saveState=true}, launchSingleTop = true, restoreState = true.
  • strings.xml — 9 new keys appended (4 tab labels + 2 search placeholders + 3 search a11y), Polish copy verbatim from UI-SPEC. All 7 existing auth_* keys preserved.
  • NavigationTest.kt@Ignore removed; 3 tests assert the four-flag contract via the public navOptions { ... } DSL and shouldLaunchSingleTop() / shouldRestoreState() / shouldPopUpToSaveState() accessors.

Verification

  • ./gradlew :composeApp:compileKotlinIosSimulatorArm64 -q → exit 0
  • ./gradlew :composeApp:iosSimulatorArm64Test --tests "dev.ulfrx.recipe.navigation.NavigationTest" → BUILD SUCCESSFUL (3 tests pass)
  • ./gradlew :composeApp:linkDebugFrameworkIosSimulatorArm64 -q → exit 0
  • All acceptance grep counts match per task.

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] Deprecated Icons.Outlined.MenuBook failed -Werror compile

  • Found during: Task 1 verify
  • Issue: 'val Icons.Outlined.MenuBook: ImageVector' is deprecated. Use the AutoMirrored version — Werror promoted the warning to a build failure.
  • Fix: Switched to Icons.AutoMirrored.Outlined.MenuBook and updated import.
  • Files modified: composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/navigation/BottomBarDestination.kt
  • Commit: 9b9029a (folded into Task 1 commit)

No other deviations. Plan executed as written.

Open Questions Resolved

  • navOptions DSL availability under nav-compose 2.9.2 K/N: Public navOptions { ... } builder and shouldLaunchSingleTop() / shouldRestoreState() / shouldPopUpToSaveState() accessors are all publicly exposed. The fake-builder fallback path described in the plan was not needed.
  • TabHomePlaceholder text strategy: Settled on androidx.compose.foundation.text.BasicText — keeps the placeholder Material-free per UI-SPEC line 31. Plan 02.1-08 will replace with real Tab*Screen composables.

Commits

  • 9b9029a feat(02.1-04): add type-safe routes and bottom bar destinations
  • 5634171 feat(02.1-04): add RootNavHost and navigateToTab extension
  • 41d9bf4 test(02.1-04): assert navigateToTab applies four-flag back-stack contract

Self-Check: PASSED

  • FOUND: composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/navigation/Routes.kt
  • FOUND: composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/navigation/BottomBarDestination.kt
  • FOUND: composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/navigation/RootNavHost.kt
  • FOUND: composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/navigation/NavExtensions.kt
  • FOUND commit 9b9029a, 5634171, 41d9bf4