---
phase: 05-calendar-strip
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - lib/features/home/data/calendar_dao.dart
  - lib/features/home/data/calendar_dao.g.dart
  - lib/features/home/domain/calendar_models.dart
  - lib/features/home/presentation/calendar_providers.dart
  - lib/core/database/database.dart
  - lib/core/database/database.g.dart
  - lib/l10n/app_de.arb
  - lib/l10n/app_localizations_de.dart
  - lib/l10n/app_localizations.dart
  - test/features/home/data/calendar_dao_test.dart
autonomous: true
requirements:
  - CAL-02
  - CAL-05

must_haves:
  truths:
    - "Querying tasks for any arbitrary date returns exactly the tasks whose nextDueDate falls on that day"
    - "Querying overdue tasks for today returns all tasks whose nextDueDate is strictly before today"
    - "Querying a future date returns only tasks due that day, no overdue carry-over"
    - "CalendarState model holds selectedDate, overdue tasks, and day tasks as separate lists"
    - "Localization strings for calendar UI exist in ARB and generated files"
  artifacts:
    - path: "lib/features/home/data/calendar_dao.dart"
      provides: "Date-parameterized task queries"
      exports: ["CalendarDao"]
    - path: "lib/features/home/domain/calendar_models.dart"
      provides: "CalendarState and reuse of TaskWithRoom"
      exports: ["CalendarState"]
    - path: "lib/features/home/presentation/calendar_providers.dart"
      provides: "Riverpod provider for calendar state"
      exports: ["calendarProvider", "selectedDateProvider"]
    - path: "test/features/home/data/calendar_dao_test.dart"
      provides: "DAO unit tests"
      min_lines: 50
  key_links:
    - from: "lib/features/home/data/calendar_dao.dart"
      to: "lib/core/database/database.dart"
      via: "DAO registered in @DriftDatabase annotation"
      pattern: "CalendarDao"
    - from: "lib/features/home/presentation/calendar_providers.dart"
      to: "lib/features/home/data/calendar_dao.dart"
      via: "Provider reads CalendarDao from AppDatabase"
      pattern: "db\\.calendarDao"
---

<objective>
Create the data layer, domain models, Riverpod providers, and localization strings for the calendar strip feature.

Purpose: The calendar strip UI (Plan 02) needs a data foundation that can answer "what tasks are due on date X?" and "what tasks are overdue relative to today?" without the old overdue/today/tomorrow bucketing. This plan builds that foundation and tests it.

Output: CalendarDao with date-parameterized queries, CalendarState model, Riverpod providers (selectedDateProvider + calendarProvider), new l10n strings, DAO 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/05-calendar-strip/5-CONTEXT.md

<interfaces>
<!-- Key types and contracts the executor needs. Extracted from codebase. -->

