Plan
SmartCrew Mobile - Plan
Technical Specification: Automated Advanced Exception Handling System
Project Context
Application: SmartCrew Mobile (Flutter)
Architecture: Provider + Firebase + Hive.
Goal: Implement a unified, automated exception handling system that eliminates manual try-catch blocks in business logic, ensures UI feedback (Toasts) without BuildContext context crashes, and separates User Errors from System Crashes.
General Directives for AI Implementation
- Clean Code: Follow SOLID principles, specifically Open/Closed for exceptions and Single Responsibility for the executor/mapper.
- Safety: Ensure
scaffoldMessengerKeychecks for null before execution to prevent null pointer exceptions. - No Context: Logic layers must not import
package:flutter/material.dartjust to getBuildContext. They should use the mixin and services defined below. - Logging: Ensure only critical system errors go to the Crashlytics placeholder; validation errors remain in the console.
Phase 1: Core Infrastructure (Models & Entry Point)
Objective: Define the polymorphic exception model and setup the global UI key.
Task 1.1: Exception Hierarchy
Path: lib/core/error/
File: base_exception.dart
Requirement: Create an abstract AppException.
- Fields:
message,title,originalError(dynamic),stackTrace. - Getters:
bool logToCrashlytics,UiStyle uiStyle(enum: dialog, toast, silent).
File: ui_style.dart
- Enum
UiStyle { dialog, toast, silent }
File: exceptions/user_exceptions.dart
- Extend
AppException.logToCrashlyticsalways returnsfalse. - Classes:
ValidationException(Style: Dialog/Toast, default title: "Action Required")NetworkException(Style: Toast, message: "No Internet Connection")DataMissingException(Style: Dialog, acceptsmissingItemandfixRoute)
File: exceptions/system_exceptions.dart
- Extend
AppException.logToCrashlyticsalways returnstrue. - Classes:
FatalErrorException(Style: Dialog, generic friendly message, logs original error).SilentSyncException(Style: Silent, logs original error).
Task 1.2: Global Navigation Key
Path: lib/smart_crew_app.dart or lib/main.dart
Requirement:
- Define a top-level global key:
final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>(); - Assign this key to the
scaffoldMessengerKeyproperty of yourMaterialApp.
Phase 2: Translation & UI Service
Objective: Bridge the gap between raw Dart/Firebase errors and the user UI without context passing.
Task 2.1: Central Error Mapper
Path: lib/core/error/error_mapper.dart
Requirement:
- Create class
ErrorMapper. - Method:
static AppException map(dynamic error, [StackTrace? stack]). - Logic:
- If
errorisAppException, return it. - If
errorisSocketException-> returnNetworkException. - If
errorisFirebaseException:- code
permission-denied-> returnValidationException("Access Denied"). - code
unavailable-> returnNetworkException.
- code
- Else -> return
FatalErrorException(wrap original error).
- If
Task 2.2: Context-Less Toast Service
Path: lib/core/services/toast_service.dart
Requirement:
- Import the
rootScaffoldMessengerKeyfrom Phase 1. - Method:
static void show(String message, {ToastType type}). - Types:
success(Green),warning(Orange),error(Red). - Implementation: Use
rootScaffoldMessengerKey.currentState?.showSnackBar(...). - Style: SnackBar behavior must be
floating.
Phase 3: The Automation Engine (Mixin)
Objective: The component that Providers will consume to get "free" error handling.
Task 3.1: Safe Execution Mixin
Path: lib/core/mixins/safe_execution_mixin.dart
Requirement:
- Define
mixin SafeExecutionMixin. - Property:
final ValueNotifier<bool> isBusyNotifier = ValueNotifier(false); - Method:
Future<void> execute( Future<void> Function() action, { String? successMessage, // optional: custom onError callback for special cases }) async - Logic Flow:
- Set
isBusyNotifier.value = true. try->await action().- If
successMessage!= null ->ToastService.show(success, type: success). catch(e, stack):final exception = ErrorMapper.map(e, stack);- If
exception.logToCrashlytics-> Print/Log to Crashlytics. - If
exception.uiStyle!= Silent:- Determine Toast Type (Warning for UserException, Error for SystemException).
ToastService.show(exception.message, type: ...)
finally-> SetisBusyNotifier.value = false.
- Set
Phase 4: Integration Example
Objective: Demonstrate how to apply this to an existing provider (refactor).
Task 4.1: Refactor ManualLogsProvider
Path: lib/providers/manual_logs_provider.dart
Action:
- Add
with SafeExecutionMixinto the class definition. - Locate
submitLog(or similar method). - Remove all existing
try-catch,isLoading = true/false, and context-dependent Dialog calls. - Wrap logic in
await execute(() async { ... }). - Add validation:
if (project == null) throw const ValidationException('Select a project');
Success Criteria for Verification
Before accepting the code, verify the following:
- The Context Test: Can
ToastService.show()be called from inside a Provider method without passingcontextarguments? (Yes/No). - The Network Test: Turn off internet simulator. Call a provider function. Does a "Network Exception" toast appear automatically? (Yes/No).
- The User Validation: Submit a form with missing data (throwing
ValidationException). Does the toast appear as Orange (Warning) and NOT Red (System Error)? (Yes/No). - The Crash Log: Does throwing
Exception("Random error")result in aFatalErrorExceptionbeing mapped and logged to console/Crashlytics wrapper? (Yes/No). - Clean Logic: Does
ManualLogsProvidercontain ZEROtry-catchblocks inside the refactored method? (Yes/No).