Skip to content

Improve initialization and environment variable handling#182

Open
shhreya13 wants to merge 1 commit intoAOSSIE-Org:mainfrom
shhreya13:improve-main-init-env-handling
Open

Improve initialization and environment variable handling#182
shhreya13 wants to merge 1 commit intoAOSSIE-Org:mainfrom
shhreya13:improve-main-init-env-handling

Conversation

@shhreya13
Copy link
Copy Markdown

@shhreya13 shhreya13 commented Mar 7, 2026

Closes #181

This PR improves the initialization process in main.dart by:

  • Validating environment variables
  • Improving error handling
  • Reusing repository instances
  • Adding route-based navigation

This prevents crashes caused by missing .env variables and improves developer experience for contributors.

Summary by CodeRabbit

Release Notes

  • Updates

    • Changed app title to "NeuroTrack Patient"
  • Improvements

    • Enhanced app initialization process with improved error handling and reliability
    • Optimized dependency management for better system stability

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 7, 2026

📝 Walkthrough

Walkthrough

The pull request enhances main.dart initialization by adding environment variable validation, establishing repositories before app startup, reorganizing dependency injection to wire repositories into providers, implementing error handling with try/catch, and updating routing to use named routes with an initialRoute configuration.

Changes

Cohort / File(s) Summary
Initialization & Robustness
patient/lib/main.dart
Added environment variable loading and validation; wrapped entire initialization sequence in try/catch block with debug logging; removed eager inline provider instantiation tied to global Supabase client.
Repository & Dependency Setup
patient/lib/main.dart
Created supabaseClient, patientRepository, and authRepository instances before app launch; wired repository-backed providers (ReportsProvider, TaskProvider, TherapyGoalsProvider, AppointmentsProvider) with explicitly passed repositories.
App Configuration & Routing
patient/lib/main.dart
Migrated from implicit to explicit routing using initialRoute ('/' mapped to SplashScreen) and routes map; updated app title from "Patient App" to "NeuroTrack Patient".

Sequence Diagram

sequenceDiagram
    participant Main as main()
    participant EnvLoader as Environment<br/>Loader
    participant Services as Supabase &<br/>Gemini
    participant Repos as Repository<br/>Factory
    participant Providers as Provider<br/>Setup
    participant App as MaterialApp
    
    Main->>EnvLoader: Load & validate .env
    alt Validation Success
        EnvLoader-->>Main: Variables loaded
        Main->>Services: Initialize Supabase<br/>& Gemini
        Services-->>Main: Services ready
        Main->>Repos: Create repositories
        Repos-->>Main: supabaseClient,<br/>patientRepository,<br/>authRepository
        Main->>Providers: Setup providers with<br/>repository instances
        Providers-->>Main: Providers configured
        Main->>App: Run app with<br/>initialRoute & routes
        App-->>Main: App launched
    else Validation Fails
        EnvLoader-->>Main: Missing variables
        Main->>Main: Log debug message
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hop hop, the init now springs with care!
Environment checked, no crashes in the air,
Repositories crafted before the app takes flight,
NeuroTrack Patient shines with sturdy might!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: improving initialization flow and adding environment variable validation and handling in main.dart.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #181: validates environment variables, improves initialization error handling with try/catch, reuses repository instances, and adds route-based navigation.
Out of Scope Changes check ✅ Passed All changes are directly related to the stated objectives: environment variable validation, initialization flow improvement, repository reuse, and navigation setup. No unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
patient/lib/main.dart (1)

27-34: Improve validation to identify which variable is missing and catch empty strings.

The current error message doesn't specify which environment variable is missing, making debugging harder. Additionally, empty strings would pass validation but fail at runtime.

♻️ Proposed improvement for more specific validation
     final supabaseUrl = dotenv.env['SUPABASE_URL'];
     final supabaseKey = dotenv.env['SUPABASE_ANON_KEY'];
     final geminiKey = dotenv.env['GEMINI_API_KEY'];

     // Validate env variables