From lib/core/database/database.dart:
```dart
// Tables: Rooms, Tasks, TaskCompletions
// Existing DAOs: RoomsDao, TasksDao, DailyPlanDao
// CalendarDao must be added to the @DriftDatabase annotation daos list
// and imported at the top of database.dart

@DriftDatabase(
  tables: [Rooms, Tasks, TaskCompletions],
  daos: [RoomsDao, TasksDao, DailyPlanDao],  // ADD CalendarDao here
)
class AppDatabase extends _$AppDatabase { ... }
```

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});
}
```

From lib/features/home/presentation/daily_plan_providers.dart:
```dart
// Pattern to follow: StreamProvider.autoDispose, manual (not @riverpod)
// because of drift's generated Task type
final dailyPlanProvider = StreamProvider.autoDispose<DailyPlanState>((ref) {
  final db = ref.watch(appDatabaseProvider);
  ...
});
```

From lib/features/home/data/daily_plan_dao.dart:
```dart
// Pattern: @DriftAccessor with tables, extends DatabaseAccessor<AppDatabase>
// Uses query.watch() for reactive streams
@DriftAccessor(tables: [Tasks, Rooms, TaskCompletions])
class DailyPlanDao extends DatabaseAccessor<AppDatabase> with _$DailyPlanDaoMixin { ... }
```

From lib/core/providers/database_provider.dart:
```dart
// appDatabaseProvider gives access to the database singleton
```
</interfaces>
</context>

<tasks>

<task type="auto" tdd="true">
  <name>Task 1: Create CalendarDao with date-parameterized queries and tests</name>
  <files>
    lib/features/home/data/calendar_dao.dart,
    lib/core/database/database.dart,
    test/features/home/data/calendar_dao_test.dart
  </files>
  <behavior>
    - watchTasksForDate(date): returns tasks whose nextDueDate falls on the given calendar day (same year/month/day), joined with room name, sorted by task name alphabetically
    - watchOverdueTasks(referenceDate): returns tasks whose nextDueDate is strictly before referenceDate (start of day), joined with room name, sorted by nextDueDate ascending
    - watchTasksForDate for a date with no tasks returns empty list
    - watchOverdueTasks returns empty when no tasks are overdue
    - watchOverdueTasks does NOT include tasks due on the referenceDate itself
    - watchTasksForDate for a past date returns only tasks originally due that day (does NOT include overdue carry-over)
  </behavior>
  <action>
    1. Create `lib/features/home/data/calendar_dao.dart`:
       - Class `CalendarDao` extends `DatabaseAccessor<AppDatabase>` with `_$CalendarDaoMixin`
       - Annotated `@DriftAccessor(tables: [Tasks, Rooms, TaskCompletions])`
       - `part 'calendar_dao.g.dart';`
       - Method `Stream<List<TaskWithRoom>> watchTasksForDate(DateTime date)`:
         Compute startOfDay and endOfDay (startOfDay + 1 day). Join tasks with rooms. Filter `tasks.nextDueDate >= startOfDay AND tasks.nextDueDate < endOfDay`. Order by `tasks.name` ascending. Map to `TaskWithRoom`.
       - Method `Stream<List<TaskWithRoom>> watchOverdueTasks(DateTime referenceDate)`:
         Compute startOfReferenceDay. Join tasks with rooms. Filter `tasks.nextDueDate < startOfReferenceDay`. Order by `tasks.nextDueDate` ascending. Map to `TaskWithRoom`.
       - Import `daily_plan_models.dart` for `TaskWithRoom` (reuse, don't duplicate).

    2. Register CalendarDao in `lib/core/database/database.dart`:
       - Add import: `import '../../features/home/data/calendar_dao.dart';`
       - Add `CalendarDao` to the `daos:` list in `@DriftDatabase`

    3. Run `dart run build_runner build --delete-conflicting-outputs` to generate `calendar_dao.g.dart` and updated `database.g.dart`.

    4. Write `test/features/home/data/calendar_dao_test.dart` following the pattern in `test/features/home/data/daily_plan_dao_test.dart`:
       - Use in-memory database: `AppDatabase(NativeDatabase.memory())`
       - Create test rooms in setUp
       - Test group for watchTasksForDate:
         - Empty when no tasks
         - Returns only tasks due on the queried date (not before, not after)
         - Returns tasks from multiple rooms
         - Sorted alphabetically by name
       - Test group for watchOverdueTasks:
         - Empty when no overdue tasks
         - Returns tasks due before reference date
         - Does NOT include tasks due ON the reference date
         - Sorted by nextDueDate ascending
  </action>
  <verify>
    <automated>cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && flutter test test/features/home/data/calendar_dao_test.dart</automated>
  </verify>
  <done>CalendarDao registered in AppDatabase, both query methods return correct results for arbitrary dates, all DAO tests pass</done>
</task>

<task type="auto">
  <name>Task 2: Create CalendarState model, Riverpod providers, and localization strings</name>
  <files>
    lib/features/home/domain/calendar_models.dart,
    lib/features/home/presentation/calendar_providers.dart,
    lib/l10n/app_de.arb
  </files>
  <action>
    1. Create `lib/features/home/domain/calendar_models.dart`:
       ```dart
       import 'package:household_keeper/features/home/domain/daily_plan_models.dart';

       /// State for the calendar day view: tasks for the selected date + overdue tasks.
       class CalendarDayState {
         final DateTime selectedDate;
         final List<TaskWithRoom> dayTasks;
         final List<TaskWithRoom> overdueTasks;

         const CalendarDayState({
           required this.selectedDate,
           required this.dayTasks,
           required this.overdueTasks,
         });

         /// True when viewing today and all tasks (day + overdue) have been completed
         /// (lists are empty but completions exist). Determined by the UI layer.
         bool get isEmpty => dayTasks.isEmpty && overdueTasks.isEmpty;
       }
       ```

    2. Create `lib/features/home/presentation/calendar_providers.dart`:
       - Import Riverpod, database_provider, calendar_dao, calendar_models, daily_plan_models
       - `final selectedDateProvider = StateProvider<DateTime>((ref) { final now = DateTime.now(); return DateTime(now.year, now.month, now.day); });`
         This is NOT autoDispose -- the selected date persists as long as the app is alive (resets on restart naturally).
       - `final calendarDayProvider = StreamProvider.autoDispose<CalendarDayState>((ref) { ... });`
         Manual definition (not @riverpod) following dailyPlanProvider pattern.
         Reads `selectedDateProvider` to get the current date.
         Reads `appDatabaseProvider` to get the DB.
         Determines if selectedDate is today: `isToday = selectedDate == DateTime(now.year, now.month, now.day)`.
         Determines if selectedDate is in the future: `isFuture = selectedDate.isAfter(today)`.
         Watches `db.calendarDao.watchTasksForDate(selectedDate)`.
         For overdue: if `isToday`, also watch `db.calendarDao.watchOverdueTasks(selectedDate)`.
         If viewing a past date or future date, overdueTasks = empty.
         Per user decision: "When viewing past days: show what was due that day. When viewing future days: show only tasks due that day, no overdue carry-over."
         Combine both streams using `Rx.combineLatest2` or simply use `asyncMap` on the day tasks stream and fetch overdue as a secondary query.

         Implementation approach: Use the dayTasks stream as the primary, and inside asyncMap call the overdue stream's `.first` when isToday. This keeps it simple and follows the existing `dailyPlanProvider` pattern of `stream.asyncMap()`.

    3. Add new l10n strings to `lib/l10n/app_de.arb` (add before the closing `}`):
       - `"calendarNoTasks": "Keine Aufgaben"` — shown when a day has no tasks at all
       - `"calendarAllDone": "Alles erledigt!"` — celebration when all tasks for a day are done
       - `"calendarOverdueSection": "Uberfaellig"` — No, reuse existing `dailyPlanSectionOverdue` ("Uberfaellig") for the overdue section header
       - `"calendarTodayButton": "Heute"` — floating today button label

       Actually, we can reuse `dailyPlanSectionOverdue` for the overdue header, `dailyPlanNoTasks` for no-tasks-at-all, and `dailyPlanAllClearTitle`/`dailyPlanAllClearMessage` for celebration. The only truly new string needed is for the Today button:
       - Add `"calendarTodayButton": "Heute"` to the ARB file

    4. Run `flutter gen-l10n` to regenerate localization files.
  </action>
  <verify>
    <automated>cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && flutter analyze --no-fatal-infos</automated>
  </verify>
  <done>CalendarDayState model exists with selectedDate/dayTasks/overdueTasks fields. selectedDateProvider and calendarDayProvider are defined. calendarDayProvider returns overdue tasks only when viewing today. New l10n string "calendarTodayButton" exists. No analysis errors.</done>
</task>

</tasks>

<verification>
- `flutter test test/features/home/data/calendar_dao_test.dart` — all DAO tests pass
- `flutter analyze --no-fatal-infos` — no errors in new or modified files
- `flutter test` — full test suite still passes (existing tests not broken by database.dart changes)
</verification>

<success_criteria>
- CalendarDao is registered in AppDatabase and has two working query methods
- CalendarDayState model correctly separates day tasks from overdue tasks
- calendarDayProvider returns overdue only for today, not for past/future dates
- All existing tests still pass after database.dart modification
- New DAO tests cover core query behaviors
</success_criteria>

<output>
After completion, create `.planning/phases/05-calendar-strip/05-01-SUMMARY.md`
</output>
