From 29b2e8cca62a281c7207a83847436b3273adca57 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Sun, 15 Mar 2026 19:49:44 +0100 Subject: [PATCH] fix(01-foundation): revise plans based on checker feedback --- .planning/phases/01-foundation/01-01-PLAN.md | 92 +++++++++++++++----- .planning/phases/01-foundation/01-02-PLAN.md | 48 ++++++---- 2 files changed, 102 insertions(+), 38 deletions(-) diff --git a/.planning/phases/01-foundation/01-01-PLAN.md b/.planning/phases/01-foundation/01-01-PLAN.md index 37988cb..2d2e81b 100644 --- a/.planning/phases/01-foundation/01-01-PLAN.md +++ b/.planning/phases/01-foundation/01-01-PLAN.md @@ -15,6 +15,10 @@ files_modified: - lib/core/theme/app_theme.dart - lib/core/theme/theme_provider.dart - lib/l10n/app_de.arb + - test/core/database/database_test.dart + - test/core/theme/theme_test.dart + - test/core/theme/color_scheme_test.dart + - test/l10n/localization_test.dart autonomous: true requirements: - FOUND-01 @@ -60,6 +64,18 @@ must_haves: - path: "lib/l10n/app_de.arb" provides: "German localization strings" contains: "tabHome" + - path: "test/core/database/database_test.dart" + provides: "Database unit and smoke tests (FOUND-01)" + contains: "schemaVersion" + - path: "test/core/theme/theme_test.dart" + provides: "Theme switching widget test (THEME-01)" + contains: "ThemeMode" + - path: "test/core/theme/color_scheme_test.dart" + provides: "ColorScheme unit tests (THEME-02)" + contains: "ColorScheme" + - path: "test/l10n/localization_test.dart" + provides: "Localization widget test (FOUND-03)" + contains: "AppLocalizations" key_links: - from: "lib/core/theme/theme_provider.dart" to: "shared_preferences" @@ -76,10 +92,10 @@ must_haves: --- -Scaffold the Flutter project and build all core infrastructure: Drift database with migration workflow, Riverpod providers with code generation, theme definitions (sage & stone palette), and ARB localization strings. +Scaffold the Flutter project and build all core infrastructure: Drift database with migration workflow, Riverpod providers with code generation, theme definitions (sage & stone palette), and ARB localization strings. Create Wave 0 test scaffolding for database, theme, and localization. -Purpose: Establish every foundational dependency and pattern so Plan 02 can build the UI shell without any infrastructure work. -Output: A Flutter project that compiles, has all dependencies resolved, code generation working, database initialized, and theme/localization ready for consumption by UI code. +Purpose: Establish every foundational dependency and pattern so Plan 02 can build the UI shell without any infrastructure work. Tests provide fast feedback during execution. +Output: A Flutter project that compiles, has all dependencies resolved, code generation working, database initialized, theme/localization ready for consumption by UI code, and test scaffolding in place. @@ -164,16 +180,21 @@ Output: A Flutter project that compiles, has all dependencies resolved, code gen - Task 2: Create core infrastructure — database, providers, theme, and localization strings + Task 2: Create core infrastructure, localization strings, and Wave 0 test scaffolding lib/core/database/database.dart, lib/core/providers/database_provider.dart, lib/core/theme/app_theme.dart, lib/core/theme/theme_provider.dart, - lib/l10n/app_de.arb + lib/l10n/app_de.arb, + lib/main.dart, + test/core/database/database_test.dart, + test/core/theme/theme_test.dart, + test/core/theme/color_scheme_test.dart, + test/l10n/localization_test.dart -1. Create `lib/core/database/database.dart` — the Drift database class: +1. Create `lib/core/database/database.dart` -- the Drift database class: - Import `package:drift/drift.dart` and `package:drift_flutter/drift_flutter.dart` - Add `part 'database.g.dart';` - Define `@DriftDatabase(tables: [])` with empty tables list (tables added in Phase 2) @@ -183,35 +204,35 @@ Output: A Flutter project that compiles, has all dependencies resolved, code gen - Static `_openConnection()` returns `driftDatabase(name: 'household_keeper', native: const DriftNativeOptions(databaseDirectory: getApplicationSupportDirectory))` - Import `package:path_provider/path_provider.dart` for `getApplicationSupportDirectory` -2. Create `lib/core/providers/database_provider.dart` — Riverpod provider for database: +2. Create `lib/core/providers/database_provider.dart` -- Riverpod provider for database: - Import riverpod_annotation and the database - Add `part 'database_provider.g.dart';` - Use `@Riverpod(keepAlive: true)` annotation (database must persist) - Function `appDatabase(Ref ref)` returns `AppDatabase()` - The provider creates the singleton database instance -3. Create `lib/core/theme/app_theme.dart` — light and dark theme definitions: +3. Create `lib/core/theme/app_theme.dart` -- light and dark theme definitions: - Define `AppTheme` class with static methods `lightTheme()` and `darkTheme()` returning `ThemeData` - Light ColorScheme: `ColorScheme.fromSeed(seedColor: Color(0xFF7A9A6D), brightness: Brightness.light, dynamicSchemeVariant: DynamicSchemeVariant.tonalSpot).copyWith(surface: Color(0xFFF5F0E8), surfaceContainerLowest: Color(0xFFFAF7F2), surfaceContainerLow: Color(0xFFF2EDE4), surfaceContainer: Color(0xFFEDE7DC), surfaceContainerHigh: Color(0xFFE7E0D5), surfaceContainerHighest: Color(0xFFE0D9CE))` - Dark ColorScheme: Same seed, `Brightness.dark`, `.copyWith(surface: Color(0xFF2A2520), surfaceContainerLowest: Color(0xFF1E1A16), surfaceContainerLow: Color(0xFF322D27), surfaceContainer: Color(0xFF3A342E), surfaceContainerHigh: Color(0xFF433D36), surfaceContainerHighest: Color(0xFF4D463F))` - Both ThemeData set `useMaterial3: true` and use the respective ColorScheme -4. Create `lib/core/theme/theme_provider.dart` — Riverpod provider for theme mode: +4. Create `lib/core/theme/theme_provider.dart` -- Riverpod provider for theme mode: - Import riverpod_annotation, flutter/material.dart, shared_preferences - Add `part 'theme_provider.g.dart';` - `@riverpod class ThemeNotifier extends _$ThemeNotifier` - `build()` method: read from SharedPreferences key `'theme_mode'`, parse to ThemeMode enum, default to `ThemeMode.system` - `setThemeMode(ThemeMode mode)` method: update state, persist to SharedPreferences - - Use `ref.read` pattern for async SharedPreferences access (NOT ref.watch — this is a Notifier, not build()) + - Use `ref.read` pattern for async SharedPreferences access (NOT ref.watch -- this is a Notifier, not build()) - Helper: `_themeModeFromString(String? value)` and `_themeModeToString(ThemeMode mode)` for serialization -5. Create `lib/l10n/app_de.arb` — German localization strings for all Phase 1 UI: +5. Create `lib/l10n/app_de.arb` -- German localization strings for all Phase 1 UI: ```json { "@@locale": "de", "appTitle": "HouseHoldKeaper", - "tabHome": "Ubersicht", - "tabRooms": "Raume", + "tabHome": "\u00dcbersicht", + "tabRooms": "R\u00e4ume", "tabSettings": "Einstellungen", "homeEmptyTitle": "Noch nichts zu tun!", "homeEmptyMessage": "Lege zuerst einen Raum an, um Aufgaben zu planen.", @@ -224,7 +245,7 @@ Output: A Flutter project that compiles, has all dependencies resolved, code gen "themeSystem": "System", "themeLight": "Hell", "themeDark": "Dunkel", - "settingsSectionAbout": "Uber", + "settingsSectionAbout": "\u00dcber", "aboutAppName": "HouseHoldKeaper", "aboutTagline": "Dein Haushalt, entspannt organisiert.", "aboutVersion": "Version {version}", @@ -235,9 +256,9 @@ Output: A Flutter project that compiles, has all dependencies resolved, code gen } } ``` - Note: Use proper German characters (umlauts) where appropriate. The tab labels "Ubersicht" should be "Ubersicht" and "Raume" should be "Raume" — but check CONTEXT.md which shows them without umlauts. Use umlauts in the ARB file: "Ubersicht", "Raume", "Uber" should actually be with umlauts if the font supports it. Per the CONTEXT.md the user specified "Ubersicht", "Raume", "Einstellungen" — follow exactly as specified there. + IMPORTANT: Use proper German umlauts throughout -- "Ubersicht" with umlaut (U+00DC), "Raume" with umlaut (U+00E4), "Uber" with umlaut (U+00DC). Per CONTEXT.md user decision: labels are "Ubersicht", "Raume", "Einstellungen" with umlauts. -6. Remove the default `lib/main.dart` content and replace with a minimal placeholder that imports ProviderScope (just enough to verify compilation — full wiring happens in Plan 02): +6. Remove the default `lib/main.dart` content and replace with a minimal placeholder that imports ProviderScope (just enough to verify compilation -- full wiring happens in Plan 02): ```dart import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -253,12 +274,41 @@ Output: A Flutter project that compiles, has all dependencies resolved, code gen 8. Run Drift migration capture: `dart run drift_dev make-migrations` This captures schema version 1 in `drift_schemas/` directory. -9. Run `dart analyze` to verify riverpod_lint is active and no analysis issues exist. +9. Create Wave 0 test files: + + a. `test/core/database/database_test.dart` (covers FOUND-01): + - Test that `AppDatabase(NativeDatabase.memory())` opens successfully + - Test that `schemaVersion` equals 1 + - Test that the database can be closed without error + - Use in-memory database (`NativeDatabase.memory()`) for test isolation + + b. `test/core/theme/color_scheme_test.dart` (covers THEME-02): + - Test that `AppTheme.lightTheme()` has `Brightness.light` + - Test that `AppTheme.darkTheme()` has `Brightness.dark` + - Test that both use sage green seed: verify `primary` color is in the green hue range + - Test that light surface color is warm (0xFFF5F0E8) + - Test that dark surface color is warm charcoal (0xFF2A2520), not cold gray + + c. `test/core/theme/theme_test.dart` (covers THEME-01): + - Widget test: wrap a `MaterialApp` with `ProviderScope` and verify that `ThemeNotifier` defaults to `ThemeMode.system` + - Test that calling `setThemeMode(ThemeMode.dark)` updates state + - Test that calling `setThemeMode(ThemeMode.light)` updates state + - Use `SharedPreferences.setMockInitialValues({})` for test isolation + + d. `test/l10n/localization_test.dart` (covers FOUND-03): + - Widget test: create a `MaterialApp` with `AppLocalizations.localizationsDelegates`, `supportedLocales: [Locale('de')]`, `locale: Locale('de')` + - Pump a widget that reads `AppLocalizations.of(context)` and displays `tabHome` + - Verify the rendered text contains the expected German string (with umlaut) + - Test that all critical keys are non-empty: `appTitle`, `tabHome`, `tabRooms`, `tabSettings` + +10. Run `dart analyze` to verify riverpod_lint is active and no analysis issues exist. + +11. Run `flutter test` to verify all Wave 0 tests pass. - cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && dart run build_runner build --delete-conflicting-outputs 2>&1 | tail -5 && dart analyze 2>&1 | tail -5 && echo "PASS: Codegen and analysis clean" + cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && dart run build_runner build --delete-conflicting-outputs 2>&1 | tail -5 && dart analyze 2>&1 | tail -5 && flutter test 2>&1 | tail -10 && echo "PASS: Codegen, analysis, and tests clean" - database.dart defines AppDatabase with schemaVersion 1. database_provider.dart exposes AppDatabase via @riverpod. app_theme.dart provides lightTheme() and darkTheme() with sage green seed and warm surface overrides. theme_provider.dart provides ThemeNotifier with shared_preferences persistence and ThemeMode.system default. app_de.arb contains all German strings for Phase 1 screens. All .g.dart files generated successfully. drift_dev make-migrations has captured schema v1. dart analyze passes cleanly. + database.dart defines AppDatabase with schemaVersion 1. database_provider.dart exposes AppDatabase via @riverpod. app_theme.dart provides lightTheme() and darkTheme() with sage green seed and warm surface overrides. theme_provider.dart provides ThemeNotifier with shared_preferences persistence and ThemeMode.system default. app_de.arb contains all German strings for Phase 1 screens with proper umlauts (Ubersicht, Raume, Uber). All .g.dart files generated successfully. drift_dev make-migrations has captured schema v1. dart analyze passes cleanly. All 4 Wave 0 test files created and passing: database_test.dart, color_scheme_test.dart, theme_test.dart, localization_test.dart. @@ -268,6 +318,7 @@ Output: A Flutter project that compiles, has all dependencies resolved, code gen - `dart run build_runner build` completes without errors (generates .g.dart files) - `dart run drift_dev make-migrations` completes (schema v1 captured) - `dart analyze` reports no errors (riverpod_lint active) +- `flutter test` passes (all Wave 0 tests green) - `flutter build apk --debug` compiles (project structure valid) @@ -277,9 +328,10 @@ Output: A Flutter project that compiles, has all dependencies resolved, code gen - Riverpod providers created with @riverpod annotation and code generation - Light and dark theme definitions with sage & stone ColorScheme palette - ThemeMode provider with shared_preferences persistence -- ARB localization file with all German strings for Phase 1 +- ARB localization file with all German strings for Phase 1 using proper umlauts - All code generation (.g.dart files) succeeds - dart analyze passes cleanly with riverpod_lint active +- Wave 0 tests pass: database (FOUND-01), localization (FOUND-03), theme switching (THEME-01), color scheme (THEME-02) diff --git a/.planning/phases/01-foundation/01-02-PLAN.md b/.planning/phases/01-foundation/01-02-PLAN.md index 92052b5..4303104 100644 --- a/.planning/phases/01-foundation/01-02-PLAN.md +++ b/.planning/phases/01-foundation/01-02-PLAN.md @@ -13,6 +13,7 @@ files_modified: - 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 @@ -56,6 +57,9 @@ must_haves: 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" @@ -84,10 +88,10 @@ must_haves: --- -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. +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. +Output: An Android app that compiles, launches, and satisfies all Phase 1 success criteria, with app shell test passing. @@ -151,13 +155,14 @@ From lib/l10n/app_de.arb (generated AppLocalizations): - Task 1: Create router, navigation shell, and all three screens + Task 1: Create router, navigation shell, all three screens, and app shell test 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 + lib/features/settings/presentation/settings_screen.dart, + test/shell/app_shell_test.dart 1. Create `lib/core/router/router.dart` -- GoRouter with StatefulShellRoute: @@ -207,16 +212,24 @@ From lib/l10n/app_de.arb (generated AppLocalizations): - `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 -- "Uber" (About):** + - **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 - cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && dart analyze 2>&1 | tail -10 && echo "PASS: All screens analyze cleanly" + 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" - router.dart defines GoRouter with StatefulShellRoute.indexedStack and 3 branches. app_shell.dart renders NavigationBar with 3 tabs using localized labels 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 "Uber" with app name, tagline, and version. All text loaded from AppLocalizations, zero hardcoded German strings in Dart code. + 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. @@ -247,17 +260,14 @@ From lib/l10n/app_de.arb (generated AppLocalizations): 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. Run `flutter build apk --debug` to verify the entire app compiles for Android. - -5. Verify the complete integration: +4. Verify the complete integration: - `dart analyze` passes cleanly - - `flutter test` passes (default test or any existing tests) - - The app structure matches the architecture from RESEARCH.md + - `flutter test` passes (all tests including Wave 0 tests from Plan 01) - cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && flutter build apk --debug 2>&1 | tail -5 && echo "PASS: App compiles for Android" + 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" - 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. The app compiles via `flutter build apk --debug` without errors. The complete architecture is in place: Drift database + Riverpod providers + GoRouter navigation + Material 3 theme + ARB localization. + 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. @@ -277,7 +287,7 @@ Verification checklist: 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. "Uber" section shows app name and tagline +11. "Über" section shows app name and tagline 12. Overall sage and stone palette feels calm and warm Human visually confirms all 12 checklist items pass @@ -285,7 +295,7 @@ Verification checklist: 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. 1. Launch the app on an Android device/emulator: `flutter run` -2. Verify bottom navigation bar shows 3 tabs with icons and German labels: "Ubersicht" (checklist icon), "Raume" (door icon), "Einstellungen" (sliders icon) +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 @@ -294,7 +304,7 @@ Verification checklist: 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 "Uber" section -- verify app name "HouseHoldKeaper" and tagline "Dein Haushalt, entspannt organisiert." +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 Type "approved" to complete Phase 1, or describe any visual/functional issues to fix @@ -303,8 +313,9 @@ Verification checklist: -- `flutter build apk --debug` succeeds - `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 @@ -320,6 +331,7 @@ Verification checklist: - 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