chore: archive v1.0 phase directories to milestones/
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
340
.planning/milestones/v1.0-phases/01-foundation/01-02-PLAN.md
Normal file
340
.planning/milestones/v1.0-phases/01-foundation/01-02-PLAN.md
Normal file
@@ -0,0 +1,340 @@
|
||||
---
|
||||
phase: 01-foundation
|
||||
plan: 02
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on:
|
||||
- "01-01"
|
||||
files_modified:
|
||||
- lib/app.dart
|
||||
- lib/main.dart
|
||||
- lib/core/router/router.dart
|
||||
- lib/shell/app_shell.dart
|
||||
- lib/features/home/presentation/home_screen.dart
|
||||
- lib/features/rooms/presentation/rooms_screen.dart
|
||||
- lib/features/settings/presentation/settings_screen.dart
|
||||
- test/shell/app_shell_test.dart
|
||||
autonomous: false
|
||||
requirements:
|
||||
- FOUND-03
|
||||
- FOUND-04
|
||||
- THEME-01
|
||||
- THEME-02
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "App launches on Android without errors and shows a bottom navigation bar"
|
||||
- "Bottom navigation has three tabs: Home, Rooms, Settings with thematic icons"
|
||||
- "Tab labels are loaded from ARB localization files, not hardcoded"
|
||||
- "Tapping each tab switches to the correct screen with preserved state"
|
||||
- "Home tab shows playful empty state with action button that navigates to Rooms tab"
|
||||
- "Rooms tab shows playful empty state with action button"
|
||||
- "Settings screen shows working theme switcher (System/Hell/Dunkel) and About section"
|
||||
- "Theme switcher persists selection across app restart"
|
||||
- "Light and dark themes render correctly with sage & stone palette"
|
||||
artifacts:
|
||||
- path: "lib/app.dart"
|
||||
provides: "MaterialApp.router with theme, localization, and ProviderScope"
|
||||
contains: "MaterialApp.router"
|
||||
min_lines: 20
|
||||
- path: "lib/main.dart"
|
||||
provides: "Entry point with ProviderScope"
|
||||
contains: "ProviderScope"
|
||||
- path: "lib/core/router/router.dart"
|
||||
provides: "GoRouter with StatefulShellRoute.indexedStack for 3-tab navigation"
|
||||
contains: "StatefulShellRoute.indexedStack"
|
||||
- path: "lib/shell/app_shell.dart"
|
||||
provides: "Scaffold with NavigationBar receiving StatefulNavigationShell"
|
||||
contains: "NavigationBar"
|
||||
min_lines: 30
|
||||
- path: "lib/features/home/presentation/home_screen.dart"
|
||||
provides: "Placeholder with empty state guiding user to Rooms tab"
|
||||
contains: "AppLocalizations"
|
||||
- path: "lib/features/rooms/presentation/rooms_screen.dart"
|
||||
provides: "Placeholder with empty state encouraging room creation"
|
||||
contains: "AppLocalizations"
|
||||
- path: "lib/features/settings/presentation/settings_screen.dart"
|
||||
provides: "Theme switcher (SegmentedButton) + About section with grouped headers"
|
||||
contains: "SegmentedButton"
|
||||
min_lines: 40
|
||||
- path: "test/shell/app_shell_test.dart"
|
||||
provides: "Navigation shell widget test (FOUND-04)"
|
||||
contains: "NavigationBar"
|
||||
key_links:
|
||||
- from: "lib/app.dart"
|
||||
to: "lib/core/router/router.dart"
|
||||
via: "routerConfig parameter"
|
||||
pattern: "routerConfig"
|
||||
- from: "lib/app.dart"
|
||||
to: "lib/core/theme/app_theme.dart"
|
||||
via: "theme and darkTheme parameters"
|
||||
pattern: "AppTheme"
|
||||
- from: "lib/app.dart"
|
||||
to: "lib/core/theme/theme_provider.dart"
|
||||
via: "ref.watch for themeMode"
|
||||
pattern: "themeNotifierProvider"
|
||||
- from: "lib/shell/app_shell.dart"
|
||||
to: "lib/l10n/app_de.arb"
|
||||
via: "AppLocalizations for tab labels"
|
||||
pattern: "AppLocalizations"
|
||||
- from: "lib/features/home/presentation/home_screen.dart"
|
||||
to: "lib/core/router/router.dart"
|
||||
via: "Cross-tab navigation to Rooms"
|
||||
pattern: "context.go.*rooms"
|
||||
- from: "lib/features/settings/presentation/settings_screen.dart"
|
||||
to: "lib/core/theme/theme_provider.dart"
|
||||
via: "SegmentedButton reads/writes ThemeNotifier"
|
||||
pattern: "themeNotifierProvider"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Build the navigation shell, all three screens (Home placeholder, Rooms placeholder, Settings with theme switcher), and wire everything into a launchable app with full theme and localization integration. Create the app shell widget test.
|
||||
|
||||
Purpose: Deliver a complete, launchable app that demonstrates the architecture established in Plan 01 -- users see the bottom navigation, can switch tabs, change themes, and all text comes from localization.
|
||||
Output: An Android app that compiles, launches, and satisfies all Phase 1 success criteria, with app shell test passing.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@/home/jlmak/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@/home/jlmak/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/01-foundation/1-CONTEXT.md
|
||||
@.planning/phases/01-foundation/01-RESEARCH.md
|
||||
@.planning/phases/01-foundation/01-01-SUMMARY.md
|
||||
|
||||
<interfaces>
|
||||
<!-- Key types and contracts from Plan 01 that this plan consumes. -->
|
||||
|
||||
From lib/core/theme/app_theme.dart:
|
||||
```dart
|
||||
class AppTheme {
|
||||
static ThemeData lightTheme();
|
||||
static ThemeData darkTheme();
|
||||
}
|
||||
```
|
||||
|
||||
From lib/core/theme/theme_provider.dart (generated):
|
||||
```dart
|
||||
// @riverpod class ThemeNotifier extends _$ThemeNotifier
|
||||
// Access via: ref.watch(themeNotifierProvider) -> ThemeMode
|
||||
// Mutate via: ref.read(themeNotifierProvider.notifier).setThemeMode(ThemeMode)
|
||||
```
|
||||
|
||||
From lib/core/database/database.dart:
|
||||
```dart
|
||||
class AppDatabase extends _$AppDatabase {
|
||||
// schemaVersion => 1
|
||||
// Used via database_provider.dart
|
||||
}
|
||||
```
|
||||
|
||||
From lib/core/providers/database_provider.dart (generated):
|
||||
```dart
|
||||
// @riverpod AppDatabase appDatabase(Ref ref)
|
||||
// Access via: ref.watch(appDatabaseProvider)
|
||||
```
|
||||
|
||||
From lib/l10n/app_de.arb (generated AppLocalizations):
|
||||
```dart
|
||||
// Access via: AppLocalizations.of(context)
|
||||
// Keys: appTitle, tabHome, tabRooms, tabSettings,
|
||||
// homeEmptyTitle, homeEmptyMessage, homeEmptyAction,
|
||||
// roomsEmptyTitle, roomsEmptyMessage, roomsEmptyAction,
|
||||
// settingsSectionAppearance, settingsThemeLabel,
|
||||
// themeSystem, themeLight, themeDark,
|
||||
// settingsSectionAbout, aboutAppName, aboutTagline, aboutVersion
|
||||
```
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Create router, navigation shell, all three screens, and app shell test</name>
|
||||
<files>
|
||||
lib/core/router/router.dart,
|
||||
lib/shell/app_shell.dart,
|
||||
lib/features/home/presentation/home_screen.dart,
|
||||
lib/features/rooms/presentation/rooms_screen.dart,
|
||||
lib/features/settings/presentation/settings_screen.dart,
|
||||
test/shell/app_shell_test.dart
|
||||
</files>
|
||||
<action>
|
||||
1. Create `lib/core/router/router.dart` -- GoRouter with StatefulShellRoute:
|
||||
- Define a top-level `GoRouter router` (or use @riverpod if needed for ref access -- keep it simple with a plain final variable since router doesn't need Riverpod state)
|
||||
- Use `StatefulShellRoute.indexedStack` with 3 branches:
|
||||
- Branch 0: `GoRoute(path: '/', builder: ... HomeScreen())`
|
||||
- Branch 1: `GoRoute(path: '/rooms', builder: ... RoomsScreen())`
|
||||
- Branch 2: `GoRoute(path: '/settings', builder: ... SettingsScreen())`
|
||||
- Builder returns `AppShell(navigationShell: navigationShell)`
|
||||
|
||||
2. Create `lib/shell/app_shell.dart` -- Scaffold with NavigationBar:
|
||||
- `AppShell` is a StatelessWidget receiving `StatefulNavigationShell navigationShell`
|
||||
- Build method: get `AppLocalizations` via `AppLocalizations.of(context)`
|
||||
- Scaffold body: `navigationShell`
|
||||
- bottomNavigationBar: `NavigationBar` with:
|
||||
- `selectedIndex: navigationShell.currentIndex`
|
||||
- `onDestinationSelected`: calls `navigationShell.goBranch(index, initialLocation: index == navigationShell.currentIndex)`
|
||||
- Three `NavigationDestination` items:
|
||||
- Home: icon `Icons.checklist_outlined`, selectedIcon `Icons.checklist`, label from `l10n.tabHome`
|
||||
- Rooms: icon `Icons.door_front_door_outlined`, selectedIcon `Icons.door_front_door`, label from `l10n.tabRooms`
|
||||
- Settings: icon `Icons.tune_outlined`, selectedIcon `Icons.tune`, label from `l10n.tabSettings`
|
||||
|
||||
3. Create `lib/features/home/presentation/home_screen.dart` -- Placeholder with empty state:
|
||||
- `HomeScreen` extends `StatelessWidget`
|
||||
- Build method: Center column with:
|
||||
- Large Material icon (e.g., `Icons.checklist_rounded`, size 80, muted color)
|
||||
- Text from `l10n.homeEmptyTitle` (styled as headline)
|
||||
- Text from `l10n.homeEmptyMessage` (styled as body, muted color)
|
||||
- `FilledButton.tonal` with text from `l10n.homeEmptyAction`
|
||||
- Button onPressed: `context.go('/rooms')` -- cross-navigates to Rooms tab
|
||||
- All text comes from AppLocalizations, zero hardcoded strings
|
||||
|
||||
4. Create `lib/features/rooms/presentation/rooms_screen.dart` -- Placeholder with empty state:
|
||||
- Same visual pattern as HomeScreen: icon + title + message + action button
|
||||
- Icon: `Icons.door_front_door_rounded` (size 80)
|
||||
- Text from `l10n.roomsEmptyTitle`, `l10n.roomsEmptyMessage`, `l10n.roomsEmptyAction`
|
||||
- Action button: `FilledButton.tonal` -- for now it can be a no-op (room creation comes in Phase 2) or show a SnackBar. The button should exist but doesn't need to do anything functional yet.
|
||||
|
||||
5. Create `lib/features/settings/presentation/settings_screen.dart` -- Theme switcher + About:
|
||||
- `SettingsScreen` extends `ConsumerWidget` (needs ref for theme provider)
|
||||
- Uses `ListView` with grouped sections:
|
||||
- **Section 1 -- "Darstellung" (Appearance):**
|
||||
- Section header: Padding + Text from `l10n.settingsSectionAppearance` styled as titleMedium with primary color
|
||||
- Theme switcher row: ListTile with title from `l10n.settingsThemeLabel`, subtitle is a `SegmentedButton<ThemeMode>` with three segments:
|
||||
- `ThemeMode.system`: label `l10n.themeSystem`, icon `Icons.settings_suggest_outlined`
|
||||
- `ThemeMode.light`: label `l10n.themeLight`, icon `Icons.light_mode_outlined`
|
||||
- `ThemeMode.dark`: label `l10n.themeDark`, icon `Icons.dark_mode_outlined`
|
||||
- `selected: {ref.watch(themeNotifierProvider)}`
|
||||
- `onSelectionChanged: (s) => ref.read(themeNotifierProvider.notifier).setThemeMode(s.first)`
|
||||
- **Section 2 -- "Über" (About):**
|
||||
- Section header: same style, text from `l10n.settingsSectionAbout`
|
||||
- ListTile: title from `l10n.aboutAppName`, subtitle from `l10n.aboutTagline`
|
||||
- ListTile: title "Version", subtitle from `l10n.aboutVersion` with version string (use package_info_plus or hardcode "0.1.0" for now -- package_info_plus can be added later if needed)
|
||||
- A `Divider` between sections for visual separation
|
||||
|
||||
6. Create `test/shell/app_shell_test.dart` (covers FOUND-04):
|
||||
- Widget test: wrap `MaterialApp.router(routerConfig: router)` in `ProviderScope` with localization delegates and `locale: Locale('de')`
|
||||
- Pump and settle
|
||||
- Verify that 3 `NavigationDestination` widgets are rendered
|
||||
- Verify that the labels match the expected German strings from ARB (with umlauts): "Übersicht", "Räume", "Einstellungen"
|
||||
- Verify that tapping a different destination changes `selectedIndex`
|
||||
- Use `SharedPreferences.setMockInitialValues({})` for ThemeNotifier isolation
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && dart analyze 2>&1 | tail -10 && flutter test test/shell/app_shell_test.dart 2>&1 | tail -10 && echo "PASS: Screens analyze cleanly, shell test passes"</automated>
|
||||
</verify>
|
||||
<done>router.dart defines GoRouter with StatefulShellRoute.indexedStack and 3 branches. app_shell.dart renders NavigationBar with 3 tabs using localized labels (with proper umlauts) and thematic icons (checklist, door, tune). home_screen.dart shows empty state with localized text and a button that navigates to /rooms. rooms_screen.dart shows empty state with localized text and action button. settings_screen.dart shows grouped sections: "Darstellung" with SegmentedButton theme switcher wired to ThemeNotifier, and "Über" with app name, tagline, and version. All text loaded from AppLocalizations, zero hardcoded German strings in Dart code. app_shell_test.dart passes, verifying 3 navigation destinations with correct labels.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Wire app.dart and main.dart -- launchable app with full integration</name>
|
||||
<files>
|
||||
lib/app.dart,
|
||||
lib/main.dart
|
||||
</files>
|
||||
<action>
|
||||
1. Create `lib/app.dart` -- the root App widget:
|
||||
- `App` extends `ConsumerWidget`
|
||||
- Build method:
|
||||
- `final themeMode = ref.watch(themeNotifierProvider);`
|
||||
- Return `MaterialApp.router()`
|
||||
- `routerConfig: router` (from router.dart)
|
||||
- `theme: AppTheme.lightTheme()`
|
||||
- `darkTheme: AppTheme.darkTheme()`
|
||||
- `themeMode: themeMode`
|
||||
- `localizationsDelegates: AppLocalizations.localizationsDelegates`
|
||||
- `supportedLocales: const [Locale('de')]`
|
||||
- `locale: const Locale('de')`
|
||||
- `debugShowCheckedModeBanner: false`
|
||||
- Import `package:flutter_gen/gen_l10n/app_localizations.dart`
|
||||
|
||||
2. Update `lib/main.dart` -- entry point:
|
||||
- `void main()` calls `runApp(const ProviderScope(child: App()))`
|
||||
- Import the App widget and flutter_riverpod
|
||||
|
||||
3. Run `dart run build_runner build --delete-conflicting-outputs` one final time to ensure all generated files are current (router may need regeneration if it uses @riverpod).
|
||||
|
||||
4. Verify the complete integration:
|
||||
- `dart analyze` passes cleanly
|
||||
- `flutter test` passes (all tests including Wave 0 tests from Plan 01)
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && dart analyze 2>&1 | tail -5 && flutter test 2>&1 | tail -10 && echo "PASS: Analysis clean, all tests pass"</automated>
|
||||
</verify>
|
||||
<done>app.dart wires MaterialApp.router with GoRouter config, light/dark themes from AppTheme, themeMode from ThemeNotifier provider, and German localization delegates. main.dart wraps App in ProviderScope. `dart analyze` passes cleanly. `flutter test` passes all tests (database, theme, color scheme, localization, app shell). The complete architecture is in place: Drift database + Riverpod providers + GoRouter navigation + Material 3 theme + ARB localization. Final confirmation: `flutter build apk --debug` compiles without errors.</done>
|
||||
</task>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking">
|
||||
<name>Task 3: Visual and functional verification of complete Phase 1 app</name>
|
||||
<files>none -- verification only</files>
|
||||
<action>
|
||||
Launch the app with `flutter run` on an Android device or emulator. Walk through the 12-step verification checklist below to confirm all Phase 1 requirements are met visually and functionally. This is a human-only verification step -- no code changes.
|
||||
|
||||
Verification checklist:
|
||||
1. App launches without errors and shows bottom navigation bar
|
||||
2. Three tabs visible with correct icons and German labels from ARB
|
||||
3. Tab switching works with state preservation
|
||||
4. Home empty state has playful text and cross-navigates to Rooms tab
|
||||
5. Rooms empty state has playful text and action button
|
||||
6. Settings has "Darstellung" section with SegmentedButton theme switcher
|
||||
7. Light theme shows warm stone/beige surfaces
|
||||
8. Dark theme shows warm charcoal-brown surfaces (not cold gray)
|
||||
9. System theme follows device setting
|
||||
10. Theme preference persists across app restart
|
||||
11. "Über" section shows app name and tagline
|
||||
12. Overall sage and stone palette feels calm and warm
|
||||
</action>
|
||||
<verify>Human visually confirms all 12 checklist items pass</verify>
|
||||
<done>User has approved the visual appearance and functional behavior of the Phase 1 app, or has provided specific feedback for issues to fix.</done>
|
||||
<what-built>Complete Phase 1 app: bottom navigation with 3 tabs, sage and stone theme (light/dark), playful German placeholder screens, Settings with working theme switcher and About section. All text from ARB localization.</what-built>
|
||||
<how-to-verify>
|
||||
1. Launch the app on an Android device/emulator: `flutter run`
|
||||
2. Verify bottom navigation bar shows 3 tabs with icons and German labels: "Übersicht" (checklist icon), "Räume" (door icon), "Einstellungen" (sliders icon)
|
||||
3. Tap each tab -- verify it switches content and the active tab indicator uses sage green
|
||||
4. On the Home tab: verify playful empty state with icon, German text, and "Raum erstellen" button. Tap the button -- verify it navigates to the Rooms tab.
|
||||
5. On the Rooms tab: verify playful empty state with door icon and German text
|
||||
6. On the Settings tab: verify "Darstellung" section header and SegmentedButton with System/Hell/Dunkel options
|
||||
7. Switch theme to "Hell" (light) -- verify warm stone/beige surface tones
|
||||
8. Switch theme to "Dunkel" (dark) -- verify warm charcoal-brown backgrounds (NOT cold gray/black)
|
||||
9. Switch back to "System" -- verify it follows device setting
|
||||
10. Kill and relaunch the app -- verify theme preference persisted
|
||||
11. Scroll to "Über" section -- verify app name "HouseHoldKeaper" and tagline "Dein Haushalt, entspannt organisiert."
|
||||
12. Overall: confirm the sage and stone palette feels calm and warm, not clinical
|
||||
</how-to-verify>
|
||||
<resume-signal>Type "approved" to complete Phase 1, or describe any visual/functional issues to fix</resume-signal>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `dart analyze` reports zero errors/warnings
|
||||
- `flutter test` passes all tests (Wave 0 + app shell test)
|
||||
- `flutter build apk --debug` succeeds
|
||||
- App launches and shows 3-tab bottom navigation
|
||||
- All UI text comes from ARB localization (no hardcoded German in .dart files)
|
||||
- Theme switching works (System/Hell/Dunkel) and persists across restart
|
||||
- Light theme: sage green accents, warm stone surfaces
|
||||
- Dark theme: sage green accents, warm charcoal-brown surfaces
|
||||
- Home empty state cross-navigates to Rooms tab
|
||||
- Settings has grouped sections with theme switcher and About
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- App launches on Android without errors showing bottom navigation with Home, Rooms, and Settings tabs
|
||||
- Light and dark themes work correctly following system setting by default using sage and stone palette
|
||||
- All UI strings loaded from ARB localization files (zero hardcoded German text in Dart code)
|
||||
- Settings screen has working theme switcher (System/Hell/Dunkel) that persists and About section
|
||||
- Placeholder screens show playful empty states with localized text and action buttons
|
||||
- All automated tests pass (Wave 0 tests from Plan 01 + app shell test)
|
||||
- Human verification approves the visual appearance and interaction
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/01-foundation/01-02-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user