Compare commits
14 Commits
88519f2de8
...
v1.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 1a1a10c9ea | |||
| 36126acc18 | |||
| 76192e22fa | |||
| 9c2ae12012 | |||
| dcb2cd0afa | |||
| c2570cdc01 | |||
| 3c2ad5c7c6 | |||
| f6272a39b4 | |||
| 170326dd85 | |||
| 74de67de59 | |||
| b0765795b8 | |||
| 489c0d5c4f | |||
| 967dc7d09a | |||
| 998f2be87f |
145
.gitea/workflows/release.yaml
Normal file
145
.gitea/workflows/release.yaml
Normal file
@@ -0,0 +1,145 @@
|
||||
name: Build and Release to F-Droid
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: docker
|
||||
env:
|
||||
ANDROID_HOME: /opt/android-sdk
|
||||
ANDROID_SDK_ROOT: /opt/android-sdk
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: '17'
|
||||
|
||||
- name: Setup Android SDK
|
||||
uses: android-actions/setup-android@v3
|
||||
|
||||
- name: Install Android SDK packages
|
||||
run: |
|
||||
sdkmanager --licenses >/dev/null <<'EOF'
|
||||
y
|
||||
y
|
||||
y
|
||||
y
|
||||
y
|
||||
y
|
||||
y
|
||||
y
|
||||
y
|
||||
y
|
||||
EOF
|
||||
sdkmanager "platform-tools" "platforms;android-36" "build-tools;36.0.0"
|
||||
|
||||
- name: Install jq
|
||||
run: |
|
||||
set -e
|
||||
SUDO=""
|
||||
if command -v sudo >/dev/null 2>&1; then
|
||||
SUDO="sudo"
|
||||
fi
|
||||
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
$SUDO apt-get update
|
||||
$SUDO apt-get install -y jq
|
||||
elif command -v apk >/dev/null 2>&1; then
|
||||
$SUDO apk add --no-cache jq
|
||||
elif command -v dnf >/dev/null 2>&1; then
|
||||
$SUDO dnf install -y jq
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
$SUDO yum install -y jq
|
||||
else
|
||||
echo "Could not find a supported package manager to install jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Setup Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: 'stable'
|
||||
|
||||
- name: Trust Flutter SDK git directory
|
||||
run: |
|
||||
set -e
|
||||
FLUTTER_BIN_DIR="$(dirname "$(command -v flutter)")"
|
||||
FLUTTER_SDK_DIR="$(cd "$FLUTTER_BIN_DIR/.." && pwd -P)"
|
||||
git config --global --add safe.directory "$FLUTTER_SDK_DIR"
|
||||
if [ -n "${FLUTTER_ROOT:-}" ]; then
|
||||
git config --global --add safe.directory "$FLUTTER_ROOT"
|
||||
fi
|
||||
# Runner-specific fallback observed in failing logs
|
||||
git config --global --add safe.directory /opt/hostedtoolcache/flutter/stable-3.41.4-x64 || true
|
||||
|
||||
- name: Verify Android + Flutter toolchain
|
||||
run: flutter doctor -v
|
||||
|
||||
- name: Install dependencies
|
||||
run: flutter pub get
|
||||
|
||||
# ADD THIS NEW STEP
|
||||
- name: Setup Android Keystore
|
||||
env:
|
||||
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
|
||||
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
|
||||
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
|
||||
run: |
|
||||
# Decode the base64 string back into the binary .jks file
|
||||
echo "$KEYSTORE_BASE64" | base64 --decode > android/app/upload-keystore.jks
|
||||
|
||||
# Create the key.properties file that build.gradle expects
|
||||
echo "storePassword=$KEY_PASSWORD" > android/key.properties
|
||||
echo "keyPassword=$KEY_PASSWORD" >> android/key.properties
|
||||
echo "keyAlias=$KEY_ALIAS" >> android/key.properties
|
||||
echo "storeFile=upload-keystore.jks" >> android/key.properties
|
||||
|
||||
- name: Build APK
|
||||
run: flutter build apk --release
|
||||
|
||||
- name: Setup F-Droid Server Tools
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y fdroidserver sshpass
|
||||
|
||||
- name: Initialize or fetch F-Droid Repository
|
||||
env:
|
||||
HOST: ${{ secrets.HETZNER_HOST }}
|
||||
USER: ${{ secrets.HETZNER_USER }}
|
||||
PASS: ${{ secrets.HETZNER_PASS }}
|
||||
run: |
|
||||
mkdir -p fdroid
|
||||
cd fdroid
|
||||
|
||||
# Try to download the existing repo/ folder from Hetzner to keep older versions and the keystore
|
||||
# If it fails (first time), we just initialize a new one
|
||||
sshpass -p "$PASS" scp -o StrictHostKeyChecking=no -r $USER@$HOST:dev/fdroid/repo . || fdroid init
|
||||
|
||||
- name: Copy new APK to repo
|
||||
run: |
|
||||
# The app-release.apk name should ideally include the version number
|
||||
# so it doesn't overwrite older versions in the repo.
|
||||
VERSION_TAG=${GITHUB_REF#refs/tags/} # gets 'v1.0.0'
|
||||
cp build/app/outputs/flutter-apk/app-release.apk fdroid/repo/my_flutter_app_${VERSION_TAG}.apk
|
||||
|
||||
- name: Generate F-Droid Index
|
||||
run: |
|
||||
cd fdroid
|
||||
fdroid update -c
|
||||
|
||||
- name: Upload Repo to Hetzner
|
||||
env:
|
||||
HOST: ${{ secrets.HETZNER_HOST }}
|
||||
USER: ${{ secrets.HETZNER_USER }}
|
||||
PASS: ${{ secrets.HETZNER_PASS }}
|
||||
run: |
|
||||
# Use rsync to efficiently upload only the changed files (the new APK and updated index files)
|
||||
sshpass -p "$PASS" rsync -avz -e "ssh -o StrictHostKeyChecking=no" fdroid/repo/ $USER@$HOST:dev/fdroid/repo/
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -118,3 +118,5 @@ app.*.symbols
|
||||
!**/ios/**/default.perspectivev3
|
||||
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||
!/dev/ci/**/Gemfile.lock
|
||||
|
||||
.idea
|
||||
20
.planning/MILESTONES.md
Normal file
20
.planning/MILESTONES.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Milestones
|
||||
|
||||
## v1.0 MVP (Shipped: 2026-03-16)
|
||||
|
||||
**Phases completed:** 4 phases, 13 plans
|
||||
**Codebase:** 10,588 LOC Dart (7,773 lib + 2,815 test), 89 tests, 76 commits
|
||||
**Timeline:** 2 days (2026-03-15 to 2026-03-16)
|
||||
|
||||
**Key accomplishments:**
|
||||
1. Flutter project with Drift SQLite, Riverpod 3 state management, ARB localization, and calm sage & stone Material 3 theme
|
||||
2. Full room CRUD with drag-and-drop reorder, icon picker, and cleanliness indicator per room card
|
||||
3. Task CRUD with 11 frequency presets + custom intervals, calendar-anchored scheduling with anchor memory, and auto-calculated next due dates
|
||||
4. Bundled German-language task templates for 14 room types with post-creation template picker
|
||||
5. Daily plan home screen with overdue/today/tomorrow sections, animated checkbox completion, and progress tracking
|
||||
6. Daily summary notification with configurable time, POST_NOTIFICATIONS permission handling, and boot receiver rescheduling
|
||||
|
||||
**Archive:** See `milestones/v1.0-ROADMAP.md` and `milestones/v1.0-REQUIREMENTS.md`
|
||||
|
||||
---
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## What This Is
|
||||
|
||||
A local-first Flutter app for organizing household chores and one-time projects, built for personal/couple use on Android. Takes the room-based task scheduling model (inspired by BeTidy), strips cloud/account/social features, and wraps it in a calm, minimal Material 3 UI. Fully offline, free, privacy-respecting — all data stays on-device.
|
||||
A local-first Flutter app for organizing household chores, built for personal/couple use on Android. Uses a room-based task scheduling model where users create rooms, add recurring tasks with frequency intervals, and the app auto-calculates the next due date after each completion. Features a daily plan home screen, bundled German-language task templates, room cleanliness indicators, and daily summary notifications. Fully offline, free, privacy-respecting — all data stays on-device.
|
||||
|
||||
## Core Value
|
||||
|
||||
@@ -12,20 +12,22 @@ Users can see what needs doing today, mark it done, and trust the app to schedul
|
||||
|
||||
### Validated
|
||||
|
||||
(None yet — ship to validate)
|
||||
- Room CRUD with icons and drag-and-drop reorder — v1.0
|
||||
- Task CRUD with frequency intervals and due date calculation — v1.0
|
||||
- Daily plan view with overdue/today/upcoming sections — v1.0
|
||||
- Task completion with auto-scheduling of next due date — v1.0
|
||||
- Bundled task templates per room type (German only, 14 room types) — v1.0
|
||||
- Daily summary notification with configurable time — v1.0
|
||||
- Light/dark theme with calm Material 3 palette — v1.0
|
||||
- Cleanliness indicator per room (based on overdue vs on-time) — v1.0
|
||||
|
||||
### Active
|
||||
|
||||
- [ ] Room CRUD with icons and optional photos
|
||||
- [ ] Task CRUD with frequency intervals and due date calculation
|
||||
- [ ] Daily plan view with overdue/today/upcoming sections
|
||||
- [ ] Task completion with auto-scheduling of next due date
|
||||
- [ ] Bundled task templates per room type (German only)
|
||||
- [ ] Daily summary notification
|
||||
- [ ] Light/dark theme with calm Material 3 palette
|
||||
- [ ] Cleanliness indicator per room (based on overdue vs on-time)
|
||||
- [ ] Task sorting (due date, alphabetical, interval, effort)
|
||||
- [ ] Task history (completion log per task)
|
||||
- [ ] Data export/import (JSON)
|
||||
- [ ] English localization
|
||||
- [ ] Room cover photos from camera or gallery
|
||||
- [ ] Task completion history log
|
||||
- [ ] Additional task sorting (alphabetical, interval, effort)
|
||||
|
||||
### Out of Scope
|
||||
|
||||
@@ -34,8 +36,9 @@ Users can see what needs doing today, mark it done, and trust the app to schedul
|
||||
- Subscription model / in-app purchases — free forever
|
||||
- Family profile sharing across devices — single-device app
|
||||
- Server-side infrastructure — zero backend
|
||||
- Data export/import (JSON) — deferred to v1.1
|
||||
- English localization — deferred to v1.1 (ship German-only MVP)
|
||||
- AI-powered task suggestions — overkill for curated templates
|
||||
- Per-task push notifications — daily summary is more effective
|
||||
- Firebase or any Google cloud services — contradicts local-first design
|
||||
- Real-time cross-device sync — potential future self-hosted feature
|
||||
- Tablet-optimized layout — future enhancement
|
||||
- Statistics & insights dashboard — v2.0
|
||||
@@ -44,11 +47,11 @@ Users can see what needs doing today, mark it done, and trust the app to schedul
|
||||
|
||||
## Context
|
||||
|
||||
- Inspired by BeTidy (iOS/Android household cleaning app) — taking the proven room-based model, removing cloud/social, refining the UI
|
||||
- Shipped v1.0 MVP with 10,588 LOC Dart (7,773 lib + 2,815 test), 89 tests
|
||||
- Tech stack: Flutter + Dart, Riverpod 3 + code generation, Drift 2.31 SQLite, GoRouter, flutter_local_notifications
|
||||
- Inspired by BeTidy (iOS/Android household cleaning app) — room-based model, no cloud/social
|
||||
- Built for personal use with partner on a shared Android device; may publish publicly later
|
||||
- Code and comments in English; UI strings German-only for MVP
|
||||
- Room photos are nice-to-have for MVP — icon-only rooms are sufficient initially
|
||||
- Developer is new to Drift (SQLite ORM) — plan should account for learning curve
|
||||
- Code and comments in English; UI strings German-only for v1.0
|
||||
- Gitea (self-hosted on Hetzner) for version control; no CI/CD pipeline yet
|
||||
|
||||
## Constraints
|
||||
@@ -57,20 +60,23 @@ Users can see what needs doing today, mark it done, and trust the app to schedul
|
||||
- **Platform**: Android-first (iOS later)
|
||||
- **Offline**: 100% offline-capable, zero network dependencies
|
||||
- **Privacy**: No data leaves the device, no analytics, no tracking
|
||||
- **Language**: German-only UI for MVP, English code/comments
|
||||
- **Language**: German-only UI for v1.0, English code/comments
|
||||
- **No CI**: No automated build pipeline initially
|
||||
|
||||
## Key Decisions
|
||||
|
||||
| Decision | Rationale | Outcome |
|
||||
|----------|-----------|---------|
|
||||
| Riverpod over Bloc | Modern, compile-safe, less boilerplate, Dart-native | — Pending |
|
||||
| Drift over raw sqflite | Type-safe queries, compile-time validation, migration support | — Pending |
|
||||
| Android-first | Primary device is Android; iOS follows | — Pending |
|
||||
| German-only MVP | Primary user language; defer localization infrastructure | — Pending |
|
||||
| No CI initially | Keep scope focused on the app itself | — Pending |
|
||||
| Calm Material 3 palette | Muted greens, warm grays, gentle blues — calm productivity, not playful | — Pending |
|
||||
| Clean Architecture | Feature-based folder structure with data/domain/presentation layers | — Pending |
|
||||
| Riverpod 3 over Bloc | Modern, compile-safe, less boilerplate, Dart-native | Good — code generation works well, @riverpod annotation reduces boilerplate |
|
||||
| Drift over raw sqflite | Type-safe queries, compile-time validation, migration support | Good — DAOs with stream queries provide reactive UI, migration workflow established |
|
||||
| Android-first | Primary device is Android; iOS follows | Good — no iOS-specific issues encountered |
|
||||
| German-only MVP | Primary user language; defer localization infrastructure | Good — ARB localization infrastructure in place from Phase 1, ready for English |
|
||||
| No CI initially | Keep scope focused on the app itself | Good — manual dart analyze + flutter test sufficient for solo dev |
|
||||
| Calm Material 3 palette | Muted greens, warm grays, gentle blues — calm productivity | Good — sage & stone theme (seed 0xFF7A9A6D) with warm charcoal dark mode |
|
||||
| Clean Architecture | Feature-based folder structure with data/domain/presentation layers | Good — clear separation, easy to navigate |
|
||||
| Calendar-anchored scheduling | Monthly/quarterly/yearly tasks anchor to original day-of-month with clamping | Good — handles Feb 28/31 edge cases correctly with anchor memory |
|
||||
| flutter_local_notifications v21 | Standard Flutter notification package, TZ-aware scheduling | Good — inexactAllowWhileIdle avoids SCHEDULE_EXACT_ALARM complexity |
|
||||
| Manual StreamProvider for drift types | riverpod_generator throws InvalidTypeException with drift Task type | Revisit — may be fixed in future riverpod_generator versions |
|
||||
|
||||
---
|
||||
*Last updated: 2026-03-15 after initialization*
|
||||
*Last updated: 2026-03-16 after v1.0 milestone*
|
||||
|
||||
65
.planning/RETROSPECTIVE.md
Normal file
65
.planning/RETROSPECTIVE.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Project Retrospective
|
||||
|
||||
*A living document updated after each milestone. Lessons feed forward into future planning.*
|
||||
|
||||
## Milestone: v1.0 — MVP
|
||||
|
||||
**Shipped:** 2026-03-16
|
||||
**Phases:** 4 | **Plans:** 13
|
||||
|
||||
### What Was Built
|
||||
- Complete room-based household chore app with auto-scheduling task management
|
||||
- Daily plan home screen with overdue/today/tomorrow sections and progress tracking
|
||||
- Bundled German task templates for 14 room types
|
||||
- Daily summary notifications with configurable time and Android permission handling
|
||||
- 89 tests covering DAOs, scheduling logic, providers, and widget behavior
|
||||
|
||||
### What Worked
|
||||
- Bottom-up phase structure (foundation -> data -> UI -> polish) kept each phase clean with minimal rework
|
||||
- TDD approach for providers and services caught several issues early (async race conditions, API mismatches)
|
||||
- Verification gates at the end of Phase 2, 3, and 4 confirmed all requirements before moving on
|
||||
- Calendar-anchored scheduling with anchor memory was designed right the first time — no rework needed
|
||||
- ARB localization from Phase 1 meant adding German strings was frictionless throughout
|
||||
|
||||
### What Was Inefficient
|
||||
- riverpod_generator InvalidTypeException with drift Task type required workaround (manual StreamProvider) in 3 separate plans — should have been caught in Phase 1 research
|
||||
- Some plan specifications referenced outdated API patterns (flutter_local_notifications positional parameters removed in v20+) — research needs to verify exact current API signatures
|
||||
- Phase 4 plan checkboxes in ROADMAP.md weren't updated to [x] by executor — minor bookkeeping gap
|
||||
|
||||
### Patterns Established
|
||||
- `@Riverpod(keepAlive: true)` AsyncNotifier with SharedPreferences for persistent settings (ThemeNotifier, NotificationSettingsNotifier)
|
||||
- Manual StreamProvider.family/autoDispose for drift type compatibility
|
||||
- DailyPlanDao innerJoin pattern for cross-table queries
|
||||
- ConsumerStatefulWidget for screens with async callbacks requiring `mounted` guards
|
||||
- Provider override pattern in widget tests for database isolation
|
||||
|
||||
### Key Lessons
|
||||
1. Research phase should verify exact current package API signatures — breaking changes between major versions cause plan deviations
|
||||
2. Drift + riverpod_generator type incompatibility is a known issue — plan for manual providers from the start when using drift
|
||||
3. Verification gates add minimal time (~2 min) but catch integration issues — keep them for all phases
|
||||
4. Progressive disclosure (AnimatedSize) is a clean pattern for conditional settings UI
|
||||
|
||||
### Cost Observations
|
||||
- Model mix: orchestrator on opus, researchers/planners/executors/checkers on sonnet
|
||||
- Total execution: ~1.3 hours for 13 plans across 4 phases
|
||||
- Notable: Verification gates averaged 2 min — very efficient for the confidence they provide
|
||||
|
||||
---
|
||||
|
||||
## Cross-Milestone Trends
|
||||
|
||||
### Process Evolution
|
||||
|
||||
| Milestone | Phases | Plans | Key Change |
|
||||
|-----------|--------|-------|------------|
|
||||
| v1.0 | 4 | 13 | Initial project — established all patterns |
|
||||
|
||||
### Cumulative Quality
|
||||
|
||||
| Milestone | Tests | Key Metric |
|
||||
|-----------|-------|------------|
|
||||
| v1.0 | 89 | dart analyze clean, 0 issues |
|
||||
|
||||
### Top Lessons (Verified Across Milestones)
|
||||
|
||||
1. (Single milestone — lessons above will be cross-validated as more milestones ship)
|
||||
@@ -1,100 +1,28 @@
|
||||
# Roadmap: HouseHoldKeaper
|
||||
|
||||
## Overview
|
||||
## Milestones
|
||||
|
||||
Four phases build the app bottom-up along its natural dependency chain. Phase 1 lays the technical foundation every subsequent phase relies on. Phase 2 delivers complete room and task management — the core scheduling loop. Phase 3 surfaces that data as the daily plan view (the primary user experience) and adds the cleanliness indicator. Phase 4 adds notifications and completes the v1 feature set. After Phase 3, the app is usable daily. After Phase 4, it is releasable.
|
||||
- **v1.0 MVP** — Phases 1-4 (shipped 2026-03-16)
|
||||
|
||||
## Phases
|
||||
|
||||
**Phase Numbering:**
|
||||
- Integer phases (1, 2, 3): Planned milestone work
|
||||
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
|
||||
<details>
|
||||
<summary>v1.0 MVP (Phases 1-4) — SHIPPED 2026-03-16</summary>
|
||||
|
||||
Decimal phases appear between their surrounding integers in numeric order.
|
||||
- [x] Phase 1: Foundation (2/2 plans) — completed 2026-03-15
|
||||
- [x] Phase 2: Rooms and Tasks (5/5 plans) — completed 2026-03-15
|
||||
- [x] Phase 3: Daily Plan and Cleanliness (3/3 plans) — completed 2026-03-16
|
||||
- [x] Phase 4: Notifications (3/3 plans) — completed 2026-03-16
|
||||
|
||||
- [x] **Phase 1: Foundation** - Project scaffold, database, state management, theme, and localization infrastructure (completed 2026-03-15)
|
||||
- [x] **Phase 2: Rooms and Tasks** - Complete room CRUD, task CRUD with auto-scheduling, and bundled templates (completed 2026-03-15)
|
||||
- [x] **Phase 3: Daily Plan and Cleanliness** - Primary daily plan screen with overdue/today/upcoming, cleanliness indicators per room (completed 2026-03-16)
|
||||
- [x] **Phase 4: Notifications** - Daily summary notification with configurable time and Android permission handling (completed 2026-03-16)
|
||||
See `milestones/v1.0-ROADMAP.md` for full phase details.
|
||||
|
||||
## Phase Details
|
||||
|
||||
### Phase 1: Foundation
|
||||
**Goal**: The app compiles, opens, and enforces correct architecture patterns — ready to receive features without accumulating technical debt
|
||||
**Depends on**: Nothing (first phase)
|
||||
**Requirements**: FOUND-01, FOUND-02, FOUND-03, FOUND-04, THEME-01, THEME-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. App launches on Android without errors and shows a bottom navigation bar with Home, Rooms, and Settings tabs
|
||||
2. Light and dark themes work correctly and follow the system setting by default, using the calm Material 3 palette (muted greens, warm grays, gentle blues)
|
||||
3. All UI strings are loaded from ARB localization files — no hardcoded German text in Dart code
|
||||
4. The Drift database opens on first launch with schemaVersion 1 and the migration workflow is established (drift_dev make-migrations runs without errors)
|
||||
5. riverpod_lint is active and flags ref.watch usage outside build() as an analysis error
|
||||
**Plans**: 2 plans
|
||||
Plans:
|
||||
- [x] 01-01-PLAN.md — Scaffold Flutter project and build core infrastructure (database, providers, theme, localization)
|
||||
- [x] 01-02-PLAN.md — Navigation shell, placeholder screens, Settings, and full app wiring
|
||||
|
||||
### Phase 2: Rooms and Tasks
|
||||
**Goal**: Users can create and manage rooms and tasks, mark tasks done, and trust the app to schedule the next occurrence automatically
|
||||
**Depends on**: Phase 1
|
||||
**Requirements**: ROOM-01, ROOM-02, ROOM-03, ROOM-04, ROOM-05, TASK-01, TASK-02, TASK-03, TASK-04, TASK-05, TASK-06, TASK-07, TASK-08, TMPL-01, TMPL-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can create a room with a name and icon, edit it, reorder rooms via drag-and-drop, and delete it (with confirmation that removes all associated tasks)
|
||||
2. User can create a task in a room with name, description, frequency interval (daily through yearly and custom), and effort level; tasks can be edited and deleted with confirmation
|
||||
3. When creating a room, user can select from bundled German-language task templates for the chosen room type (all 14 room types covered) and they are added to the room as tasks
|
||||
4. User can mark a task done (tap or swipe), which records the completion and sets the next due date correctly based on the interval
|
||||
5. Overdue tasks are visually highlighted with a distinct color or badge on room cards and in task lists; tasks within a room are sorted by due date by default
|
||||
6. Each room card shows its name, icon, count of due tasks, and cleanliness indicator
|
||||
**Plans**: 5 plans
|
||||
Plans:
|
||||
- [x] 02-01-PLAN.md — Data layer: Drift tables, migration v1->v2, DAOs, scheduling utility, domain models, templates, tests
|
||||
- [x] 02-02-PLAN.md — Room CRUD UI: 2-column card grid, room form, icon picker, drag-and-drop reorder, providers
|
||||
- [x] 02-03-PLAN.md — Task CRUD UI: task list, task row with completion, task form, overdue highlighting, providers
|
||||
- [x] 02-04-PLAN.md — Template selection: template picker bottom sheet, room type detection, integration with room creation
|
||||
- [x] 02-05-PLAN.md — Visual and functional verification checkpoint
|
||||
|
||||
### Phase 3: Daily Plan and Cleanliness
|
||||
**Goal**: Users can open the app and immediately see what needs doing today, act on tasks directly from the plan view, and see a room-level health indicator
|
||||
**Depends on**: Phase 2
|
||||
**Requirements**: PLAN-01, PLAN-02, PLAN-03, PLAN-04, PLAN-05, PLAN-06, CLEAN-01
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. The Home tab shows today's tasks grouped by room, with a separate highlighted section at the top for overdue tasks
|
||||
2. User can mark a task done directly from the daily plan view via swipe or checkbox without navigating to the room
|
||||
3. User can see upcoming tasks (tomorrow and this week) from the daily plan screen
|
||||
4. A progress indicator shows completed vs total tasks for today (e.g., "5 von 12 erledigt")
|
||||
5. When no tasks are due, an encouraging "all clear" empty state is shown instead of an empty list
|
||||
6. Each room card displays a cleanliness indicator derived from the ratio of overdue tasks to total tasks in that room
|
||||
**Plans**: 3 plans
|
||||
Plans:
|
||||
- [x] 03-01-PLAN.md — Data layer: DailyPlanDao with cross-room join query, providers, and localization keys
|
||||
- [x] 03-02-PLAN.md — Daily plan UI: HomeScreen rewrite with progress card, task sections, animated completion, empty state
|
||||
- [x] 03-03-PLAN.md — Visual and functional verification checkpoint
|
||||
|
||||
### Phase 4: Notifications
|
||||
**Goal**: Users receive a daily summary notification reminding them of today's task count, and can control notification behavior from settings
|
||||
**Depends on**: Phase 2
|
||||
**Requirements**: NOTF-01, NOTF-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User receives one daily notification showing the count of tasks due today, scheduled at a configurable time
|
||||
2. User can enable or disable notifications from the Settings tab, and the change takes effect immediately
|
||||
3. Notifications are correctly rescheduled after device reboot (RECEIVE_BOOT_COMPLETED receiver active)
|
||||
4. On Android API 33+, the app requests POST_NOTIFICATIONS permission at the appropriate moment and degrades gracefully if denied
|
||||
**Plans**: 3 plans
|
||||
Plans:
|
||||
- [ ] 04-01-PLAN.md — Infrastructure: packages, Android config, NotificationService, NotificationSettingsNotifier, DAO queries, timezone init, tests
|
||||
- [ ] 04-02-PLAN.md — Settings UI: Benachrichtigungen section with toggle, time picker, permission flow, scheduling wiring, tests
|
||||
- [ ] 04-03-PLAN.md — Verification gate: dart analyze + full test suite + requirement confirmation
|
||||
</details>
|
||||
|
||||
## Progress
|
||||
|
||||
**Execution Order:**
|
||||
Phases execute in numeric order: 1 -> 2 -> 3 -> 4
|
||||
|
||||
Note: Phase 4 depends on Phase 2 (needs scheduling data) but can be developed in parallel with Phase 3.
|
||||
|
||||
| Phase | Plans Complete | Status | Completed |
|
||||
|-------|----------------|--------|-----------|
|
||||
| 1. Foundation | 2/2 | Complete | 2026-03-15 |
|
||||
| 2. Rooms and Tasks | 5/5 | Complete | 2026-03-15 |
|
||||
| 3. Daily Plan and Cleanliness | 3/3 | Complete | 2026-03-16 |
|
||||
| 4. Notifications | 3/3 | Complete | 2026-03-16 |
|
||||
| Phase | Milestone | Plans Complete | Status | Completed |
|
||||
|-------|-----------|----------------|--------|-----------|
|
||||
| 1. Foundation | v1.0 | 2/2 | Complete | 2026-03-15 |
|
||||
| 2. Rooms and Tasks | v1.0 | 5/5 | Complete | 2026-03-15 |
|
||||
| 3. Daily Plan and Cleanliness | v1.0 | 3/3 | Complete | 2026-03-16 |
|
||||
| 4. Notifications | v1.0 | 3/3 | Complete | 2026-03-16 |
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
gsd_state_version: 1.0
|
||||
milestone: v1.0
|
||||
milestone_name: milestone
|
||||
status: executing
|
||||
stopped_at: Completed 04-03-PLAN.md (Phase 4 Verification Gate)
|
||||
last_updated: "2026-03-16T14:20:25.850Z"
|
||||
last_activity: 2026-03-16 — Completed 04-01-PLAN.md (Notification infrastructure)
|
||||
milestone_name: MVP
|
||||
status: shipped
|
||||
stopped_at: v1.0 milestone complete
|
||||
last_updated: "2026-03-16T20:00:00.000Z"
|
||||
last_activity: 2026-03-16 — v1.0 MVP milestone shipped
|
||||
progress:
|
||||
total_phases: 4
|
||||
completed_phases: 4
|
||||
@@ -18,26 +18,25 @@ progress:
|
||||
|
||||
## Project Reference
|
||||
|
||||
See: .planning/PROJECT.md (updated 2026-03-15)
|
||||
See: .planning/PROJECT.md (updated 2026-03-16)
|
||||
|
||||
**Core value:** Users can see what needs doing today, mark it done, and trust the app to schedule the next occurrence — without thinking about it.
|
||||
**Current focus:** Phase 4: Notifications (Phase 3 complete)
|
||||
**Current focus:** v1.0 shipped — planning next milestone
|
||||
|
||||
## Current Position
|
||||
|
||||
Phase: 4 of 4 (Notifications)
|
||||
Plan: 1 of 2 in current phase -- COMPLETE
|
||||
Status: Phase 4 in progress — plan 1 complete, plan 2 (Settings UI) pending
|
||||
Last activity: 2026-03-16 — Completed 04-01-PLAN.md (Notification infrastructure)
|
||||
Milestone: v1.0 MVP — SHIPPED 2026-03-16
|
||||
Status: All 4 phases complete, 13/13 plans executed, 89 tests passing
|
||||
Next: `/gsd:new-milestone` for v1.1
|
||||
|
||||
Progress: [██████████] 100%
|
||||
Progress: [##########] 100%
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
**Velocity:**
|
||||
- Total plans completed: 10
|
||||
- Average duration: 6.1 min
|
||||
- Total execution time: 1.0 hours
|
||||
- Total plans completed: 13
|
||||
- Total execution time: ~1.3 hours
|
||||
- Average duration: ~6 min/plan
|
||||
|
||||
**By Phase:**
|
||||
|
||||
@@ -46,85 +45,24 @@ Progress: [██████████] 100%
|
||||
| 1 - Foundation | 2 | 15 min | 7.5 min |
|
||||
| 2 - Rooms and Tasks | 5 | 35 min | 7.0 min |
|
||||
| 3 - Daily Plan and Cleanliness | 3 | 11 min | 3.7 min |
|
||||
|
||||
**Recent Trend:**
|
||||
- Last 5 plans: 02-04 (3 min), 02-05 (1 min), 03-01 (5 min), 03-02 (4 min), 03-03 (2 min)
|
||||
- Trend: Verification gates consistently fast (1-2 min)
|
||||
|
||||
*Updated after each plan completion*
|
||||
| Phase 02 P01 | 8 | 2 tasks | 16 files |
|
||||
| Phase 02 P02 | 11 | 2 tasks | 14 files |
|
||||
| Phase 02 P03 | 12 | 2 tasks | 8 files |
|
||||
| Phase 02 P04 | 3 | 2 tasks | 5 files |
|
||||
| Phase 02 P05 | 1 | 1 task | 0 files |
|
||||
| Phase 03 P01 | 5 | 2 tasks | 10 files |
|
||||
| Phase 03 P02 | 4 | 2 tasks | 5 files |
|
||||
| Phase 03 P03 | 2 | 2 tasks | 0 files |
|
||||
| Phase 04-notifications P01 | 9 | 2 tasks | 11 files |
|
||||
| Phase 04-notifications P02 | 5 | 2 tasks | 5 files |
|
||||
| Phase 04-notifications P03 | 2 | 1 tasks | 0 files |
|
||||
| 4 - Notifications | 3 | 16 min | 5.3 min |
|
||||
|
||||
## Accumulated Context
|
||||
|
||||
### Decisions
|
||||
|
||||
Decisions are logged in PROJECT.md Key Decisions table.
|
||||
Recent decisions affecting current work:
|
||||
|
||||
- [Pre-phase]: Riverpod 3.3 requires Flutter 3.41+ — verify before scaffolding
|
||||
- [Pre-phase]: All due dates stored as date-only (calendar day), not DateTime — enforce from first migration
|
||||
- [Pre-phase]: German-only UI for MVP; localization infrastructure (ARB + AppLocalizations) required from Phase 1 even with one locale
|
||||
- [Pre-phase]: riverpod_lint must be active before any feature code — catches ref.watch outside build() at analysis time
|
||||
- [Pre-phase]: drift_dev make-migrations workflow must be established in Phase 1 — recovery cost is data loss
|
||||
- [01-01]: Pinned drift/drift_dev to 2.31.0 for analyzer ^9.0.0 compatibility with riverpod_generator 4.0.3
|
||||
- [01-01]: Generated Riverpod 3 provider named themeProvider (not themeNotifierProvider) per new naming convention
|
||||
- [Phase 01-02]: Used themeProvider (Riverpod 3 naming) instead of themeNotifierProvider referenced in plan
|
||||
- [02-01]: Scheduling functions are top-level pure functions with DateTime today parameter for testability
|
||||
- [02-01]: Calendar-anchored intervals use anchorDay nullable field for month-clamping memory
|
||||
- [02-01]: RoomWithStats computed via asyncMap on watchAllRooms stream, not a custom SQL join
|
||||
- [02-01]: Templates stored as Dart const map for type safety, not JSON assets
|
||||
- [02-01]: detectRoomType uses contains-based matching with alias map
|
||||
- [Phase 02]: Scheduling functions are top-level pure functions with DateTime today parameter for testability
|
||||
- [Phase 02]: Calendar-anchored intervals use anchorDay nullable field for month-clamping memory
|
||||
- [Phase 02]: Templates stored as Dart const map for type safety, not JSON assets
|
||||
- [02-02]: ReorderableBuilder<Widget> with typed onReorder callback for drag-and-drop grid
|
||||
- [02-02]: Long-press context menu (bottom sheet) for edit/delete on room cards
|
||||
- [02-02]: Provider override pattern in tests to decouple from database dependency
|
||||
- [02-03]: tasksInRoomProvider defined as manual StreamProvider.family due to riverpod_generator InvalidTypeException with drift Task type
|
||||
- [02-03]: Frequency selector uses ChoiceChip Wrap layout for 10 presets plus custom option
|
||||
- [02-03]: TaskRow uses ListTile with middle-dot separator between relative date and frequency label
|
||||
- [02-04]: Template picker uses StatefulWidget (not Consumer) receiving data via constructor
|
||||
- [02-04]: Room creation navigates to /rooms/$roomId (context.go) instead of context.pop to show new room
|
||||
- [02-04]: Calendar-anchored intervals set anchorDay to today's day-of-month; day-count intervals set null
|
||||
- [02-05]: Auto-approved verification checkpoint: dart analyze clean, 59/59 tests passing, all Phase 2 code integrated
|
||||
- [03-01]: DailyPlanDao uses innerJoin (not leftOuterJoin) since tasks always have a room
|
||||
- [03-01]: watchCompletionsToday uses customSelect with readsFrom for proper stream invalidation
|
||||
- [03-01]: dailyPlanProvider uses manual StreamProvider.autoDispose (not @riverpod) due to drift Task type issue
|
||||
- [03-01]: Progress total = remaining overdue + remaining today + completedTodayCount for stable denominator
|
||||
- [03-02]: Used stream-driven completion with local _completingTaskIds Set for animation instead of AnimatedList
|
||||
- [03-02]: DailyPlanTaskRow is StatelessWidget (not ConsumerWidget) -- completion callback passed in from parent
|
||||
- [03-02]: No-tasks empty state uses dailyPlanNoTasks key for clearer daily plan context messaging
|
||||
- [03-03]: Phase 3 verification gate passed: dart analyze clean, 72/72 tests, all 7 requirements confirmed functional
|
||||
- [Phase 04-01]: timezone constraint upgraded to ^0.11.0 — flutter_local_notifications v21 requires ^0.11.0, plan specified ^0.9.4
|
||||
- [Phase 04-01]: flutter_local_notifications v21 uses named parameters in initialize() and zonedSchedule() — positional API removed in v20+
|
||||
- [Phase 04-01]: Generated Riverpod 3 provider named notificationSettingsProvider (not notificationSettingsNotifierProvider) — consistent with themeProvider naming convention
|
||||
- [Phase 04-01]: nextInstanceOf exposed as @visibleForTesting public method to enable TZ logic unit testing without native dispatch mocking
|
||||
- [Phase Phase 04-02]: openNotificationSettings() not available in flutter_local_notifications v21 — simplified to informational SnackBar (no action button)
|
||||
- [Phase Phase 04-02]: ConsumerStatefulWidget for SettingsScreen — async permission callbacks require mounted guards after every await
|
||||
- [Phase 04-notifications]: Phase 4 verification gate passed: dart analyze --fatal-infos zero issues, 89/89 tests passing — all NOTF-01 and NOTF-02 requirements confirmed functional
|
||||
All v1.0 decisions are recorded in PROJECT.md Key Decisions table with outcomes.
|
||||
|
||||
### Pending Todos
|
||||
|
||||
None yet.
|
||||
None.
|
||||
|
||||
### Blockers/Concerns
|
||||
|
||||
- ~~[Research]: Recurrence policy edge cases not fully specified~~ — **RESOLVED** in 2-CONTEXT.md: calendar-anchored intervals clamp to last day with anchor memory, day-count intervals roll forward. Next due from original due date. Catch-up skips to next future date.
|
||||
- [Research]: Notification time configuration (user-adjustable vs hardcoded) not resolved. Decide before Phase 4 planning.
|
||||
- ~~[Research]: First-launch template seeding UX (silent vs prompted) not resolved~~ — **RESOLVED** in 2-CONTEXT.md: post-creation prompt with all templates unchecked. Room type is optional, detected from name. Custom rooms skip templates entirely.
|
||||
None — all v1.0 blockers resolved.
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-03-16T14:13:32.148Z
|
||||
Stopped at: Completed 04-03-PLAN.md (Phase 4 Verification Gate)
|
||||
Last session: 2026-03-16
|
||||
Stopped at: v1.0 milestone complete
|
||||
Resume file: None
|
||||
|
||||
@@ -3,11 +3,16 @@
|
||||
"granularity": "coarse",
|
||||
"parallelization": true,
|
||||
"commit_docs": true,
|
||||
"model_profile": "quality",
|
||||
"model_profile": "balanced",
|
||||
"workflow": {
|
||||
"research": true,
|
||||
"plan_check": true,
|
||||
"verifier": true,
|
||||
"nyquist_validation": true
|
||||
"nyquist_validation": true,
|
||||
"auto_advance": true,
|
||||
"_auto_chain_active": true
|
||||
},
|
||||
"git": {
|
||||
"branching_strategy": "none"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,12 @@
|
||||
# Requirements Archive: v1.0 MVP
|
||||
|
||||
**Archived:** 2026-03-16
|
||||
**Status:** SHIPPED
|
||||
|
||||
For current requirements, see `.planning/REQUIREMENTS.md`.
|
||||
|
||||
---
|
||||
|
||||
# Requirements: HouseHoldKeaper
|
||||
|
||||
**Defined:** 2026-03-15
|
||||
100
.planning/milestones/v1.0-ROADMAP.md
Normal file
100
.planning/milestones/v1.0-ROADMAP.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Roadmap: HouseHoldKeaper
|
||||
|
||||
## Overview
|
||||
|
||||
Four phases build the app bottom-up along its natural dependency chain. Phase 1 lays the technical foundation every subsequent phase relies on. Phase 2 delivers complete room and task management — the core scheduling loop. Phase 3 surfaces that data as the daily plan view (the primary user experience) and adds the cleanliness indicator. Phase 4 adds notifications and completes the v1 feature set. After Phase 3, the app is usable daily. After Phase 4, it is releasable.
|
||||
|
||||
## Phases
|
||||
|
||||
**Phase Numbering:**
|
||||
- Integer phases (1, 2, 3): Planned milestone work
|
||||
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
|
||||
|
||||
Decimal phases appear between their surrounding integers in numeric order.
|
||||
|
||||
- [x] **Phase 1: Foundation** - Project scaffold, database, state management, theme, and localization infrastructure (completed 2026-03-15)
|
||||
- [x] **Phase 2: Rooms and Tasks** - Complete room CRUD, task CRUD with auto-scheduling, and bundled templates (completed 2026-03-15)
|
||||
- [x] **Phase 3: Daily Plan and Cleanliness** - Primary daily plan screen with overdue/today/upcoming, cleanliness indicators per room (completed 2026-03-16)
|
||||
- [x] **Phase 4: Notifications** - Daily summary notification with configurable time and Android permission handling (completed 2026-03-16)
|
||||
|
||||
## Phase Details
|
||||
|
||||
### Phase 1: Foundation
|
||||
**Goal**: The app compiles, opens, and enforces correct architecture patterns — ready to receive features without accumulating technical debt
|
||||
**Depends on**: Nothing (first phase)
|
||||
**Requirements**: FOUND-01, FOUND-02, FOUND-03, FOUND-04, THEME-01, THEME-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. App launches on Android without errors and shows a bottom navigation bar with Home, Rooms, and Settings tabs
|
||||
2. Light and dark themes work correctly and follow the system setting by default, using the calm Material 3 palette (muted greens, warm grays, gentle blues)
|
||||
3. All UI strings are loaded from ARB localization files — no hardcoded German text in Dart code
|
||||
4. The Drift database opens on first launch with schemaVersion 1 and the migration workflow is established (drift_dev make-migrations runs without errors)
|
||||
5. riverpod_lint is active and flags ref.watch usage outside build() as an analysis error
|
||||
**Plans**: 2 plans
|
||||
Plans:
|
||||
- [x] 01-01-PLAN.md — Scaffold Flutter project and build core infrastructure (database, providers, theme, localization)
|
||||
- [x] 01-02-PLAN.md — Navigation shell, placeholder screens, Settings, and full app wiring
|
||||
|
||||
### Phase 2: Rooms and Tasks
|
||||
**Goal**: Users can create and manage rooms and tasks, mark tasks done, and trust the app to schedule the next occurrence automatically
|
||||
**Depends on**: Phase 1
|
||||
**Requirements**: ROOM-01, ROOM-02, ROOM-03, ROOM-04, ROOM-05, TASK-01, TASK-02, TASK-03, TASK-04, TASK-05, TASK-06, TASK-07, TASK-08, TMPL-01, TMPL-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can create a room with a name and icon, edit it, reorder rooms via drag-and-drop, and delete it (with confirmation that removes all associated tasks)
|
||||
2. User can create a task in a room with name, description, frequency interval (daily through yearly and custom), and effort level; tasks can be edited and deleted with confirmation
|
||||
3. When creating a room, user can select from bundled German-language task templates for the chosen room type (all 14 room types covered) and they are added to the room as tasks
|
||||
4. User can mark a task done (tap or swipe), which records the completion and sets the next due date correctly based on the interval
|
||||
5. Overdue tasks are visually highlighted with a distinct color or badge on room cards and in task lists; tasks within a room are sorted by due date by default
|
||||
6. Each room card shows its name, icon, count of due tasks, and cleanliness indicator
|
||||
**Plans**: 5 plans
|
||||
Plans:
|
||||
- [x] 02-01-PLAN.md — Data layer: Drift tables, migration v1->v2, DAOs, scheduling utility, domain models, templates, tests
|
||||
- [x] 02-02-PLAN.md — Room CRUD UI: 2-column card grid, room form, icon picker, drag-and-drop reorder, providers
|
||||
- [x] 02-03-PLAN.md — Task CRUD UI: task list, task row with completion, task form, overdue highlighting, providers
|
||||
- [x] 02-04-PLAN.md — Template selection: template picker bottom sheet, room type detection, integration with room creation
|
||||
- [x] 02-05-PLAN.md — Visual and functional verification checkpoint
|
||||
|
||||
### Phase 3: Daily Plan and Cleanliness
|
||||
**Goal**: Users can open the app and immediately see what needs doing today, act on tasks directly from the plan view, and see a room-level health indicator
|
||||
**Depends on**: Phase 2
|
||||
**Requirements**: PLAN-01, PLAN-02, PLAN-03, PLAN-04, PLAN-05, PLAN-06, CLEAN-01
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. The Home tab shows today's tasks grouped by room, with a separate highlighted section at the top for overdue tasks
|
||||
2. User can mark a task done directly from the daily plan view via swipe or checkbox without navigating to the room
|
||||
3. User can see upcoming tasks (tomorrow and this week) from the daily plan screen
|
||||
4. A progress indicator shows completed vs total tasks for today (e.g., "5 von 12 erledigt")
|
||||
5. When no tasks are due, an encouraging "all clear" empty state is shown instead of an empty list
|
||||
6. Each room card displays a cleanliness indicator derived from the ratio of overdue tasks to total tasks in that room
|
||||
**Plans**: 3 plans
|
||||
Plans:
|
||||
- [x] 03-01-PLAN.md — Data layer: DailyPlanDao with cross-room join query, providers, and localization keys
|
||||
- [x] 03-02-PLAN.md — Daily plan UI: HomeScreen rewrite with progress card, task sections, animated completion, empty state
|
||||
- [x] 03-03-PLAN.md — Visual and functional verification checkpoint
|
||||
|
||||
### Phase 4: Notifications
|
||||
**Goal**: Users receive a daily summary notification reminding them of today's task count, and can control notification behavior from settings
|
||||
**Depends on**: Phase 2
|
||||
**Requirements**: NOTF-01, NOTF-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User receives one daily notification showing the count of tasks due today, scheduled at a configurable time
|
||||
2. User can enable or disable notifications from the Settings tab, and the change takes effect immediately
|
||||
3. Notifications are correctly rescheduled after device reboot (RECEIVE_BOOT_COMPLETED receiver active)
|
||||
4. On Android API 33+, the app requests POST_NOTIFICATIONS permission at the appropriate moment and degrades gracefully if denied
|
||||
**Plans**: 3 plans
|
||||
Plans:
|
||||
- [ ] 04-01-PLAN.md — Infrastructure: packages, Android config, NotificationService, NotificationSettingsNotifier, DAO queries, timezone init, tests
|
||||
- [ ] 04-02-PLAN.md — Settings UI: Benachrichtigungen section with toggle, time picker, permission flow, scheduling wiring, tests
|
||||
- [ ] 04-03-PLAN.md — Verification gate: dart analyze + full test suite + requirement confirmation
|
||||
|
||||
## Progress
|
||||
|
||||
**Execution Order:**
|
||||
Phases execute in numeric order: 1 -> 2 -> 3 -> 4
|
||||
|
||||
Note: Phase 4 depends on Phase 2 (needs scheduling data) but can be developed in parallel with Phase 3.
|
||||
|
||||
| Phase | Plans Complete | Status | Completed |
|
||||
|-------|----------------|--------|-----------|
|
||||
| 1. Foundation | 2/2 | Complete | 2026-03-15 |
|
||||
| 2. Rooms and Tasks | 5/5 | Complete | 2026-03-15 |
|
||||
| 3. Daily Plan and Cleanliness | 3/3 | Complete | 2026-03-16 |
|
||||
| 4. Notifications | 3/3 | Complete | 2026-03-16 |
|
||||
117
.planning/phases/02-rooms-and-tasks/2-CONTEXT.md
Normal file
117
.planning/phases/02-rooms-and-tasks/2-CONTEXT.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Phase 2: Rooms and Tasks - Context
|
||||
|
||||
**Gathered:** 2026-03-15
|
||||
**Status:** Ready for planning
|
||||
|
||||
<domain>
|
||||
## Phase Boundary
|
||||
|
||||
Users can create and manage rooms and tasks, mark tasks done, and trust the app to schedule the next occurrence automatically. Delivers: room CRUD with icons and reorder, task CRUD with frequency intervals and effort levels, task completion with auto-scheduling, bundled German-language task templates for 14 room types, overdue highlighting, and room cards with cleanliness indicators.
|
||||
|
||||
Requirements: ROOM-01, ROOM-02, ROOM-03, ROOM-04, ROOM-05, TASK-01, TASK-02, TASK-03, TASK-04, TASK-05, TASK-06, TASK-07, TASK-08, TMPL-01, TMPL-02
|
||||
|
||||
</domain>
|
||||
|
||||
<decisions>
|
||||
## Implementation Decisions
|
||||
|
||||
### Room cards & layout
|
||||
- **2-column grid** layout on the Rooms screen — compact cards, shows more rooms at once
|
||||
- Each card shows: **room icon, room name, count of due/overdue tasks, thin cleanliness progress bar**
|
||||
- No next-task preview or total task count on cards — keep them clean
|
||||
- **Cleanliness indicator**: thin horizontal progress bar at bottom of card, fill color shifts green→yellow→red based on ratio of on-time to overdue tasks
|
||||
- **Icon picker**: curated grid of ~20-30 hand-picked household Material Icons in a bottom sheet. No full icon search — focused and simple
|
||||
- Cards support drag-and-drop reorder (ROOM-04)
|
||||
- Delete room with confirmation dialog that warns about cascade deletion of all tasks (ROOM-03)
|
||||
|
||||
### Task completion & overdue
|
||||
- **Leading checkbox** on each task row to mark done — tap to toggle. No swipe gesture.
|
||||
- Tapping the task row (not the checkbox) opens task detail/edit
|
||||
- **Overdue visual**: due date text turns warm red/coral color. Rest of row stays normal — subtle but clear
|
||||
- **No undo** on completion — immediate and final. Records timestamp, auto-calculates next due date
|
||||
- **Task row info**: task name, relative due date (e.g. "Heute", "in 3 Tagen", "Überfällig"), and frequency label (e.g. "Wöchentlich", "Alle 3 Tage"). No effort indicator or description preview on list view
|
||||
- Tasks within a room sorted by due date (default sort order, TASK-06)
|
||||
|
||||
### Template selection flow
|
||||
- **Post-creation prompt**: user creates a room first (name + icon), then gets prompted "Aufgaben aus Vorlagen hinzufügen?" with template selection
|
||||
- **Room type is optional** — used only to determine which templates to suggest. Not stored as a permanent field. If no matching room type is detected, no template prompt appears
|
||||
- **All templates unchecked** by default — user explicitly checks what they want. No pre-selection
|
||||
- Users can create fully custom rooms (name + icon only) with no template prompt if no room type matches
|
||||
- Templates cover all 14 room types from TMPL-02: Küche, Badezimmer, Schlafzimmer, Wohnzimmer, Flur, Büro, Garage, Balkon, Waschküche, Keller, Kinderzimmer, Gästezimmer, Esszimmer, Garten/Außenbereich
|
||||
- Templates are bundled in the app as static data (German language)
|
||||
|
||||
### Scheduling & recurrence
|
||||
- **Two interval categories** with different behavior:
|
||||
- **Day-count intervals** (daily, every N days, weekly, biweekly): add N days from due date. Pure arithmetic, no clamping.
|
||||
- **Calendar-anchored intervals** (monthly, quarterly, every N months, yearly): anchor to original day-of-month. If the month is shorter, clamp to last day of month but remember the anchor (e.g. task set for the 31st: Jan 31 → Feb 28 → Mar 31)
|
||||
- **Next due calculated from original due date**, not completion date — keeps rhythm stable even when completed late
|
||||
- **Catch-up on very late completion**: if calculated next due is in the past, keep adding intervals until next due is today or in the future. No stacking of missed occurrences
|
||||
- **Custom intervals**: user picks a number + unit (Tage/Wochen/Monate). E.g. "Alle 10 Tage" or "Alle 3 Monate"
|
||||
- **Preset intervals** from TASK-04: daily, every 2 days, every 3 days, weekly, biweekly, monthly, every 2 months, quarterly, every 6 months, yearly, custom
|
||||
- All due dates stored as date-only (calendar day) — established in Phase 1 pre-decision
|
||||
|
||||
### Claude's Discretion
|
||||
- Room creation form layout (full screen vs bottom sheet vs dialog)
|
||||
- Task creation/edit form layout and field ordering
|
||||
- Exact Material Icons chosen for the curated icon picker set
|
||||
- Drag-and-drop reorder implementation approach (ReorderableListView vs custom)
|
||||
- Delete confirmation dialog design
|
||||
- Animation on task completion (checkbox fill, row transition)
|
||||
- Template data structure and storage format (Dart constants vs JSON asset)
|
||||
- Exact color values for overdue red/coral (within the sage & stone palette)
|
||||
- Empty state design for rooms with no tasks (following Phase 1 playful tone)
|
||||
|
||||
</decisions>
|
||||
|
||||
<specifics>
|
||||
## Specific Ideas
|
||||
|
||||
- Room type detection for templates should be lightweight — match room name against known types, don't force a classification step
|
||||
- The template prompt after room creation should feel like a helpful suggestion, not a required step — easy to dismiss
|
||||
- Overdue text color should be warm (coral/terracotta) not harsh alarm-red — fits the calm sage & stone palette
|
||||
- Relative due date labels in German: "Heute", "Morgen", "in X Tagen", "Überfällig seit X Tagen"
|
||||
- The cleanliness bar should be subtle — thin, at the bottom edge of the card, not a dominant visual element
|
||||
- Checkbox interaction should feel instant — no loading spinners, optimistic UI
|
||||
|
||||
</specifics>
|
||||
|
||||
<code_context>
|
||||
## Existing Code Insights
|
||||
|
||||
### Reusable Assets
|
||||
- `AppDatabase` (`lib/core/database/database.dart`): Drift database with schema v1, currently no tables — Phase 2 adds Room, Task, and TaskCompletion tables
|
||||
- `appDatabaseProvider` (`lib/core/providers/database_provider.dart`): Riverpod provider with `keepAlive: true` and `ref.onDispose(db.close)` — all DAOs will reference this
|
||||
- `ThemeNotifier` pattern (`lib/core/theme/theme_provider.dart`): AsyncNotifier with SharedPreferences persistence — template for room/task notifiers
|
||||
- `SettingsScreen` (`lib/features/settings/presentation/settings_screen.dart`): ConsumerWidget with `ref.watch` + `ref.read(...notifier)` pattern — template for reactive screens
|
||||
- `RoomsScreen` placeholder (`lib/features/rooms/presentation/rooms_screen.dart`): Ready to replace with actual room grid
|
||||
- `app_de.arb` (`lib/l10n/app_de.arb`): Localization file with 18 existing keys — Phase 2 adds room/task/frequency/effort strings
|
||||
|
||||
### Established Patterns
|
||||
- **Riverpod 3 code generation**: `@riverpod` annotation + `.g.dart` files via build_runner. Functional providers for reads, class-based AsyncNotifier for mutations
|
||||
- **Clean architecture**: `features/X/data/domain/presentation` layer structure. Presentation never imports directly from data layer
|
||||
- **GoRouter StatefulShellRoute**: `/rooms` branch exists, ready for nested routes (`/rooms/:roomId`, `/rooms/:roomId/tasks/new`)
|
||||
- **Material 3 theming**: `ColorScheme.fromSeed` with sage green seed (0xFF7A9A6D), warm stone surfaces. All color via `Theme.of(context).colorScheme`
|
||||
- **Localization**: ARB-based, German-only, strongly typed `AppLocalizations.of(context).keyName`
|
||||
- **Database testing**: `NativeDatabase.memory()` for in-memory tests, `setUp/tearDown` pattern
|
||||
- **Widget testing**: `ProviderScope` + `MaterialApp.router` with German locale
|
||||
|
||||
### Integration Points
|
||||
- Phase 2 replaces the `RoomsScreen` placeholder with the actual room grid
|
||||
- Room cards link to room detail screens via GoRouter nested routes under `/rooms`
|
||||
- Task completion data feeds Phase 3's daily plan view (overdue/today/upcoming grouping)
|
||||
- Cleanliness indicator logic established here is reused by Phase 3 room cards on the Home screen
|
||||
- Phase 4 notifications query task due dates established in this phase's schema
|
||||
|
||||
</code_context>
|
||||
|
||||
<deferred>
|
||||
## Deferred Ideas
|
||||
|
||||
None — discussion stayed within phase scope
|
||||
|
||||
</deferred>
|
||||
|
||||
---
|
||||
|
||||
*Phase: 02-rooms-and-tasks*
|
||||
*Context gathered: 2026-03-15*
|
||||
@@ -1,3 +1,6 @@
|
||||
import java.io.FileInputStream
|
||||
import java.util.Properties
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
@@ -6,8 +9,8 @@ plugins {
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.jlmak.household_keeper"
|
||||
compileSdk = 35
|
||||
namespace = "de.jeanlucmakiola.household_keeper"
|
||||
compileSdk = 36
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
@@ -22,7 +25,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId = "com.jlmak.household_keeper"
|
||||
applicationId = "de.jeanlucmakiola.household_keeper"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||
minSdk = flutter.minSdkVersion
|
||||
@@ -31,11 +34,25 @@ android {
|
||||
versionName = flutter.versionName
|
||||
}
|
||||
|
||||
val keystorePropertiesFile = rootProject.file("key.properties")
|
||||
val keystoreProperties = Properties()
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
keyAlias = keystoreProperties.getProperty("keyAlias")
|
||||
keyPassword = keystoreProperties.getProperty("keyPassword")
|
||||
storeFile = keystoreProperties.getProperty("storeFile")?.let { file(it) }
|
||||
storePassword = keystoreProperties.getProperty("storePassword")
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
18
household_keeper.iml
Normal file
18
household_keeper.iml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.idea" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||
</content>
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Flutter Plugins" level="project" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -10,8 +10,8 @@ import 'package:household_keeper/core/notifications/notification_service.dart';
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
tz.initializeTimeZones();
|
||||
final timeZoneName = await FlutterTimezone.getLocalTimezone();
|
||||
tz.setLocalLocation(tz.getLocation(timeZoneName));
|
||||
final timeZone = await FlutterTimezone.getLocalTimezone();
|
||||
tz.setLocalLocation(tz.getLocation(timeZone.identifier));
|
||||
await NotificationService().initialize();
|
||||
runApp(const ProviderScope(child: App()));
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ dependencies:
|
||||
flutter_reorderable_grid_view: ^5.6.0
|
||||
flutter_local_notifications: ^21.0.0
|
||||
timezone: ^0.11.0
|
||||
flutter_timezone: ^1.0.8
|
||||
flutter_timezone: ^5.0.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
24
test/drift/household_keeper/generated/schema.dart
Normal file
24
test/drift/household_keeper/generated/schema.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
// dart format width=80
|
||||
// GENERATED BY drift_dev, DO NOT MODIFY.
|
||||
// ignore_for_file: type=lint,unused_import
|
||||
//
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift/internal/migrations.dart';
|
||||
import 'schema_v1.dart' as v1;
|
||||
import 'schema_v2.dart' as v2;
|
||||
|
||||
class GeneratedHelper implements SchemaInstantiationHelper {
|
||||
@override
|
||||
GeneratedDatabase databaseForVersion(QueryExecutor db, int version) {
|
||||
switch (version) {
|
||||
case 1:
|
||||
return v1.DatabaseAtV1(db);
|
||||
case 2:
|
||||
return v2.DatabaseAtV2(db);
|
||||
default:
|
||||
throw MissingSchemaException(version, versions);
|
||||
}
|
||||
}
|
||||
|
||||
static const versions = const [1, 2];
|
||||
}
|
||||
16
test/drift/household_keeper/generated/schema_v1.dart
Normal file
16
test/drift/household_keeper/generated/schema_v1.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
// dart format width=80
|
||||
// GENERATED BY drift_dev, DO NOT MODIFY.
|
||||
// ignore_for_file: type=lint,unused_import
|
||||
//
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
class DatabaseAtV1 extends GeneratedDatabase {
|
||||
DatabaseAtV1(QueryExecutor e) : super(e);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities => [];
|
||||
@override
|
||||
int get schemaVersion => 1;
|
||||
}
|
||||
1034
test/drift/household_keeper/generated/schema_v2.dart
Normal file
1034
test/drift/household_keeper/generated/schema_v2.dart
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user