docs(phase-2): complete phase execution

This commit is contained in:
2026-03-15 22:29:38 +01:00
parent 6ad42536e9
commit 98f42ccb9c
2 changed files with 198 additions and 3 deletions

View File

@@ -2,9 +2,9 @@
gsd_state_version: 1.0 gsd_state_version: 1.0
milestone: v1.0 milestone: v1.0
milestone_name: milestone milestone_name: milestone
status: executing status: planning
stopped_at: Completed 02-05-PLAN.md stopped_at: Completed 02-05-PLAN.md (Phase 2 complete)
last_updated: "2026-03-15T21:22:53Z" last_updated: "2026-03-15T21:29:33.821Z"
last_activity: 2026-03-15 — Completed 02-05-PLAN.md (Phase 2 verification gate passed) last_activity: 2026-03-15 — Completed 02-05-PLAN.md (Phase 2 verification gate passed)
progress: progress:
total_phases: 4 total_phases: 4

View File

@@ -0,0 +1,195 @@
---
phase: 02-rooms-and-tasks
verified: 2026-03-15T22:00:00Z
status: human_needed
score: 15/15 must-haves verified
human_verification:
- test: "Run the app and create a room named 'Kueche'. Verify the template picker bottom sheet appears with German task templates after saving."
expected: "Template picker shows 5 Kueche templates (Abspuelen, Herd reinigen, etc.), all unchecked. Selecting some and tapping 'Hinzufuegen' creates those tasks in the room."
why_human: "Modal bottom sheet display and CheckboxListTile interaction cannot be verified programmatically without a running device."
- test: "Tap checkbox on a task. Verify the next due date updates and the task re-sorts in the list."
expected: "Checkbox triggers completion, next due date advances by the task interval, task moves to correct sort position if needed. No undo prompt appears."
why_human: "Real-time UI update and sort behavior require running app observation."
- test: "Create multiple rooms and drag one to a new position. Navigate away and back."
expected: "Reordered position persists after returning to the rooms screen."
why_human: "Drag-and-drop interaction and persistence across navigation require a running device."
- test: "Create a task with monthly interval. Mark it done. Observe the new due date."
expected: "New due date is exactly one month later from the original due date (not from today). If the original was past-due, catch-up logic advances to a future date."
why_human: "Calendar-anchored rescheduling and catch-up logic correctness with real data requires running app observation."
- test: "Create a task with a past due date (edit nextDueDate in DB or set initial date to yesterday). Verify the overdue indicator."
expected: "Due date text on the task row appears in warm coral/red. Room card cleanliness progress bar shifts toward red."
why_human: "Visual color rendering and gradient bar value require running device."
---
# Phase 2: Rooms and Tasks Verification Report
**Phase Goal:** Users can create and manage rooms and tasks, mark tasks done, and trust the app to schedule the next occurrence automatically
**Verified:** 2026-03-15T22:00:00Z
**Status:** human_needed (all automated checks pass; 5 UI behaviors require running device confirmation)
**Re-verification:** No — initial verification
---
## Goal Achievement
### Observable Truths
| # | Truth | Status | Evidence |
|---|-------|--------|----------|
| 1 | Room CRUD operations work correctly at the database layer | VERIFIED | `rooms_dao.dart`: insert, update, deleteRoom (transaction with cascade), reorderRooms all implemented; 6 DAO tests green |
| 2 | Task CRUD operations work correctly at the database layer | VERIFIED | `tasks_dao.dart`: insert, update, deleteTask (transaction), watchTasksInRoom ordered by nextDueDate; 7 DAO tests green |
| 3 | Task completion records timestamp and auto-calculates next due date | VERIFIED | `tasks_dao.dart` lines 42-81: transaction inserts TaskCompletion, calls `calculateNextDueDate` then `catchUpToPresent`, writes updated nextDueDate |
| 4 | All 8 interval types and custom intervals produce correct next due dates | VERIFIED | `scheduling.dart`: all 8 IntervalType cases handled via switch; 17 scheduling tests green |
| 5 | Calendar-anchored intervals clamp to last day of month with anchor memory | VERIFIED | `scheduling.dart` `_addMonths()` helper uses anchorDay parameter; test "monthly from Jan 31 gives Feb 28, then Mar 31" in scheduling_test.dart |
| 6 | Catch-up logic advances past-due dates to next future occurrence | VERIFIED | `catchUpToPresent` while loop in `scheduling.dart` lines 50-66; test coverage confirms |
| 7 | All 14 room types have bundled German-language task templates | VERIFIED | `task_templates.dart`: 14 keys present (kueche through garten), 3-5 templates each; 11 template tests green |
| 8 | Overdue detection correctly identifies tasks with nextDueDate before today | VERIFIED | `tasks_dao.dart` `getOverdueTaskCount()`, `rooms_dao.dart` `watchRoomWithStats()`, `task_row.dart` `isOverdue` check — all use `dueDate.isBefore(today)` logic |
| 9 | User can create/edit a room with name and icon from curated picker | VERIFIED | `room_form_screen.dart` 272 lines: full form with validation, `icon_picker_sheet.dart` 94 lines: 5-column grid of 25 icons |
| 10 | User can see rooms as 2-column card grid with icon, name, due count, cleanliness bar | VERIFIED | `rooms_screen.dart`: ReorderableBuilder + GridView.count(crossAxisCount:2); `room_card.dart`: LinearProgressIndicator(minHeight:3) with Color.lerp sage-to-coral |
| 11 | User can reorder rooms via drag-and-drop | VERIFIED | `rooms_screen.dart` lines 133-155: ReorderableBuilder.onReorder calls `roomActionsProvider.notifier.reorderRooms()` |
| 12 | User can see all tasks in a room sorted by due date | VERIFIED | `task_list_screen.dart` watches `tasksInRoomProvider(roomId)`; DAO orders by nextDueDate ASC |
| 13 | User can create/edit/delete tasks with frequency and effort selectors | VERIFIED | `task_form_screen.dart` 442 lines: ChoiceChip wrap for 10 presets + custom, SegmentedButton for effort, date picker; delete via long-press confirmation dialog |
| 14 | User can mark task done, which triggers auto-rescheduling | VERIFIED | `task_row.dart` line 61: checkbox calls `taskActionsProvider.notifier.completeTask(task.id)`, which calls `tasks_dao.completeTask()` transaction |
| 15 | Template picker shows after room creation for matched room names | VERIFIED | `room_form_screen.dart` lines 86-101: `detectRoomType(name)``showTemplatePickerSheet()``_createTasksFromTemplates()` |
**Score: 15/15 truths verified**
---
### Required Artifacts
| Artifact | Min Lines | Actual Lines | Status | Details |
|----------|-----------|--------------|--------|---------|
| `lib/core/database/database.dart` | — | 83 | VERIFIED | schemaVersion=2, 3 tables, daos:[RoomsDao,TasksDao], MigrationStrategy with PRAGMA foreign_keys |
| `lib/features/rooms/data/rooms_dao.dart` | — | 127 | VERIFIED | All 6 CRUD methods + watchAllRooms + watchRoomWithStats + cascade delete transaction |
| `lib/features/tasks/data/tasks_dao.dart` | — | 102 | VERIFIED | All 5 CRUD methods + completeTask transaction + getOverdueTaskCount |
| `lib/features/tasks/domain/scheduling.dart` | — | 66 | VERIFIED | calculateNextDueDate (8 cases) + catchUpToPresent |
| `lib/features/tasks/domain/frequency.dart` | — | 62 | VERIFIED | IntervalType enum (8 values, indexed), FrequencyInterval with presets (10) and German labels |
| `lib/features/tasks/domain/effort_level.dart` | — | 23 | VERIFIED | EffortLevel enum (3 values, indexed), EffortLevelLabel extension with German labels |
| `lib/features/tasks/domain/relative_date.dart` | — | 18 | VERIFIED | formatRelativeDate returns Heute/Morgen/in X Tagen/Uberfaellig |
| `lib/features/rooms/domain/room_icons.dart` | — | 40 | VERIFIED | curatedRoomIcons (25 entries), mapIconName with fallback |
| `lib/features/templates/data/task_templates.dart` | — | 371 | VERIFIED | TaskTemplate class, roomTemplates (14 types, 3-5 each), detectRoomType with alias map |
| `lib/features/rooms/presentation/rooms_screen.dart` | 50 | 188 | VERIFIED | ConsumerWidget, AsyncValue.when, ReorderableBuilder grid, empty state, FAB, delete dialog |
| `lib/features/rooms/presentation/room_card.dart` | 40 | 123 | VERIFIED | InkWell→/rooms/{id}, icon, name, dueTasks badge, LinearProgressIndicator(minHeight:3), long-press menu |
| `lib/features/rooms/presentation/room_form_screen.dart` | 50 | 272 | VERIFIED | ConsumerStatefulWidget, create+edit modes, name validation, icon picker, detectRoomType+template flow |
| `lib/features/rooms/presentation/icon_picker_sheet.dart` | 30 | 94 | VERIFIED | showIconPickerSheet helper, GridView.count(5), selected highlight with primaryContainer |
| `lib/features/rooms/presentation/room_providers.dart` | — | 48 | VERIFIED | roomWithStatsListProvider stream, RoomActions notifier (create/update/delete/reorder) |
| `lib/features/tasks/presentation/task_list_screen.dart` | 50 | 228 | VERIFIED | ConsumerWidget, tasksInRoomProvider, empty state, ListView, FAB, AppBar with edit/delete |
| `lib/features/tasks/presentation/task_row.dart` | 40 | 106 | VERIFIED | ListTile, Checkbox→completeTask, formatRelativeDate, isOverdue coral color, onTap→edit, onLongPress→delete |
| `lib/features/tasks/presentation/task_form_screen.dart` | 80 | 442 | VERIFIED | ConsumerStatefulWidget, ChoiceChip frequency wrap, SegmentedButton effort, date picker, create+edit |
| `lib/features/tasks/presentation/task_providers.dart` | — | 65 | VERIFIED | tasksInRoomProvider (manual StreamProvider.family), TaskActions notifier (CRUD + completeTask) |
| `lib/features/templates/presentation/template_picker_sheet.dart` | 40 | 198 | VERIFIED | TemplatePickerSheet StatefulWidget, DraggableScrollableSheet, CheckboxListTile, skip/add buttons |
| `lib/core/router/router.dart` | — | 85 | VERIFIED | /rooms/new, /rooms/:roomId, /rooms/:roomId/edit, /rooms/:roomId/tasks/new, /rooms/:roomId/tasks/:taskId |
---
### Key Link Verification
| From | To | Via | Status | Details |
|------|----|-----|--------|---------|
| `tasks_dao.dart` | `scheduling.dart` | completeTask calls calculateNextDueDate + catchUpToPresent | WIRED | Lines 57, 70: both functions called in transaction |
| `database.dart` | `rooms_dao.dart` | daos: [RoomsDao, TasksDao] annotation | WIRED | Line 47: `daos: [RoomsDao, TasksDao]` |
| `database.dart` | `tasks_dao.dart` | daos annotation | WIRED | Line 47: confirmed |
| `database.dart` | `frequency.dart` | intEnum<IntervalType> column | WIRED | Line 28: `intEnum<IntervalType>()()` on intervalType column |
| `room_providers.dart` | `rooms_dao.dart` | ref.watch(appDatabaseProvider) | WIRED | Line 12: `ref.watch(appDatabaseProvider)` then `db.roomsDao.watchRoomWithStats()` |
| `rooms_screen.dart` | `room_providers.dart` | ref.watch(roomWithStatsListProvider) | WIRED | Line 21: `ref.watch(roomWithStatsListProvider)` |
| `room_card.dart` | `router.dart` | context.go('/rooms/…') | WIRED | Line 43: `context.go('/rooms/${room.id}')` |
| `task_providers.dart` | `tasks_dao.dart` | ref.watch(appDatabaseProvider) | WIRED | Line 18: `ref.watch(appDatabaseProvider)` then `db.tasksDao.watchTasksInRoom(roomId)` |
| `task_list_screen.dart` | `task_providers.dart` | ref.watch(tasksInRoomProvider(roomId)) | WIRED | Line 24: `ref.watch(tasksInRoomProvider(roomId))` |
| `task_row.dart` | `relative_date.dart` | formatRelativeDate for German labels | WIRED | Line 47: `formatRelativeDate(task.nextDueDate, now)` |
| `task_row.dart` | `task_providers.dart` | checkbox onChanged calls taskActions.completeTask | WIRED | Line 61: `ref.read(taskActionsProvider.notifier).completeTask(task.id)` |
| `room_form_screen.dart` | `task_templates.dart` | detectRoomType on room name after save | WIRED | Line 86: `detectRoomType(name)` |
| `room_form_screen.dart` | `template_picker_sheet.dart` | showTemplatePickerSheet on match | WIRED | Line 90: `showTemplatePickerSheet(context: context, ...)` |
| `room_form_screen.dart` | `task_providers.dart` | _createTasksFromTemplates calls taskActions.createTask | WIRED | Line 123: `taskActions.createTask(...)` inside `_createTasksFromTemplates` |
**All 14 key links: WIRED**
---
### Requirements Coverage
| Requirement | Source Plan | Description | Status | Evidence |
|-------------|-------------|-------------|--------|----------|
| ROOM-01 | 02-01, 02-02 | Create room with name and curated icon | SATISFIED | RoomFormScreen + IconPickerSheet + RoomsDao.insertRoom |
| ROOM-02 | 02-01, 02-02 | Edit room name and icon | SATISFIED | RoomFormScreen(roomId:) edit mode + RoomsDao.updateRoom |
| ROOM-03 | 02-01, 02-02 | Delete room with confirmation (cascade) | SATISFIED | Confirmation dialog + RoomsDao.deleteRoom (transaction cascade) |
| ROOM-04 | 02-01, 02-02 | Reorder rooms via drag-and-drop | SATISFIED | ReorderableBuilder in RoomsScreen + RoomsDao.reorderRooms |
| ROOM-05 | 02-01, 02-02 | Room cards with icon, name, due count, cleanliness indicator | SATISFIED | RoomCard: icon, name, dueTasks badge, LinearProgressIndicator with Color.lerp |
| TASK-01 | 02-01, 02-03 | Create task with name, description, frequency, effort | SATISFIED | TaskFormScreen (create mode) + TaskActions.createTask |
| TASK-02 | 02-01, 02-03 | Edit task name, description, frequency, effort | SATISFIED | TaskFormScreen (edit mode): loads existing task, all fields editable |
| TASK-03 | 02-01, 02-03 | Delete task with confirmation | SATISFIED | TaskRow long-press → confirmation dialog → TaskActions.deleteTask |
| TASK-04 | 02-01, 02-03 | Frequency interval presets (10 options) + custom | SATISFIED | FrequencyInterval.presets (10 entries: daily through yearly) + custom ChoiceChip + number/unit picker |
| TASK-05 | 02-01, 02-03 | Effort level (low/medium/high) | SATISFIED | EffortLevel enum + SegmentedButton in TaskFormScreen |
| TASK-06 | 02-01, 02-03 | Tasks sorted by due date | SATISFIED | watchTasksInRoom orders by nextDueDate ASC at DAO level |
| TASK-07 | 02-01, 02-03 | Mark task done, records completion, auto-schedules | SATISFIED | Checkbox → completeTask → TasksDao transaction (insert completion + calculateNextDueDate + catchUpToPresent + update) |
| TASK-08 | 02-01, 02-03 | Overdue tasks visually highlighted | SATISFIED | task_row.dart: isOverdue → `_overdueColor` (0xFFE07A5F) on due date text; room_card.dart: cleanlinessRatio → red progress bar |
| TMPL-01 | 02-01, 02-04 | Template selection prompt after room creation | SATISFIED | room_form_screen.dart: detectRoomType → showTemplatePickerSheet → _createTasksFromTemplates |
| TMPL-02 | 02-01, 02-04 | 14 preset room types with German templates | SATISFIED | task_templates.dart: kueche, badezimmer, schlafzimmer, wohnzimmer, flur, buero, garage, balkon, waschkueche, keller, kinderzimmer, gaestezimmer, esszimmer, garten (14 confirmed) |
**15/15 requirements satisfied. No orphaned requirements.**
---
### Anti-Patterns Found
| File | Line | Pattern | Severity | Impact |
|------|------|---------|----------|--------|
| None | — | — | — | — |
No TODO/FIXME comments, no placeholder bodies, no empty implementations found. `dart analyze lib/` reports zero issues.
---
### Human Verification Required
The following items require a running device. All automated checks pass (59/59 tests green, dart analyze clean), but these visual and interaction behaviors cannot be confirmed programmatically:
#### 1. Template Picker Appearance and Selection
**Test:** Run the app. Tap FAB on the Rooms screen. Enter "Kueche" as room name. Select any icon. Tap the check button.
**Expected:** A bottom sheet slides up showing 5 task templates (Abspuelen, Herd reinigen, Kuehlschrank reinigen, Backofen reinigen, Muell rausbringen) as CheckboxListTiles, all unchecked. Each shows frequency and effort label. Tapping "Uberspringen" navigates to the room without tasks. Checking templates and tapping "Hinzufuegen" creates those tasks and navigates to the room.
**Why human:** Modal bottom sheet rendering and CheckboxListTile state cannot be exercised without a real Flutter runtime.
#### 2. Task Completion and Auto-Rescheduling Feel
**Test:** Open any room with tasks. Tap the leading checkbox on a task.
**Expected:** The task's due date updates immediately (reactive stream). The task may re-sort in the list. No undo prompt. For a weekly task, the new due date is exactly 7 days from the original due date (not from today).
**Why human:** Real-time stream propagation and sort-order change require observing a running UI.
#### 3. Drag-and-Drop Reorder Persistence
**Test:** Create 3+ rooms. Long-press a room card and drag it to a new position. Navigate to Settings and back to Rooms.
**Expected:** The new room order persists after navigation.
**Why human:** Drag gesture, onReorder callback, and persistence across navigation require device interaction.
#### 4. Overdue Highlighting Visual Rendering
**Test:** Create a task and manually set its initial due date to yesterday (or two days ago). Navigate back to the task list.
**Expected:** The due date text on that task row is warm coral (0xFFE07A5F). The room card's cleanliness bar shifts toward red.
**Why human:** Color rendering values and gradient interpolation require visual inspection.
#### 5. Custom Room Without Template Prompt
**Test:** Create a room named "Mein Hobbyraum".
**Expected:** No template picker bottom sheet appears. The app navigates directly to the (empty) task list for the new room.
**Why human:** Confirming absence of UI elements requires running device observation.
---
### Summary
Phase 2 is fully implemented at the code level. The goal — "Users can create and manage rooms and tasks, mark tasks done, and trust the app to schedule the next occurrence automatically" — is achieved by the codebase:
- **Data layer (Plan 02-01):** Drift schema v2 with Rooms/Tasks/TaskCompletions tables, RoomsDao and TasksDao with all CRUD operations, pure scheduling utility handling all 8 interval types with calendar anchoring and catch-up logic, and German task templates for all 14 room types.
- **Room UI (Plan 02-02):** 2-column reorderable card grid, create/edit form with icon picker, cascade-warning delete dialog, cleanliness progress bar.
- **Task UI (Plan 02-03):** Task list screen with sorted rows, checkbox completion, overdue coral highlighting, create/edit form with frequency presets and custom interval, effort selector.
- **Template flow (Plan 02-04):** Room creation detects room type, shows checklist bottom sheet, creates selected tasks atomically.
All 59 unit tests pass. All 14 key links are wired. All 15 requirements are satisfied. Zero placeholder code or dart analysis issues detected.
The remaining items flagged for human verification are purely visual or interaction behaviors that cannot be confirmed without a running device.
---
*Verified: 2026-03-15T22:00:00Z*
*Verifier: Claude (gsd-verifier)*