docs(03): create phase plan for daily plan and cleanliness

This commit is contained in:
2026-03-16 12:21:59 +01:00
parent aedfa82248
commit 76eee6baa7
4 changed files with 671 additions and 3 deletions

View File

@@ -0,0 +1,277 @@
---
phase: 03-daily-plan-and-cleanliness
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- lib/features/home/data/daily_plan_dao.dart
- lib/features/home/data/daily_plan_dao.g.dart
- lib/features/home/domain/daily_plan_models.dart
- lib/features/home/presentation/daily_plan_providers.dart
- lib/core/database/database.dart
- lib/core/database/database.g.dart
- lib/l10n/app_de.arb
- test/features/home/data/daily_plan_dao_test.dart
autonomous: true
requirements:
- PLAN-01
- PLAN-02
- PLAN-03
- PLAN-05
must_haves:
truths:
- "DailyPlanDao.watchAllTasksWithRoomName() returns tasks joined with room name, sorted by nextDueDate ascending"
- "DailyPlanDao.watchCompletionsToday() returns count of completions recorded today"
- "dailyPlanProvider categorizes tasks into overdue, today, and tomorrow sections"
- "Progress total = remaining overdue + remaining today + completedTodayCount (stable denominator)"
- "Localization keys for daily plan sections and progress text exist in app_de.arb"
artifacts:
- path: "lib/features/home/data/daily_plan_dao.dart"
provides: "Cross-room join query and today's completion count"
exports: ["DailyPlanDao", "TaskWithRoom"]
- path: "lib/features/home/domain/daily_plan_models.dart"
provides: "DailyPlanState data class for categorized daily plan data"
exports: ["DailyPlanState"]
- path: "lib/features/home/presentation/daily_plan_providers.dart"
provides: "Riverpod provider combining task stream and completion stream"
exports: ["dailyPlanProvider"]
- path: "test/features/home/data/daily_plan_dao_test.dart"
provides: "Unit tests for cross-room query, date categorization, completion count"
min_lines: 80
key_links:
- from: "lib/features/home/data/daily_plan_dao.dart"
to: "lib/core/database/database.dart"
via: "@DriftAccessor registration"
pattern: "DailyPlanDao"
- from: "lib/features/home/presentation/daily_plan_providers.dart"
to: "lib/features/home/data/daily_plan_dao.dart"
via: "db.dailyPlanDao.watchAllTasksWithRoomName()"
pattern: "dailyPlanDao"
---
<objective>
Build the data and provider layers for the daily plan feature: a Drift DAO with cross-room join query, a DailyPlanState model with overdue/today/tomorrow categorization, a Riverpod provider combining task and completion streams, localization keys, and unit tests.
Purpose: Provides the reactive data foundation that the daily plan UI (Plan 02) will consume. Separated from UI to keep each plan at ~50% context.
Output: DailyPlanDao with join query, DailyPlanState model, dailyPlanProvider, localization keys, and passing unit tests.
</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/03-daily-plan-and-cleanliness/3-CONTEXT.md
@.planning/phases/03-daily-plan-and-cleanliness/03-RESEARCH.md
@lib/core/database/database.dart
@lib/features/tasks/data/tasks_dao.dart
@lib/features/tasks/presentation/task_providers.dart
@lib/core/providers/database_provider.dart
@test/features/tasks/data/tasks_dao_test.dart
<interfaces>
<!-- Key types and contracts the executor needs. Extracted from codebase. -->
From lib/core/database/database.dart:
```dart
class Rooms extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get name => text().withLength(min: 1, max: 100)();
TextColumn get iconName => text()();
IntColumn get sortOrder => integer().withDefault(const Constant(0))();
DateTimeColumn get createdAt => dateTime().clientDefault(() => DateTime.now())();
}
class Tasks extends Table {
IntColumn get id => integer().autoIncrement()();
IntColumn get roomId => integer().references(Rooms, #id)();
TextColumn get name => text().withLength(min: 1, max: 200)();
TextColumn get description => text().nullable()();
IntColumn get intervalType => intEnum<IntervalType>()();
IntColumn get intervalDays => integer().withDefault(const Constant(1))();
IntColumn get anchorDay => integer().nullable()();
IntColumn get effortLevel => intEnum<EffortLevel>()();
DateTimeColumn get nextDueDate => dateTime()();
DateTimeColumn get createdAt => dateTime().clientDefault(() => DateTime.now())();
}
class TaskCompletions extends Table {
IntColumn get id => integer().autoIncrement()();
IntColumn get taskId => integer().references(Tasks, #id)();
DateTimeColumn get completedAt => dateTime()();
}
@DriftDatabase(
tables: [Rooms, Tasks, TaskCompletions],
daos: [RoomsDao, TasksDao],
)
class AppDatabase extends _$AppDatabase { ... }
```
From lib/core/providers/database_provider.dart:
```dart
@Riverpod(keepAlive: true)
AppDatabase appDatabase(Ref ref) { ... }
```
From lib/features/tasks/presentation/task_providers.dart:
```dart
// Manual StreamProvider.family pattern (used because riverpod_generator
// has trouble with drift's generated Task type)
final tasksInRoomProvider =
StreamProvider.family.autoDispose<List<Task>, int>((ref, roomId) {
final db = ref.watch(appDatabaseProvider);
return db.tasksDao.watchTasksInRoom(roomId);
});
```
</interfaces>
</context>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: DailyPlanDao with cross-room join query and completion count</name>
<files>
lib/features/home/data/daily_plan_dao.dart,
lib/features/home/data/daily_plan_dao.g.dart,
lib/features/home/domain/daily_plan_models.dart,
lib/core/database/database.dart,
lib/core/database/database.g.dart,
test/features/home/data/daily_plan_dao_test.dart
</files>
<behavior>
- watchAllTasksWithRoomName returns empty list when no tasks exist
- watchAllTasksWithRoomName returns tasks with correct room name from join
- watchAllTasksWithRoomName returns tasks sorted by nextDueDate ascending
- watchAllTasksWithRoomName returns tasks from multiple rooms with correct room name pairing
- watchCompletionsToday returns 0 when no completions exist
- watchCompletionsToday returns correct count of completions recorded today
- watchCompletionsToday does not count completions from yesterday
</behavior>
<action>
1. Create `lib/features/home/domain/daily_plan_models.dart` with:
- `TaskWithRoom` class: `final Task task`, `final String roomName`, `final int roomId`, const constructor
- `DailyPlanState` class: `final List<TaskWithRoom> overdueTasks`, `final List<TaskWithRoom> todayTasks`, `final List<TaskWithRoom> tomorrowTasks`, `final int completedTodayCount`, `final int totalTodayCount`, const constructor
2. Create `lib/features/home/data/daily_plan_dao.dart` with:
- `@DriftAccessor(tables: [Tasks, Rooms, TaskCompletions])`
- `class DailyPlanDao extends DatabaseAccessor<AppDatabase> with _$DailyPlanDaoMixin`
- `Stream<List<TaskWithRoom>> watchAllTasksWithRoomName()`: innerJoin tasks with rooms on rooms.id.equalsExp(tasks.roomId), orderBy nextDueDate asc, map rows using readTable(tasks) and readTable(rooms)
- `Stream<int> watchCompletionsToday({DateTime? today})`: count TaskCompletions where completedAt >= startOfDay AND completedAt < endOfDay. Use customSelect with SQL COUNT(*) and readsFrom: {taskCompletions} for proper stream invalidation
3. Register DailyPlanDao in `lib/core/database/database.dart`:
- Add import for daily_plan_dao.dart
- Add `DailyPlanDao` to `@DriftDatabase(daos: [...])` list
- Run `dart run build_runner build --delete-conflicting-outputs` to regenerate database.g.dart and daily_plan_dao.g.dart
4. Create `test/features/home/data/daily_plan_dao_test.dart`:
- Follow existing tasks_dao_test.dart pattern: `AppDatabase(NativeDatabase.memory())`, setUp/tearDown
- Create 2 rooms and insert tasks with different due dates across them
- Test all behaviors listed above
- Use stream.first for single-emission testing (same pattern as existing tests)
IMPORTANT: The customSelect approach for watchCompletionsToday must use `readsFrom: {taskCompletions}` so Drift knows which table to watch for stream invalidation. Without this, the stream won't re-fire on new completions.
</action>
<verify>
<automated>cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && flutter test test/features/home/data/daily_plan_dao_test.dart</automated>
</verify>
<done>
- DailyPlanDao registered in AppDatabase, code generation passes
- watchAllTasksWithRoomName returns tasks joined with room name, sorted by due date
- watchCompletionsToday returns accurate count of today's completions
- All unit tests pass
- TaskWithRoom and DailyPlanState models defined with correct fields
</done>
</task>
<task type="auto">
<name>Task 2: Daily plan provider with date categorization, progress tracking, and localization keys</name>
<files>
lib/features/home/presentation/daily_plan_providers.dart,
lib/l10n/app_de.arb
</files>
<action>
1. Create `lib/features/home/presentation/daily_plan_providers.dart` with:
- Import daily_plan_models.dart, database_provider.dart
- Define `dailyPlanProvider` as a manual `StreamProvider.autoDispose<DailyPlanState>` (NOT using @riverpod, same pattern as tasksInRoomProvider because drift Task type causes riverpod_generator issues)
- Inside provider: `ref.watch(appDatabaseProvider)` to get db
- Watch `db.dailyPlanDao.watchAllTasksWithRoomName()` stream
- Use `.asyncMap()` on the task stream to:
a. Get completions today count via `db.dailyPlanDao.watchCompletionsToday().first`
b. Compute `today = DateTime(now.year, now.month, now.day)`, `tomorrow = today + 1 day`, `dayAfterTomorrow = tomorrow + 1 day`
c. Partition tasks into: overdue (dueDate < today), todayList (today <= dueDate < tomorrow), tomorrowList (tomorrow <= dueDate < dayAfterTomorrow)
d. Compute totalTodayCount = overdue.length + todayList.length + completedTodayCount
e. Return DailyPlanState with all fields
CRITICAL for progress accuracy: totalTodayCount includes completedTodayCount so the denominator stays stable as tasks are completed. Without this, completing a task would shrink the total (since the task moves to a future due date), making progress appear to go backward.
2. Add localization keys to `lib/l10n/app_de.arb` (add these AFTER existing keys, before the closing brace):
```json
"dailyPlanProgress": "{completed} von {total} erledigt",
"@dailyPlanProgress": {
"placeholders": {
"completed": { "type": "int" },
"total": { "type": "int" }
}
},
"dailyPlanSectionOverdue": "\u00dcberf\u00e4llig",
"dailyPlanSectionToday": "Heute",
"dailyPlanSectionUpcoming": "Demn\u00e4chst",
"dailyPlanUpcomingCount": "Demn\u00e4chst ({count})",
"@dailyPlanUpcomingCount": {
"placeholders": {
"count": { "type": "int" }
}
},
"dailyPlanAllClearTitle": "Alles erledigt! \ud83c\udf1f",
"dailyPlanAllClearMessage": "Keine Aufgaben f\u00fcr heute. Genie\u00dfe den Moment!",
"dailyPlanNoOverdue": "Keine \u00fcberf\u00e4lligen Aufgaben",
"dailyPlanNoTasks": "Noch keine Aufgaben angelegt"
```
Note: Use Unicode escapes for umlauts in ARB keys (same pattern as existing keys). The "all clear" title includes a star emoji per the established playful German tone from Phase 1.
3. Run `flutter gen-l10n` (or `flutter pub get` which triggers it) to regenerate localization classes.
4. Verify `dart analyze` passes clean on all new files.
</action>
<verify>
<automated>cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && dart analyze lib/features/home/ lib/l10n/ && flutter test</automated>
</verify>
<done>
- dailyPlanProvider defined as manual StreamProvider.autoDispose returning DailyPlanState
- Tasks correctly categorized into overdue (before today), today (today), tomorrow (next day)
- Progress total is stable: remaining overdue + remaining today + completedTodayCount
- All 10 new localization keys present in app_de.arb and code-generated without errors
- dart analyze clean, full test suite passes
</done>
</task>
</tasks>
<verification>
- `flutter test test/features/home/data/daily_plan_dao_test.dart` -- all DAO tests pass
- `dart analyze lib/features/home/` -- no analysis errors
- `flutter test` -- full suite still passes (no regressions)
- DailyPlanDao registered in AppDatabase daos list
- dailyPlanProvider compiles and references DailyPlanDao correctly
</verification>
<success_criteria>
- DailyPlanDao.watchAllTasksWithRoomName() returns reactive stream of tasks joined with room names
- DailyPlanDao.watchCompletionsToday() returns reactive count of today's completions
- dailyPlanProvider categorizes tasks into overdue/today/tomorrow with stable progress tracking
- All localization keys for daily plan UI are defined
- All existing tests still pass (no regressions from database.dart changes)
</success_criteria>
<output>
After completion, create `.planning/phases/03-daily-plan-and-cleanliness/03-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,276 @@
---
phase: 03-daily-plan-and-cleanliness
plan: 02
type: execute
wave: 2
depends_on:
- 03-01
files_modified:
- lib/features/home/presentation/home_screen.dart
- lib/features/home/presentation/daily_plan_task_row.dart
- lib/features/home/presentation/progress_card.dart
- test/features/home/presentation/home_screen_test.dart
autonomous: true
requirements:
- PLAN-04
- PLAN-06
- CLEAN-01
must_haves:
truths:
- "User sees progress card at top of daily plan showing 'X von Y erledigt' with linear progress bar"
- "User sees overdue tasks in a highlighted section (warm coral) that only appears when overdue tasks exist"
- "User sees today's tasks in a section below overdue"
- "User sees tomorrow's tasks in a collapsed 'Demnachst (N)' section that expands on tap"
- "User can check a checkbox on an overdue or today task, which animates the task out and increments progress"
- "When no overdue or today tasks are due, user sees 'Alles erledigt!' empty state with celebration icon"
- "Room name tag on each task row navigates to that room's task list on tap"
- "Task rows have NO row-tap navigation -- only checkbox and room tag are interactive"
- "CLEAN-01 cleanliness indicator already visible on room cards (Phase 2 -- no new work)"
artifacts:
- path: "lib/features/home/presentation/home_screen.dart"
provides: "Complete daily plan screen replacing placeholder"
min_lines: 100
- path: "lib/features/home/presentation/daily_plan_task_row.dart"
provides: "Task row variant with room name tag, optional checkbox, no row-tap"
min_lines: 50
- path: "lib/features/home/presentation/progress_card.dart"
provides: "Progress banner card with linear progress bar"
min_lines: 30
- path: "test/features/home/presentation/home_screen_test.dart"
provides: "Widget tests for empty state, section rendering"
min_lines: 40
key_links:
- from: "lib/features/home/presentation/home_screen.dart"
to: "lib/features/home/presentation/daily_plan_providers.dart"
via: "ref.watch(dailyPlanProvider)"
pattern: "dailyPlanProvider"
- from: "lib/features/home/presentation/home_screen.dart"
to: "lib/features/tasks/presentation/task_providers.dart"
via: "ref.read(taskActionsProvider.notifier).completeTask()"
pattern: "taskActionsProvider"
- from: "lib/features/home/presentation/daily_plan_task_row.dart"
to: "go_router"
via: "context.go('/rooms/\$roomId') on room tag tap"
pattern: "context\\.go"
---
<objective>
Build the daily plan UI: replace the HomeScreen placeholder with the full daily plan screen featuring a progress card, overdue/today/tomorrow sections, animated task completion, and "all clear" empty state.
Purpose: This is the app's primary screen -- the first thing users see. It transforms the placeholder Home tab into the core daily workflow: see what's due, check it off, feel progress.
Output: Complete HomeScreen rewrite, DailyPlanTaskRow widget, ProgressCard widget, and widget tests.
</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/03-daily-plan-and-cleanliness/3-CONTEXT.md
@.planning/phases/03-daily-plan-and-cleanliness/03-RESEARCH.md
@.planning/phases/03-daily-plan-and-cleanliness/03-01-SUMMARY.md
@lib/features/home/presentation/home_screen.dart
@lib/features/tasks/presentation/task_row.dart
@lib/features/tasks/presentation/task_providers.dart
@lib/features/tasks/domain/relative_date.dart
@lib/core/router/router.dart
@lib/l10n/app_de.arb
<interfaces>
<!-- From Plan 01 outputs -- executor should use these directly -->
From lib/features/home/domain/daily_plan_models.dart:
```dart
class TaskWithRoom {
final Task task;
final String roomName;
final int roomId;
const TaskWithRoom({required this.task, required this.roomName, required this.roomId});
}
class DailyPlanState {
final List<TaskWithRoom> overdueTasks;
final List<TaskWithRoom> todayTasks;
final List<TaskWithRoom> tomorrowTasks;
final int completedTodayCount;
final int totalTodayCount; // overdue + today + completedTodayCount
const DailyPlanState({...});
}
```
From lib/features/home/presentation/daily_plan_providers.dart:
```dart
final dailyPlanProvider = StreamProvider.autoDispose<DailyPlanState>((ref) { ... });
```
From lib/features/tasks/presentation/task_providers.dart:
```dart
@riverpod
class TaskActions extends _$TaskActions {
Future<void> completeTask(int taskId) async { ... }
}
```
From lib/features/tasks/domain/relative_date.dart:
```dart
String formatRelativeDate(DateTime dueDate, DateTime today);
// Returns: "Heute", "Morgen", "in X Tagen", "Uberfaellig seit X Tagen"
```
From lib/l10n/app_de.arb (Plan 01 additions):
```
dailyPlanProgress(completed, total) -> "{completed} von {total} erledigt"
dailyPlanSectionOverdue -> "Uberfaellig"
dailyPlanSectionToday -> "Heute"
dailyPlanSectionUpcoming -> "Demnachst"
dailyPlanUpcomingCount(count) -> "Demnachst ({count})"
dailyPlanAllClearTitle -> "Alles erledigt!"
dailyPlanAllClearMessage -> "Keine Aufgaben fuer heute. Geniesse den Moment!"
dailyPlanNoTasks -> "Noch keine Aufgaben angelegt"
```
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: DailyPlanTaskRow and ProgressCard widgets</name>
<files>
lib/features/home/presentation/daily_plan_task_row.dart,
lib/features/home/presentation/progress_card.dart
</files>
<action>
1. Create `lib/features/home/presentation/daily_plan_task_row.dart`:
- `class DailyPlanTaskRow extends StatelessWidget` (NOT ConsumerWidget -- no ref needed; completion callback passed in)
- Constructor params: `required TaskWithRoom taskWithRoom`, `required bool showCheckbox`, `VoidCallback? onCompleted`
- Build a `ListTile` with:
- `leading`: If showCheckbox, a `Checkbox(value: false, onChanged: (_) => onCompleted?.call())`. If not showCheckbox, null (tomorrow tasks are read-only)
- `title`: `Text(task.name)` with titleMedium, maxLines 1, ellipsis overflow
- `subtitle`: A `Row` containing:
a. Room name tag: `GestureDetector` wrapping a `Container` with `secondaryContainer` background, rounded corners (4px), containing `Text(roomName)` in `labelSmall` with `onSecondaryContainer` color. `onTap: () => context.go('/rooms/${taskWithRoom.roomId}')`
b. `SizedBox(width: 8)`
c. Relative date text via `formatRelativeDate(task.nextDueDate, DateTime.now())`. Color: `_overdueColor` (0xFFE07A5F) if overdue, `onSurfaceVariant` otherwise. Overdue check: dueDate (date-only) < today (date-only)
- NO `onTap` -- per user decision, daily plan task rows have no row-tap navigation. Only checkbox and room tag are interactive
- NO `onLongPress` -- no edit/delete from daily plan
2. Create `lib/features/home/presentation/progress_card.dart`:
- `class ProgressCard extends StatelessWidget`
- Constructor: `required int completed`, `required int total`
- Build a `Card` with `margin: EdgeInsets.all(16)`:
- `Text(l10n.dailyPlanProgress(completed, total))` in `titleMedium` with `fontWeight: FontWeight.bold`
- `SizedBox(height: 12)`
- `ClipRRect(borderRadius: 4)` wrapping `LinearProgressIndicator`:
- `value: total > 0 ? completed / total : 0.0`
- `minHeight: 8`
- `backgroundColor: colorScheme.surfaceContainerHighest`
- `color: colorScheme.primary`
- When total is 0 and completed is 0 (no tasks at all), the progress card should still render gracefully (0.0 progress, "0 von 0 erledigt")
</action>
<verify>
<automated>cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && dart analyze lib/features/home/presentation/daily_plan_task_row.dart lib/features/home/presentation/progress_card.dart</automated>
</verify>
<done>
- DailyPlanTaskRow renders task name, room name tag (tappable, navigates to room), relative date (coral if overdue)
- DailyPlanTaskRow has checkbox only when showCheckbox=true (overdue/today), hidden for tomorrow
- DailyPlanTaskRow has NO onTap or onLongPress on the row itself
- ProgressCard shows "X von Y erledigt" text with linear progress bar
- Both widgets pass dart analyze
</done>
</task>
<task type="auto">
<name>Task 2: HomeScreen rewrite with daily plan sections, animated completion, empty state, and tests</name>
<files>
lib/features/home/presentation/home_screen.dart,
test/features/home/presentation/home_screen_test.dart
</files>
<action>
1. COMPLETE REWRITE of `lib/features/home/presentation/home_screen.dart`:
- Change from `StatelessWidget` to `ConsumerStatefulWidget` (needs ref for providers AND state for AnimatedList keys)
- `ref.watch(dailyPlanProvider)` in build method
- Use `AsyncValue.when(loading: ..., error: ..., data: ...)` pattern:
- `loading`: Center(child: CircularProgressIndicator())
- `error`: Center(child: Text(error.toString()))
- `data`: Build the daily plan UI
DAILY PLAN UI STRUCTURE (data case):
a. **"No tasks at all" state**: If totalTodayCount == 0 AND tomorrowTasks.isEmpty AND completedTodayCount == 0, show the existing empty state pattern (homeEmptyTitle / homeEmptyMessage / homeEmptyAction button navigating to /rooms). This covers the case where the user has not created any rooms/tasks yet. Use `dailyPlanNoTasks` localization key for this.
b. **"All clear" state** (PLAN-06): If overdueTasks.isEmpty AND todayTasks.isEmpty AND completedTodayCount > 0, show celebration empty state: `Icons.celebration_outlined` (size 80, onSurface alpha 0.4), `dailyPlanAllClearTitle`, `dailyPlanAllClearMessage`. This means there WERE tasks today but they're all done.
c. **"Also all clear but nothing was ever due today"**: If overdueTasks.isEmpty AND todayTasks.isEmpty AND completedTodayCount == 0 AND tomorrowTasks.isNotEmpty, show same celebration empty state but with the progress card showing 0/0 and then the tomorrow section. (Edge case: nothing today, but stuff tomorrow.)
d. **Normal state** (tasks exist): `ListView` with:
1. `ProgressCard(completed: completedTodayCount, total: totalTodayCount)` -- always first
2. If overdueTasks.isNotEmpty: Section header "Uberfaellig" (titleMedium, warm coral color 0xFFE07A5F) with `Padding(horizontal: 16, vertical: 8)`, followed by `DailyPlanTaskRow` for each overdue task with `showCheckbox: true`
3. Section header "Heute" (titleMedium, primary color) with same padding, followed by `DailyPlanTaskRow` for each today task with `showCheckbox: true`
4. If tomorrowTasks.isNotEmpty: `ExpansionTile` with `initiallyExpanded: false`, title: `dailyPlanUpcomingCount(count)` in titleMedium. Children: `DailyPlanTaskRow` for each tomorrow task with `showCheckbox: false`
COMPLETION ANIMATION (PLAN-04):
- For the simplicity-first approach (avoiding AnimatedList desync pitfalls from research): When checkbox is tapped, call `ref.read(taskActionsProvider.notifier).completeTask(taskId)`. The Drift stream will naturally re-emit without the completed task (its nextDueDate moves to the future). This provides a seamless removal.
- To add visual feedback: Wrap each DailyPlanTaskRow in the overdue and today sections with an `AnimatedSwitcher` (or use `AnimatedList` if confident). The simplest approach: maintain a local `Set<int> _completingTaskIds` in state. When checkbox tapped, add taskId to set, triggering a rebuild that wraps the row in `SizeTransition` animating to zero height over 300ms. After animation, the stream re-emission removes it permanently.
- Alternative simpler approach: Use a plain ListView. On checkbox tap, fire completeTask(). The stream re-emission rebuilds the list without the task. No explicit animation, but the progress counter updates immediately giving visual feedback. This is acceptable for v1.
- RECOMMENDED: Use `AnimatedList` with `GlobalKey<AnimatedListState>` for overdue+today section. On completion, call `removeItem()` with `SizeTransition + SlideTransition` (slide right, 300ms, easeInOut). Fire `completeTask()` simultaneously. When the stream re-emits, compare with local list and reconcile. See research Pattern 3 for exact code. BUT if this proves complex during implementation, fall back to the simpler "let stream handle it" approach.
2. Create `test/features/home/presentation/home_screen_test.dart`:
- Use provider override pattern (same as app_shell_test.dart):
- Override `dailyPlanProvider` with a `StreamProvider` returning test data
- Override `appDatabaseProvider` if needed
- Test cases:
a. Empty state: When no tasks exist, shows homeEmptyTitle text and action button
b. All clear state: When overdue=[], today=[], completedTodayCount > 0, shows "Alles erledigt!" text
c. Normal state: When tasks exist, shows progress card with correct counts
d. Overdue section: When overdue tasks exist, shows "Uberfaellig" header
e. Tomorrow section: Shows collapsed "Demnachst" header with count
3. Run `flutter test` to confirm all tests pass (existing + new).
</action>
<verify>
<automated>cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && flutter test test/features/home/presentation/home_screen_test.dart && flutter test</automated>
</verify>
<done>
- HomeScreen fully replaced with daily plan: progress card at top, overdue section (conditional), today section, tomorrow section (collapsed ExpansionTile)
- Checkbox on overdue/today tasks triggers completion via taskActionsProvider, task animates out or disappears on stream re-emission
- Tomorrow tasks are read-only (no checkbox)
- Room name tags navigate to room task list via context.go
- "All clear" empty state shown when all today's tasks are done
- "No tasks" empty state shown when no tasks exist at all
- Widget tests cover empty state, all clear state, normal state with sections
- Full test suite passes
- CLEAN-01 verified: room cards already show cleanliness indicator (no new work needed)
</done>
</task>
</tasks>
<verification>
- `flutter test test/features/home/` -- all home feature tests pass
- `flutter test` -- full suite passes (no regressions)
- `dart analyze` -- clean analysis
- HomeScreen shows daily plan with all three sections
- CLEAN-01 confirmed via existing room card cleanliness indicator
</verification>
<success_criteria>
- HomeScreen replaced with complete daily plan (no more placeholder)
- Progress card shows "X von Y erledigt" with accurate counts
- Overdue tasks highlighted with warm coral section header, only shown when overdue tasks exist
- Today tasks shown in dedicated section with checkboxes
- Tomorrow tasks in collapsed ExpansionTile, read-only
- Checkbox completion triggers database update and task disappears
- "All clear" empty state displays when all tasks done
- Room name tags navigate to room task list
- No row-tap navigation on task rows (daily plan is focused action screen)
- CLEAN-01 verified on room cards
</success_criteria>
<output>
After completion, create `.planning/phases/03-daily-plan-and-cleanliness/03-02-SUMMARY.md`
</output>

View File

@@ -0,0 +1,111 @@
---
phase: 03-daily-plan-and-cleanliness
plan: 03
type: execute
wave: 3
depends_on:
- 03-02
files_modified: []
autonomous: false
requirements:
- PLAN-01
- PLAN-02
- PLAN-03
- PLAN-04
- PLAN-05
- PLAN-06
- CLEAN-01
must_haves:
truths:
- "dart analyze reports zero issues"
- "Full test suite passes (flutter test)"
- "All Phase 3 requirements verified functional"
artifacts: []
key_links: []
---
<objective>
Verification gate for Phase 3: confirm all daily plan requirements are working end-to-end. Run automated checks and perform visual/functional verification.
Purpose: Ensure Phase 3 is complete and the daily plan is the app's primary, functional home screen.
Output: Verification confirmation or list of issues to fix.
</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/03-daily-plan-and-cleanliness/3-CONTEXT.md
@.planning/phases/03-daily-plan-and-cleanliness/03-01-SUMMARY.md
@.planning/phases/03-daily-plan-and-cleanliness/03-02-SUMMARY.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Run automated verification suite</name>
<files></files>
<action>
Run in sequence:
1. `dart analyze` -- must report zero issues
2. `flutter test` -- full suite must pass (all existing + new Phase 3 tests)
3. Report results: total tests, pass count, any failures
If any issues found, fix them before proceeding to checkpoint.
</action>
<verify>
<automated>cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && dart analyze && flutter test</automated>
</verify>
<done>
- dart analyze: zero issues
- flutter test: all tests pass
</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<name>Task 2: Visual and functional verification of daily plan</name>
<files></files>
<action>
Present the verification checklist to the user. All automated work is already complete from Plans 01 and 02.
</action>
<what-built>
Complete daily plan feature (Phase 3): The Home tab now shows the daily plan with progress tracking, overdue/today/tomorrow task sections, checkbox completion, and room navigation. Cleanliness indicators are already on room cards from Phase 2.
</what-built>
<how-to-verify>
1. Launch app: `flutter run`
2. PLAN-01: Home tab shows tasks due today. Each task row displays the room name as a small tag
3. PLAN-02: If any tasks are overdue, they appear in a separate "Uberfaellig" section at the top with warm coral highlighting
4. PLAN-03: Scroll down to see "Demnachst (N)" section -- it should be collapsed. Tap to expand and see tomorrow's tasks (read-only, no checkboxes)
5. PLAN-04: Tap a checkbox on an overdue or today task -- the task should complete and disappear from the list
6. PLAN-05: The progress card at the top shows "X von Y erledigt" -- verify the counter updates when you complete a task
7. PLAN-06: Complete all overdue and today tasks -- the screen should show "Alles erledigt!" celebration empty state
8. CLEAN-01: Switch to Rooms tab -- each room card still shows the cleanliness indicator bar
9. Room name tag: Tap a room name tag on a task row -- should navigate to that room's task list
</how-to-verify>
<verify>User confirms all 9 verification steps pass</verify>
<done>All Phase 3 requirements verified functional by user</done>
<resume-signal>Type "approved" or describe issues to fix</resume-signal>
</task>
</tasks>
<verification>
- Automated: dart analyze clean + flutter test all pass
- Manual: All 7 Phase 3 requirements verified by user
</verification>
<success_criteria>
- All automated checks pass
- User confirms all Phase 3 requirements work correctly
- Phase 3 is complete
</success_criteria>
<output>
After completion, create `.planning/phases/03-daily-plan-and-cleanliness/03-03-SUMMARY.md`
</output>