--- phase: 02-household-creation plan: 03 type: execute wave: 2 depends_on: [02-01] files_modified: - lib/features/household/providers/household_provider.dart - lib/features/household/domain/usecases/create_household_usecase.dart - lib/features/household/domain/usecases/generate_invite_code_usecase.dart - lib/features/household/domain/usecases/join_household_usecase.dart - lib/features/household/domain/usecases/get_user_households_usecase.dart autonomous: true must_haves: truths: - "Household state management provides reactive updates across the app" - "Use cases encapsulate business logic for household operations" - "Provider integrates with existing authentication state" - "Household operations handle loading states and errors properly" artifacts: - path: "lib/features/household/providers/household_provider.dart" provides: "Global household state management" contains: "class HouseholdProvider", "Riverpod", "AsyncValue" - path: "lib/features/household/domain/usecases/create_household_usecase.dart" provides: "Household creation business logic" contains: "class CreateHouseholdUseCase", "Future" - path: "lib/features/household/domain/usecases/join_household_usecase.dart" provides: "Household joining logic with validation" contains: "class JoinHouseholdUseCase", "invite code validation" - path: "lib/features/household/domain/usecases/get_user_households_usecase.dart" provides: "User household retrieval logic" contains: "class GetUserHouseholdsUseCase", "List" key_links: - from: "lib/features/household/providers/household_provider.dart" to: "lib/features/household/domain/usecases/create_household_usecase.dart" via: "dependency injection" pattern: "CreateHouseholdUseCase.*createHouseholdUseCase" - from: "lib/features/household/providers/household_provider.dart" to: "lib/providers/auth_provider.dart" via: "authentication state" pattern: "ref.watch.*authProvider" --- Implement household state management and business logic use cases following clean architecture patterns. Purpose: Provide reactive household state that integrates with authentication and handles all household operations with proper error handling. Output: Complete state management layer with use cases and Riverpod provider ready for UI integration. @~/.opencode/get-shit-done/workflows/execute-plan.md @~/.opencode/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md # State Management References @lib/providers/auth_provider.dart @lib/features/authentication/data/repositories/auth_repository_impl.dart Create Household Use Cases lib/features/household/domain/usecases/create_household_usecase.dart lib/features/household/domain/usecases/generate_invite_code_usecase.dart lib/features/household/domain/usecases/join_household_usecase.dart lib/features/household/domain/usecases/get_user_households_usecase.dart Create use cases for household operations following clean architecture: 1. CreateHouseholdUseCase (create_household_usecase.dart): ```dart class CreateHouseholdUseCase { final HouseholdRepository repository; CreateHouseholdUseCase(this.repository); Future call(String name, String userId) async { if (name.trim().isEmpty) { throw HouseholdValidationException('Household name cannot be empty'); } if (name.length > 100) { throw HouseholdValidationException('Household name too long (max 100 characters)'); } return await repository.createHousehold(name.trim(), userId); } } ``` 2. GenerateInviteCodeUseCase (generate_invite_code_usecase.dart): ```dart class GenerateInviteCodeUseCase { final HouseholdRepository repository; GenerateInviteCodeUseCase(this.repository); Future call(String householdId, String userId) async { // Check if user is owner (will be validated in repository) return await repository.generateInviteCode(householdId, userId); } } ``` 3. JoinHouseholdUseCase (join_household_usecase.dart): ```dart class JoinHouseholdUseCase { final HouseholdRepository repository; JoinHouseholdUseCase(this.repository); Future call(String inviteCode, String userId) async { if (inviteCode.trim().isEmpty) { throw HouseholdValidationException('Invite code cannot be empty'); } if (inviteCode.length != 8) { throw HouseholdValidationException('Invite code must be 8 characters'); } return await repository.joinHousehold(inviteCode.trim().toUpperCase(), userId); } } ``` 4. GetUserHouseholdsUseCase (get_user_households_usecase.dart): ```dart class GetUserHouseholdsUseCase { final HouseholdRepository repository; GetUserHouseholdsUseCase(this.repository); Future> call(String userId) async { return await repository.getUserHouseholds(userId); } } ``` Include proper validation and business logic in each use case. Create custom exception classes for household operations. flutter analyze lib/features/household/domain/usecases/*.dart passes Household use cases encapsulate business logic with proper validation Create Household Provider lib/features/household/providers/household_provider.dart Create Riverpod provider for household state management: ```dart import 'package:flutter_riverpod/flutter_riverpod.dart'; // Use case providers final createHouseholdUseCaseProvider = Provider((ref) { final repository = ref.watch(householdRepositoryProvider); return CreateHouseholdUseCase(repository); }); final generateInviteCodeUseCaseProvider = Provider((ref) { final repository = ref.watch(householdRepositoryProvider); return GenerateInviteCodeUseCase(repository); }); final joinHouseholdUseCaseProvider = Provider((ref) { final repository = ref.watch(householdRepositoryProvider); return JoinHouseholdUseCase(repository); }); final getUserHouseholdsUseCaseProvider = Provider((ref) { final repository = ref.watch(householdRepositoryProvider); return GetUserHouseholdsUseCase(repository); }); // Main household provider class HouseholdProvider extends StateNotifier>> { final GetUserHouseholdsUseCase _getUserHouseholdsUseCase; final CreateHouseholdUseCase _createHouseholdUseCase; final JoinHouseholdUseCase _joinHouseholdUseCase; final GenerateInviteCodeUseCase _generateInviteCodeUseCase; HouseholdProvider( this._getUserHouseholdsUseCase, this._createHouseholdUseCase, this._joinHouseholdUseCase, this._generateInviteCodeUseCase, ) : super(const AsyncValue.loading()) { _initialize(); } Future _initialize() async { state = const AsyncValue.loading(); try { // Will be called when auth state is available } catch (e, stack) { state = AsyncValue.error(e, stack); } } Future loadUserHouseholds(String userId) async { state = const AsyncValue.loading(); try { final households = await _getUserHouseholdsUseCase(userId); state = AsyncValue.data(households); } catch (e, stack) { state = AsyncValue.error(e, stack); } } Future createHousehold(String name, String userId) async { try { final household = await _createHouseholdUseCase(name, userId); // Refresh the list await loadUserHouseholds(userId); return household; } catch (e) { throw HouseholdOperationException('Failed to create household: $e'); } } Future joinHousehold(String inviteCode, String userId) async { try { final household = await _joinHouseholdUseCase(inviteCode, userId); // Refresh the list await loadUserHouseholds(userId); return household; } catch (e) { throw HouseholdOperationException('Failed to join household: $e'); } } Future generateInviteCode(String householdId, String userId) async { try { return await _generateInviteCodeUseCase(householdId, userId); } catch (e) { throw HouseholdOperationException('Failed to generate invite code: $e'); } } void clearHouseholds() { state = const AsyncValue.data([]); } } // Provider instance final householdProvider = StateNotifierProvider>>((ref) { return HouseholdProvider( ref.read(getUserHouseholdsUseCaseProvider), ref.read(createHouseholdUseCaseProvider), ref.read(joinHouseholdUseCaseProvider), ref.read(generateInviteCodeUseCaseProvider), ); }); // Current selected household provider final currentHouseholdProvider = StateProvider((ref) => null); // Repository provider (to be added to main providers file) final householdRepositoryProvider = Provider((ref) { final datasource = ref.read(householdRemoteDatasourceProvider); return HouseholdRepositoryImpl(datasource); }); final householdRemoteDatasourceProvider = Provider((ref) { final client = ref.read(supabaseClientProvider); return HouseholdRemoteDatasource(client); }); ``` Follow auth provider patterns for consistency. Include proper error handling and state transitions. flutter analyze lib/features/household/providers/household_provider.dart passes Household provider provides reactive state management with proper integration Create Household Exception Classes lib/features/household/domain/exceptions/household_exceptions.dart Create custom exception classes for household operations: ```dart // Base household exception abstract class HouseholdException implements Exception { final String message; const HouseholdException(this.message); @override String toString() => 'HouseholdException: $message'; } // Validation exceptions class HouseholdValidationException extends HouseholdException { const HouseholdValidationException(String message) : super(message); @override String toString() => 'HouseholdValidationException: $message'; } // Operation exceptions class HouseholdOperationException extends HouseholdException { const HouseholdOperationException(String message) : super(message); @override String toString() => 'HouseholdOperationException: $message'; } // Specific household exceptions class HouseholdNotFoundException extends HouseholdException { const HouseholdNotFoundException(String message) : super(message); @override String toString() => 'HouseholdNotFoundException: $message'; } class InviteCodeException extends HouseholdException { const InviteCodeException(String message) : super(message); @override String toString() => 'InviteCodeException: $message'; } class HouseholdMembershipException extends HouseholdException { const HouseholdMembershipException(String message) : super(message); @override String toString() => 'HouseholdMembershipException: $message'; } ``` Follow authentication exception patterns for consistency. flutter analyze lib/features/household/domain/exceptions/household_exceptions.dart passes Household exception classes provide clear error categorization 1. Use cases encapsulate business logic with proper validation 2. Household provider provides reactive state management following Riverpod patterns 3. Exception classes provide clear error categorization 4. Integration with authentication state is properly structured 5. All household operations handle loading states and errors appropriately Household state management is complete with use cases, provider, and exception handling ready for UI integration. After completion, create `.planning/phases/02-household-creation/02-03-SUMMARY.md` with state management implementation summary