-    if (supabaseUrl == null || supabaseKey == null || geminiKey == null) {
-      throw Exception("Missing environment variables in .env file");
-    }
+    final missingVars = <String>[];
+    if (supabaseUrl == null || supabaseUrl.isEmpty) {
+      missingVars.add('SUPABASE_URL');
+    }
+    if (supabaseKey == null || supabaseKey.isEmpty) {
+      missingVars.add('SUPABASE_ANON_KEY');
+    }
+    if (geminiKey == null || geminiKey.isEmpty) {
+      missingVars.add('GEMINI_API_KEY');
+    }
+    if (missingVars.isNotEmpty) {
+      throw Exception("Missing or empty environment variables in .env file: ${missingVars.join(', ')}");
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patient/lib/main.dart` around lines 27 - 34, The environment validation
currently checks only for null on
dotenv.env['SUPABASE_URL']/['SUPABASE_ANON_KEY']/['GEMINI_API_KEY']
(supabaseUrl, supabaseKey, geminiKey) and throws a generic Exception; change it
to treat null or empty/whitespace-only strings as missing by trimming each value
and collecting the names of any missing vars, then throw an Exception that lists
which specific variables are missing (e.g., "Missing environment variables:
SUPABASE_URL, GEMINI_API_KEY") so callers know exactly which env vars to fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@patient/lib/main.dart`:
- Around line 104-106: The catch block in main() currently only logs
initialization errors and returns, leaving the UI blank; update the catch to
call runApp() with a simple error UI so users see feedback instead of a frozen
screen. Create or use an InitializationErrorScreen (or similar) widget that
accepts the error/stack message, and in the catch (e, s) replace debugPrint(...)
with runApp(InitializationErrorScreen(error: e.toString(), stack: s.toString()))
(or wrap it in a small MaterialApp) so the app always renders a visible error
page when initialization (e.g., in main(), Supabase setup, or .env loading)
fails. Ensure you capture both exception and stack (catch (e, s)) and keep the
debugPrint but still call runApp to display the error widget.
- Around line 55-63: setupDependencyInjection currently registers
SupabasePatientRepository but not AuthRepository, causing manual instantiation
in main.dart to produce duplicate instances; update dependency_injector.dart to
register AuthRepository (mapping AuthRepository to SupabaseAuthRepository) and
then in main.dart stop creating new
SupabasePatientRepository/SupabaseAuthRepository instances and instead resolve
both repositories from getIt (e.g., getIt<PatientRepository>() and
getIt<AuthRepository>()) so providers receive the singleton instances and
chat_manager.dart's getIt<PatientRepository>() returns the same object.

---

Nitpick comments:
In `@patient/lib/main.dart`:
- Around line 27-34: The environment validation currently checks only for null
on dotenv.env['SUPABASE_URL']/['SUPABASE_ANON_KEY']/['GEMINI_API_KEY']
(supabaseUrl, supabaseKey, geminiKey) and throws a generic Exception; change it
to treat null or empty/whitespace-only strings as missing by trimming each value
and collecting the names of any missing vars, then throw an Exception that lists
which specific variables are missing (e.g., "Missing environment variables:
SUPABASE_URL, GEMINI_API_KEY") so callers know exactly which env vars to fix.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 247132d5-8019-4787-88ec-bb29ec5b1821

📥 Commits

Reviewing files that changed from the base of the PR and between 421e7c2 and bf08c18.

📒 Files selected for processing (1)
  • patient/lib/main.dart

Comment on lines +55 to +63
// Setup dependency injection
setupDependencyInjection();

// Create shared repositories
final supabaseClient = Supabase.instance.client;
final patientRepository =
SupabasePatientRepository(supabaseClient: supabaseClient);
final authRepository =
SupabaseAuthRepository(supabaseClient: supabaseClient);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if getIt is used elsewhere in the codebase to retrieve repositories
rg -n "getIt<" --type=dart -g '!**/dependency_injector.dart'

Repository: AOSSIE-Org/NeuroTrack

Length of output: 340


🏁 Script executed:

# Find the dependency injection setup file
fd -e dart | xargs grep -l "setupDependencyInjection"

Repository: AOSSIE-Org/NeuroTrack

Length of output: 208


🏁 Script executed:

# Look at main.dart more broadly to understand the context
find . -name "main.dart" -path "*/patient/*" -type f

Repository: AOSSIE-Org/NeuroTrack

Length of output: 88


🏁 Script executed:

# Check the provider definitions to see how repositories are passed
rg -n "PatientRepository\|AuthRepository" --type=dart -A 3 patient/lib/main.dart

Repository: AOSSIE-Org/NeuroTrack

Length of output: 47


🏁 Script executed:

# Read the dependency injector to see what gets registered
cat -n patient/lib/core/utils/dependency_injector.dart

Repository: AOSSIE-Org/NeuroTrack

Length of output: 597


🏁 Script executed:

# Read main.dart to see the full context around lines 55-63 and how repositories are used
cat -n patient/lib/main.dart | head -100

Repository: AOSSIE-Org/NeuroTrack

Length of output: 4065


Redundant repository instantiation creates inconsistent dependency management across the codebase.

setupDependencyInjection() registers SupabasePatientRepository as a singleton in GetIt, but lines 59-63 create new instances that are passed to providers. This results in:

  • Two separate SupabasePatientRepository instances in memory
  • Providers use the manually created instance
  • chat_manager.dart uses getIt<PatientRepository>(), retrieving a different instance
  • Inconsistent state management if changes occur in one instance

Update setupDependencyInjection() to also register AuthRepository, then retrieve both repositories from GetIt instead of creating them manually:

    // Setup dependency injection
    setupDependencyInjection();

-    // Create shared repositories
-    final supabaseClient = Supabase.instance.client;
-    final patientRepository =
-        SupabasePatientRepository(supabaseClient: supabaseClient);
-    final authRepository =
-        SupabaseAuthRepository(supabaseClient: supabaseClient);
+    // Retrieve shared repositories from GetIt
+    final patientRepository = getIt<PatientRepository>();
+    final authRepository = getIt<AuthRepository>();

This requires updating setupDependencyInjection() in dependency_injector.dart to register AuthRepository.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patient/lib/main.dart` around lines 55 - 63, setupDependencyInjection
currently registers SupabasePatientRepository but not AuthRepository, causing
manual instantiation in main.dart to produce duplicate instances; update
dependency_injector.dart to register AuthRepository (mapping AuthRepository to
SupabaseAuthRepository) and then in main.dart stop creating new
SupabasePatientRepository/SupabaseAuthRepository instances and instead resolve
both repositories from getIt (e.g., getIt<PatientRepository>() and
getIt<AuthRepository>()) so providers receive the singleton instances and
chat_manager.dart's getIt<PatientRepository>() returns the same object.

Comment on lines +104 to +106
} catch (e) {
debugPrint("App initialization failed: $e");
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

App fails silently if initialization errors occur - no UI is shown.

If any initialization step throws (e.g., missing .env file, Supabase connection failure), the app only logs to debug console and exits the main() function without calling runApp(). The user sees a blank/frozen screen with no feedback.

The PR objective was to "prevent crashes caused by missing .env variables," but this implementation still leaves the app in an unusable state.

🐛 Proposed fix: Show an error screen to the user
   } catch (e) {
     debugPrint("App initialization failed: $e");
+    runApp(
+      MaterialApp(
+        home: Scaffold(
+          body: Center(
+            child: Padding(
+              padding: const EdgeInsets.all(24.0),
+              child: Column(
+                mainAxisAlignment: MainAxisAlignment.center,
+                children: [
+                  const Icon(Icons.error_outline, size: 64, color: Colors.red),
+                  const SizedBox(height: 16),
+                  const Text(
+                    'Initialization Failed',
+                    style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
+                  ),
+                  const SizedBox(height: 8),
+                  Text(
+                    e.toString(),
+                    textAlign: TextAlign.center,
+                    style: const TextStyle(color: Colors.grey),
+                  ),
+                ],
+              ),
+            ),
+          ),
+        ),
+      ),
+    );
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (e) {
debugPrint("App initialization failed: $e");
}
} catch (e) {
debugPrint("App initialization failed: $e");
runApp(
MaterialApp(
home: Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, size: 64, color: Colors.red),
const SizedBox(height: 16),
const Text(
'Initialization Failed',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
e.toString(),
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.grey),
),
],
),
),
),
),
),
);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patient/lib/main.dart` around lines 104 - 106, The catch block in main()
currently only logs initialization errors and returns, leaving the UI blank;
update the catch to call runApp() with a simple error UI so users see feedback
instead of a frozen screen. Create or use an InitializationErrorScreen (or
similar) widget that accepts the error/stack message, and in the catch (e, s)
replace debugPrint(...) with runApp(InitializationErrorScreen(error:
e.toString(), stack: s.toString())) (or wrap it in a small MaterialApp) so the
app always renders a visible error page when initialization (e.g., in main(),
Supabase setup, or .env loading) fails. Ensure you capture both exception and
stack (catch (e, s)) and keep the debugPrint but still call runApp to display
the error widget.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enhancement: Improve environment variable handling in main.dart

1 participant