Building a TODO app using Flutter with PFA (Practical Flutter Architecture), featuring:
- State management:
watch_it+command_it - Dependency injection:
get_it - Local storage:
hive(Phase 1) - Cloud storage:
firebase(Phase 2)
Goal: Initialize Flutter project with required dependencies
Tasks:
- Create new Flutter project:
flutter create todoit - Update
pubspec.yamlwith dependencies:dependencies: flutter: sdk: flutter # State Management & DI watch_it: ^1.7.0 command_it: ^8.0.0 get_it: ^8.0.0 # Local Storage hive: ^2.2.3 hive_flutter: ^1.1.0 # Utilities uuid: ^4.0.0 intl: ^0.19.0 dev_dependencies: flutter_test: sdk: flutter hive_generator: ^2.0.1 build_runner: ^2.4.0 flutter_lints: ^4.0.0 mockito: ^5.4.0
- Run:
flutter pub get - Create project structure (folders)
Deliverables:
- Configured Flutter project
- All dependencies installed
- Folder structure created
Goal: Set up feature-based folder organization
Tasks:
- Create folder structure:
lib/ ├── main.dart ├── locator.dart ├── features/ │ ├── todos/ │ │ ├── views/ │ │ ├── managers/ │ │ └── models/ │ └── settings/ │ ├── views/ │ └── managers/ ├── services/ │ └── storage/ └── shared/ ├── widgets/ └── utils/
Deliverables:
- Clean folder structure following PFA principles
Goal: Create domain objects and DTOs for todos
Files to create:
lib/features/todos/models/todo.dart- Domain modellib/features/todos/models/todo_dto.dart- Hive DTO with annotations
Todo Model Properties:
id: String (UUID)title: Stringdescription: StringisCompleted: boolcreatedAt: DateTimeupdatedAt: DateTime?
Tasks:
- Create
Tododomain class with:- Immutable properties
copyWith()methodtoDTO()conversion
- Create
TodoDTOHive class with:@HiveTypeannotation@HiveFieldannotationstoDomain()conversion
- Run code generation:
flutter pub run build_runner build --delete-conflicting-outputs
Deliverables:
todo.dartwith domain modeltodo_dto.g.dartgeneratedtodo_dto.dartwith Hive annotations
Goal: Create Hive service for local storage
Files to create:
lib/services/storage/hive_storage_service.dart
Methods to implement:
Future<void> init()- Initialize Hive boxFuture<List<TodoDTO>> getAllTodos()Future<TodoDTO?> getTodoById(String id)Future<void> saveTodo(TodoDTO todo)Future<void> updateTodo(TodoDTO todo)Future<void> deleteTodo(String id)Stream<List<TodoDTO>> watchTodos()- For real-time updates
Tasks:
- Implement
HiveStorageServiceclass - Handle box opening/closing
- Implement CRUD operations
- Add error handling
- Test service independently
Deliverables:
- Fully functional
HiveStorageService - Error handling for storage operations
Goal: Implement business logic layer with Commands
Files to create:
lib/features/todos/managers/todo_manager.dart
Properties:
ValueNotifier<List<Todo>> todosValueNotifier<Todo?> selectedTodo
Commands:
Command<void, List<Todo>> loadTodosCommand- Load all todosCommand<Todo, void> addTodoCommand- Add new todoCommand<Todo, void> updateTodoCommand- Update existingCommand<String, void> deleteTodoCommand- Delete by IDCommand<String, void> toggleTodoCommand- Toggle completion
Tasks:
- Create
TodoManagerclass - Inject
HiveStorageServicedependency - Implement all commands with async operations
- Update
todosValueNotifier after operations - Add error handling for each command
- Implement filtering logic (all/active/completed)
Deliverables:
TodoManagerwith full CRUD operations- Commands for all todo operations
- Reactive state with ValueNotifiers
Goal: Configure get_it service locator
Files to create:
lib/locator.dart
Tasks:
- Create
setupLocator()function - Register
HiveStorageServiceas lazy singleton - Register
TodoManageras lazy singleton - Ensure proper dependency order
- Add initialization in
main.dart
Code structure:
void setupLocator() {
// Services
di.registerLazySingleton<HiveStorageService>(
() => HiveStorageService(),
);
// Managers
di.registerLazySingleton<TodoManager>(
() => TodoManager(di<HiveStorageService>()),
);
}Deliverables:
- Configured dependency injection
- All services and managers registered
Goal: Setup Hive and dependencies in main.dart
Files to modify:
lib/main.dart
Tasks:
- Initialize Flutter bindings
- Initialize Hive with
Hive.initFlutter() - Register Hive adapters
- Open Hive boxes
- Call
setupLocator() - Wait for async dependencies:
await di.allReady() - Run app
Code structure:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize Hive
await Hive.initFlutter();
Hive.registerAdapter(TodoDTOAdapter());
await Hive.openBox<TodoDTO>('todos');
// Setup DI
setupLocator();
// Wait for all async deps
await di.allReady();
runApp(const MyApp());
}Deliverables:
- Properly initialized app
- Hive ready for use
- All dependencies available
Goal: Build main screen showing all todos
Files to create:
lib/features/todos/views/todo_list_view.dartlib/features/todos/views/widgets/todo_item.dart
Features:
- Display todos in ListView
- Filter tabs: All / Active / Completed
- Loading indicator while fetching
- Empty state message
- FAB to add new todo
- Swipe to delete
- Tap to toggle completion
- Long press for edit
Watch expressions:
final todos = watchPropertyValue((TodoManager m) => m.todos.value);
final isLoading = watchValue((TodoManager m) => m.loadTodosCommand.isExecuting);Tasks:
- Create
TodoListViewextendingWatchingWidget - Watch todos and loading state
- Implement filter tabs (BottomNavigationBar or TabBar)
- Create
TodoItemwidget for list items - Implement swipe-to-delete with Dismissible
- Add FAB for creating todos
- Handle empty states
- Add error handler for delete/update commands
Deliverables:
- Functional todo list with reactive updates
- Filter functionality
- Interactive todo items
Goal: Build form for creating and editing todos
Files to create:
lib/features/todos/views/todo_form_view.dart
Form fields:
- Title (required, TextFormField)
- Description (optional, TextFormField with multiple lines)
- Save/Cancel buttons
Features:
- Validate title is not empty
- Handle both add and edit modes
- Show loading indicator during save
- Navigate back on success
- Show error on failure
Tasks:
- Create
TodoFormViewextendingWatchingWidget - Create Form with GlobalKey
- Implement TextFormFields with validation
- Detect add vs edit mode (constructor parameter)
- Watch command execution state
- Call appropriate command (add or update)
- Register error handler to show SnackBar
- Navigate back on success
Deliverables:
- Working form for add/edit
- Validation
- Error handling
Goal: Setup navigation between screens
Files to modify:
lib/main.dart
Routes:
/- TodoListView/add- TodoFormView (add mode)/edit/:id- TodoFormView (edit mode)
Tasks:
- Define MaterialApp routes or use named routes
- Implement navigation from FAB to add screen
- Implement navigation from todo item to edit screen
- Handle back navigation after save
Deliverables:
- Working navigation flow
- Proper data passing between screens
Goal: Create reusable UI components
Files to create:
lib/shared/widgets/loading_indicator.dartlib/shared/widgets/empty_state.dartlib/shared/widgets/error_dialog.dart
Tasks:
- Create
LoadingIndicatorwidget - Create
EmptyStatewidget with icon and message - Create
ErrorDialogutility function - Use throughout the app
Deliverables:
- Reusable widget library
- Consistent UI/UX
Goal: Add settings screen with theme toggle
Files to create:
lib/features/settings/managers/settings_manager.dartlib/features/settings/views/settings_view.dart
Features:
- Dark mode toggle
- Clear all todos option
- About section
- Store settings in Hive
Tasks:
- Create
SettingsManagerwith:ValueNotifier<bool> isDarkModeCommand<bool, void> toggleThemeCommandCommand<void, void> clearAllTodosCommand
- Register in locator
- Create
SettingsViewwith switches - Update MaterialApp theme based on
isDarkMode - Watch theme in main.dart
Deliverables:
- Working settings screen
- Theme persistence
- Clear all functionality
Goal: Write unit tests for business logic
Files to create:
test/managers/todo_manager_test.darttest/services/hive_storage_service_test.dart
Test cases:
- TodoManager:
- Adding todo updates list
- Deleting todo removes from list
- Toggling completion changes state
- Commands handle errors properly
- HiveStorageService:
- CRUD operations work correctly
- Error handling
Tasks:
- Setup test dependencies (mockito)
- Create mock services
- Write unit tests for TodoManager
- Write tests for storage service
- Achieve >80% coverage for business logic
Deliverables:
- Comprehensive unit test suite
- Verified business logic
Goal: Write widget tests for UI
Files to create:
test/views/todo_list_view_test.darttest/views/todo_form_view_test.dart
Test cases:
- TodoListView:
- Displays todos correctly
- Shows loading indicator
- Shows empty state
- Filters work correctly
- TodoFormView:
- Validates required fields
- Saves correctly
- Shows errors
Tasks:
- Setup widget test harness
- Mock TodoManager
- Write widget tests
- Test user interactions
Deliverables:
- Widget test coverage
- UI behavior verification
Goal: Handle edge cases and improve UX
Tasks:
- Add confirmation dialog for delete
- Add confirmation for clear all
- Implement undo after delete (SnackBar action)
- Add pull-to-refresh
- Improve loading states
- Add animations (hero animation, list animations)
- Handle keyboard properly in forms
- Add focus management
- Accessibility: Semantics labels
- Test on different screen sizes
Deliverables:
- Polished user experience
- Edge cases handled
- Smooth animations
Goal: Configure Firebase for the app
Tasks:
- Create Firebase project at console.firebase.google.com
- Add Android app (download google-services.json)
- Add iOS app (download GoogleService-Info.plist)
- Update pubspec.yaml with Firebase packages:
firebase_core: ^3.0.0 cloud_firestore: ^5.0.0 firebase_auth: ^5.0.0
- Initialize Firebase in main.dart
- Configure FlutterFire CLI
Deliverables:
- Firebase project configured
- Firebase SDK integrated
Goal: Implement cloud storage layer
Files to create:
lib/services/storage/firebase_storage_service.dartlib/services/storage/storage_service.dart(abstract interface)
Tasks:
- Create
StorageServiceinterface - Refactor
HiveStorageServiceto implement interface - Create
FirebaseStorageServiceimplementing same interface:- Use Firestore collections
- Implement same methods as Hive service
- Add user-specific data (use Firebase Auth UID)
- Real-time listeners with
snapshots()
- Update locator to support switching
Deliverables:
- Abstract storage interface
- Firebase storage implementation
- Both implementations compatible
Goal: Add user authentication
Files to create:
lib/features/auth/managers/auth_manager.dartlib/features/auth/views/login_view.dart
Features:
- Email/password authentication
- Google Sign-In (optional)
- Anonymous authentication option
- Logout
Commands:
Command<LoginCredentials, User> loginCommandCommand<void, User> loginAnonymouslyCommandCommand<void, void> logoutCommand
Tasks:
- Create
AuthManagerwith Firebase Auth - Register in locator
- Create login screen
- Add auth state listener
- Protect todo routes (require authentication)
- Update Firebase rules for user-specific data
Deliverables:
- Working authentication
- Protected data per user
- Login/logout flow
Goal: Sync between local (Hive) and cloud (Firebase)
Files to create:
lib/services/sync/sync_service.dartlib/features/todos/managers/sync_manager.dart
Sync strategies:
- Online-first: Always use Firebase when online
- Offline-first: Use Hive, sync to Firebase when online
- Hybrid: Hive for reads, Firebase for writes with background sync
Tasks:
- Choose sync strategy (recommend offline-first)
- Implement
SyncService:- Listen to network connectivity
- Detect conflicts (last-write-wins or manual)
- Queue operations when offline
- Sync on reconnect
- Update
TodoManagerto use sync service - Handle sync errors
- Show sync status in UI
Deliverables:
- Offline capability
- Automatic sync
- Conflict resolution
Goal: Secure cloud data
Tasks:
- Write Firestore security rules:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId}/todos/{todoId} { allow read, write: if request.auth != null && request.auth.uid == userId; } } }
- Test rules with Firebase emulator
- Deploy rules to production
Deliverables:
- Secure Firestore rules
- User data isolation
Goal: Help users migrate from Hive to Firebase
Files to create:
lib/services/migration/migration_service.dart
Tasks:
- Create one-time migration function
- Copy all Hive data to Firebase
- Mark migration complete in shared preferences
- Run on first launch after Firebase update
Deliverables:
- Smooth migration experience
- No data loss
Goal: Ensure production readiness
Tasks:
- Test offline mode extensively
- Test sync conflicts
- Test authentication flows
- Performance testing (large datasets)
- Memory profiling
- Network usage optimization
- Add analytics (Firebase Analytics)
- Add crash reporting (Firebase Crashlytics)
- Update tests for Firebase functionality
Deliverables:
- Production-ready app
- Performance optimized
- Monitoring in place
- ✅ Working todo app with Hive
- ✅ Full CRUD operations
- ✅ PFA architecture implemented
- ✅ No cloud dependency
Timeline: 2-3 days
- ✅ Settings and theme
- ✅ Tests written
- ✅ Polished UX
- ✅ Ready for users
Timeline: 1-2 days
- ✅ Firebase integrated
- ✅ Authentication working
- ✅ Data syncing
- ✅ Production ready
Timeline: 3-5 days
- ✅ Basic CRUD operations
- ✅ Local storage (Hive)
- ✅ Todo list display
- ✅ Add/edit form
- ✅ Filters (all/active/completed)
- ✅ Dark mode
- ✅ Settings screen
- ✅ Error handling
- Pull-to-refresh
- Undo delete
- Animations
- Search functionality
- Sharing todos
- Categories/tags
- Due dates & reminders
- Attachments
- Collaboration
- Option A: Build complete local app first, then add Firebase (recommended)
- Pros: Faster MVP, testable without network
- Cons: Migration work later
- Option B: Build with Firebase from start
- Pros: No migration
- Cons: Slower development, network dependency
Recommendation: Follow Phase 1 completely, then Phase 2
- Current Plan: Hive first, Firebase later
- Alternative: SQLite → Firebase
- Alternative: Firebase only with offline persistence
Recommendation: Stick with Hive for Phase 1 (simpler, less setup)
- All managers (100% coverage goal)
- All services
- All commands
- Domain models
- All views
- Key user flows
- Error states
- End-to-end flows
- Auth flow (Phase 2)
- Sync scenarios (Phase 2)
- App launch: < 2 seconds
- Todo list rendering: < 100ms for 1000 items
- CRUD operations: < 500ms
- Firebase sync: < 3 seconds
- Memory usage: < 100MB
To begin development:
- Run:
flutter create todoit - Follow Step 1 (Project Setup)
- Work through steps sequentially
- Commit after each major step
- Test frequently
First commit checklist:
- Project created
- Dependencies added
- Folder structure created
- README updated
- rules.md in project root
- plan.md in project root