Skip to content

Conversation

@vnaik10
Copy link

@vnaik10 vnaik10 commented May 31, 2025

🐛 Issue Fixed
Fixes #369 - Users were being redirected to login page after successful signup instead of being automatically logged in and taken to home screen.
✨ Solution Overview
Implemented comprehensive authentication flow improvements with robust multi-layer error handling to create a seamless user experience! 🚀
🛠️ Changes Made
🗄️ Repository Layer

✅ Added atomic document creation with 200ms propagation delay
✅ Enhanced data consistency for user creation

🧩 Bloc Layer

✅ Implemented 3-retry mechanism with 300ms intervals for authentication state
✅ Improved state management reliability

📊 Data Models

✅ Added searchParams field to UserModel/UserEntity
✅ Enhanced search functionality capabilities

🧭 Router Layer

✅ Added signup-specific navigation guards
✅ Prevents redirect loops and improves flow control

🔥 Firebase Setup

✅ Updated configuration for better performance
✅ Added firebase_options.dart to gitignore for open source compatibility

🔧 Technical Improvements

🎯 Enhanced BlocBuilder type safety across authentication components
🛡️ Improved error handling throughout signup flow
⚡ Resolved navigation timing issues during authentication state changes
🔄 Better state synchronization between Firebase Auth and Firestore

🧪 Testing Results

✅ End-to-end signup flow - Works perfectly!
✅ Automatic redirect to home screen - No more manual login required
✅ Zero crashes or navigation loops - Stable and reliable
✅ Firebase integration - Authentication + Firestore working seamlessly

🎉 Impact & Benefits

🚀 Improved UX: Users now automatically logged in after successful signup
🛡️ Enhanced Stability: Better authentication state management prevents edge cases
🔄 Backward Compatible: All existing functionality preserved
📱 Smoother Onboarding: Reduces friction in user registration process

Closes #369 🔒

issue.369.fixed.mp4

Summary by CodeRabbit

  • New Features

    • User profiles now store searchable parameters to improve search and personalization.
  • Bug Fixes

    • More reliable startup login detection with automatic retry attempts.
    • Smoother sign-in/signup flows with small timing adjustments to reduce race conditions.
  • Chores

    • Refined app initialization and authentication wiring; root route now directs to the main view with auth-aware redirect.
  • UI

    • Updated responsive design defaults and improved tab styling; added a review provider at app root.

✏️ Tip: You can customize this high-level summary in your review settings.

@vnaik10 vnaik10 requested a review from jddeep as a code owner May 31, 2025 12:22
@coderabbitai
Copy link

coderabbitai bot commented May 31, 2025

Walkthrough

This PR adds retry logic to authentication user-fetching, inserts short delays and reorders dispatches in sign-in/sign-up flows, introduces a new searchParams field on user models/entities, removes the Wrapper widget in favor of root-level bloc provisioning, and adjusts root route redirecting to gate access by auth state.

Changes

Cohort / File(s) Change Summary
Authentication Bloc (retry logic)
lib/application/authentication/authentication_bloc.dart
Introduced retry loop (up to 3 attempts with 300ms delay) in _mapAppStartedToState and _mapLoggedInToState when calling _authRepository.getUser(). Emits Authenticated immediately if logged-in and user object present; continues retries if user present but data null; emits OnboardingIncomplete on final null; emits Unauthenticated for not-logged-in or on exception. Added attempt logging in _mapAppStartedToState.
Login / Register flows (timing & ordering)
lib/application/authentication/login_register/login_register_bloc.dart
Added 200ms async delays and reordered events: after Google sign-in and after SignUpWithEmail, the bloc now awaits ~200ms and dispatches LoggedIn before emitting SignUpSuccess (or emitting login-related states), removing the previous immediate LoggedIn dispatch paths. No public APIs changed.
User model/entity (searchParams)
lib/data/models/user_model.dart, lib/domain/entities/user_entity.dart
Added searchParams: List<String> to UserModel and UserEntity with default empty list. Wired through constructors, fromEntity/fromDocument/fromMap/fromSnapshot, and toEntity/toMap serialization paths. Adjusted props and map return types accordingly.
App bootstrap & routing
lib/main.dart, lib/router.dart
Removed the Wrapper-based routing; main.dart now provides AuthenticationBloc via MultiBlocProvider at app root and registers ReviewHubProvider. Root route ('/') now builds HomeView and uses a redirect callback that inspects AuthenticationBloc state to redirect unauthenticated users to /login. Simplified designSize logic and added tabBarTheme indicator color.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant LoginRegister as LoginRegisterBloc
    participant AuthRepo as AuthRepository
    participant AuthBloc as AuthenticationBloc
    participant Router

    User->>LoginRegister: complete sign-up / sign-in
    LoginRegister->>AuthRepo: create/sign-in user (backend)
    LoginRegister->>LoginRegister: await 200ms
    LoginRegister->>AuthBloc: dispatch LoggedIn
    LoginRegister-->>User: emit SignUpSuccess / SignedIn (after dispatch)
    AuthBloc->>AuthRepo: getUser()  <-- triggered by LoggedIn handling
    AuthRepo->>AuthRepo: attempt 1
    Note right of AuthRepo: if null -> wait 300ms and retry (up to 3)
    AuthRepo-->>AuthBloc: user object or null
    alt user present
        AuthBloc->>AuthBloc: emit Authenticated
        Router->>User: navigate Home
    else user null after retries
        AuthBloc->>AuthBloc: emit OnboardingIncomplete or Unauthenticated
        Router->>User: navigate Onboarding or Login
    end
Loading
sequenceDiagram
    participant AppStart as App
    participant AuthRepo as AuthRepository
    participant AuthBloc as AuthenticationBloc
    AppStart->>AuthBloc: AppStarted event
    AuthBloc->>AuthRepo: getUser()
    AuthRepo->>AuthRepo: attempt 1
    Note over AuthRepo: if response null -> 300ms delay and retry
    AuthRepo->>AuthRepo: attempt 2
    AuthRepo-->>AuthBloc: user or null
    alt user present
        AuthBloc->>AuthBloc: emit Authenticated
    else user null after retries
        AuthBloc->>AuthBloc: emit Unauthenticated
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Pay attention to authentication_bloc retry loop for race conditions and correct final-state emission.
  • Verify ordering and side effects in login_register_bloc after introducing the 200ms delays and reordering of dispatch vs emit.
  • Confirm new searchParams is consistently serialized/deserialized and that map keys/types match downstream expectations.
  • Check router redirect logic for possible timing issues when AuthenticationBloc state is uninitialized.

Poem

🐰
I hopped three times to fetch your state,
A little pause to make sign-up great.
New search seeds tucked in my sack,
Wrapper gone — I found a faster track.
Hop home now, no more detour chat!

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Out of Scope Changes check ❓ Inconclusive While primary changes address #369, the addition of searchParams field to UserModel and UserEntity appears unrelated to the signup/authentication flow fix. Clarify whether the searchParams field addition is required for issue #369 or represents separate feature work that should be split into a separate PR.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the primary change: implementing automatic login redirect after successful signup to fix issue #369.
Linked Issues check ✅ Passed All code changes directly address the linked issue #369: automatic login after signup and redirect to home screen without manual re-login.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

@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: 7

🧹 Nitpick comments (2)
lib/router.dart (1)

17-36: Review the redirect logic and consider potential edge cases.

The redirect logic handles the main authentication states correctly, but consider these potential improvements:

  1. Service locator coupling: Directly accessing locator<AuthenticationBloc>().state in the router creates tight coupling. Consider passing the authentication state through context or using a more dependency injection-friendly approach.

  2. Error handling: Add error handling for cases where the service locator might fail or the AuthenticationBloc is not properly initialized.

  3. State exhaustiveness: Consider adding explicit handling for any other possible authentication states to make the logic more defensive.

 redirect: (context, state) {
+  try {
     final authState = locator<AuthenticationBloc>().state;
     
     // Allow access if authenticated
     if (authState is Authenticated) {
       return null;
     }
     
     // Allow access if currently authenticating (during signup flow)
     if (authState is Uninitialized) {
       return null;
     }
     
     // Only redirect to login if definitely unauthenticated
     if (authState is Unauthenticated) {
       return '/login';
     }
     
     return null;
+  } catch (e) {
+    // Fallback to login if authentication state cannot be determined
+    return '/login';
+  }
 },
lib/data/repositories/firebase_authentication_repository.dart (1)

247-254: Consider enhancing the exception class for better error handling.

The current implementation is functional but could be improved to provide more structured error information.

Consider adding error codes or types for better error handling:

 class AuthenticationFailure implements Exception {
   final String message;
+  final String? code;
+  final dynamic originalError;
   
-  AuthenticationFailure(this.message);
+  AuthenticationFailure(this.message, {this.code, this.originalError});
+  
+  factory AuthenticationFailure.fromFirebaseException(FirebaseAuthException e) {
+    return AuthenticationFailure(
+      e.message ?? 'Authentication failed',
+      code: e.code,
+      originalError: e,
+    );
+  }
   
   @override
   String toString() => message;
 }

Then update usage:

-    } on FirebaseAuthException catch (e) {
-      throw AuthenticationFailure(e.message ?? 'Authentication failed');
+    } on FirebaseAuthException catch (e) {
+      throw AuthenticationFailure.fromFirebaseException(e);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7074a6e and f3db9b7.

📒 Files selected for processing (7)
  • lib/application/authentication/authentication_bloc.dart (1 hunks)
  • lib/application/authentication/login_register/login_register_bloc.dart (2 hunks)
  • lib/data/models/user_model.dart (6 hunks)
  • lib/data/repositories/firebase_authentication_repository.dart (3 hunks)
  • lib/domain/entities/user_entity.dart (6 hunks)
  • lib/main.dart (3 hunks)
  • lib/router.dart (1 hunks)
🔇 Additional comments (3)
lib/domain/entities/user_entity.dart (1)

16-16: Well-implemented addition of the searchParams field.

The searchParams field has been consistently added across all parts of the UserEntity class:

  • ✅ Added to class definition with proper typing
  • ✅ Included in constructor with sensible default (empty list)
  • ✅ Handled in both fromMap and fromSnapshot factory methods with null safety
  • ✅ Included in toMap serialization
  • ✅ Maintains backward compatibility

The implementation follows proper patterns and maintains consistency with existing list fields like following, followers, and posts.

Also applies to: 22-22, 46-48, 59-60, 74-76, 87-88, 105-105

lib/data/models/user_model.dart (1)

17-17: Well-implemented field addition!

The searchParams field has been consistently integrated throughout the model class, following the same patterns as existing fields. The null-safe handling in fromMap and proper initialization with an empty list are good practices.

Also applies to: 23-23, 49-49, 64-64, 78-80, 92-92, 107-107

lib/main.dart (1)

85-87: Verify UI scaling across different device sizes.

The fixed design size of 390x844 (iPhone 12/13 dimensions) might not scale optimally on tablets or desktop screens that were previously handled with conditional logic.

Please ensure the UI looks correct on:

  • Tablets (both portrait and landscape)
  • Desktop/web views
  • Smaller phones (e.g., iPhone SE)

The splitScreenMode: true helps, but visual testing across devices is recommended.

Comment on lines +102 to 107

// Add delay before updating authentication state
await Future.delayed(const Duration(milliseconds: 200));

// Then update authentication state
_authenticationBloc.add(LoggedIn());
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Reconsider the fixed delay approach for state synchronization.

The 200ms delay before updating authentication state is a brittle approach to handle data consistency. This could lead to issues in varying network conditions and doesn't guarantee that Firestore operations have completed.

Consider these more robust alternatives:

  1. Implement proper completion callbacks from the repository layer
  2. Use Firebase Auth state change listeners to trigger authentication updates
  3. Implement retry mechanisms in the data fetching layer instead of fixed delays
- // Add delay before updating authentication state
- await Future.delayed(const Duration(milliseconds: 200));
- 
- // Then update authentication state
+ // Update authentication state immediately - let AuthenticationBloc handle retries
 _authenticationBloc.add(LoggedIn());

The AuthenticationBloc already has retry logic, so the delays here might be redundant.

🤖 Prompt for AI Agents
In lib/application/authentication/login_register/login_register_bloc.dart around
lines 102 to 107, replace the fixed 200ms delay before updating the
authentication state with a more reliable synchronization method. Remove the
Future.delayed call and instead ensure that the authentication state update
(_authenticationBloc.add(LoggedIn())) is triggered only after confirming that
Firestore operations have fully completed, either by using completion callbacks
from the repository, listening to Firebase Auth state changes, or relying on
existing retry logic in the AuthenticationBloc to handle consistency without
arbitrary delays.

Comment on lines +146 to +153
// First wait for a delay to ensure Firestore propagation
await Future.delayed(const Duration(milliseconds: 200));

// Then add the LoggedIn event
_authenticationBloc.add(LoggedIn());

// Then emit SignUpSuccess
emit(SignUpSuccess(user));
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Same timing concern applies to the signup flow.

The fixed 200ms delay approach has the same reliability issues as mentioned in the Google signin flow. The comment mentions "Firestore propagation" but this doesn't guarantee the operation has completed.

Since the repository's signUp method should handle the atomicity of user creation, consider removing this delay and letting the AuthenticationBloc's retry mechanism handle any timing issues:

- // First wait for a delay to ensure Firestore propagation
- await Future.delayed(const Duration(milliseconds: 200));
- 
- // Then add the LoggedIn event
+ // Add the LoggedIn event - AuthenticationBloc will handle retries
  _authenticationBloc.add(LoggedIn());
- 
- // Then emit SignUpSuccess
  emit(SignUpSuccess(user));
📝 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
// First wait for a delay to ensure Firestore propagation
await Future.delayed(const Duration(milliseconds: 200));
// Then add the LoggedIn event
_authenticationBloc.add(LoggedIn());
// Then emit SignUpSuccess
emit(SignUpSuccess(user));
// Add the LoggedIn event - AuthenticationBloc will handle retries
_authenticationBloc.add(LoggedIn());
emit(SignUpSuccess(user));
🤖 Prompt for AI Agents
In lib/application/authentication/login_register/login_register_bloc.dart around
lines 146 to 153, remove the fixed 200ms delay that waits for Firestore
propagation before adding the LoggedIn event and emitting SignUpSuccess. This
delay is unreliable and unnecessary because the signUp method in the repository
should ensure atomic user creation. Instead, directly add the LoggedIn event and
emit SignUpSuccess, allowing the AuthenticationBloc's retry mechanism to handle
any timing or propagation issues.

Comment on lines +71 to 101
int retries = 0;
const maxRetries = 3;
const retryDelay = Duration(milliseconds: 300);

while (retries < maxRetries) {
final (userLoggedIn, user) = await _authRepository.getUser();

if (userLoggedIn && user != null) {

emit(Authenticated(user.toEntity()));
return;
} else if (userLoggedIn && user == null) {
if (retries == maxRetries - 1) {

emit(OnboardingIncomplete());
return;
}
} else {

emit(Unauthenticated());
return;
}


retries++;
await Future.delayed(retryDelay);
}


emit(Unauthenticated());
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Apply the same refactoring to avoid code duplication.

This method has identical retry logic to _mapAppStartedToState. Using the extracted _handleAuthenticationCheck method would eliminate this duplication.

 _mapLoggedInToState(
     AuthenticationEvent event, Emitter<AuthenticationState> emit) async {
-  // ... existing retry logic
+  await _handleAuthenticationCheck(emit);
 }

This also removes the need for try-catch here since the extracted method handles the authentication logic, and any unexpected errors would bubble up appropriately.

📝 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
int retries = 0;
const maxRetries = 3;
const retryDelay = Duration(milliseconds: 300);
while (retries < maxRetries) {
final (userLoggedIn, user) = await _authRepository.getUser();
if (userLoggedIn && user != null) {
emit(Authenticated(user.toEntity()));
return;
} else if (userLoggedIn && user == null) {
if (retries == maxRetries - 1) {
emit(OnboardingIncomplete());
return;
}
} else {
emit(Unauthenticated());
return;
}
retries++;
await Future.delayed(retryDelay);
}
emit(Unauthenticated());
}
_mapLoggedInToState(
AuthenticationEvent event, Emitter<AuthenticationState> emit) async {
await _handleAuthenticationCheck(emit);
}
🤖 Prompt for AI Agents
In lib/application/authentication/authentication_bloc.dart between lines 71 and
101, the retry logic in this method duplicates the logic already extracted into
the _handleAuthenticationCheck method used by _mapAppStartedToState. Refactor
this method to call _handleAuthenticationCheck instead of repeating the retry
loop and authentication checks. This will remove code duplication and also
eliminate the need for a try-catch block here since _handleAuthenticationCheck
manages errors and authentication logic centrally.

Comment on lines +32 to +62
int retries = 0;
const maxRetries = 3;
const retryDelay = Duration(milliseconds: 300);

while (retries < maxRetries) {
final (userLoggedIn, user) = await _authRepository.getUser();
log('User: $userLoggedIn, $user (attempt ${retries + 1})');

if (userLoggedIn && user != null) {

emit(Authenticated(user.toEntity()));
return;
} else if (userLoggedIn && user == null) {
if (retries == maxRetries - 1) {

emit(OnboardingIncomplete());
return;
}
} else {

emit(Unauthenticated());
return;
}


retries++;
await Future.delayed(retryDelay);
}


emit(Unauthenticated());
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve the retry mechanism implementation.

The retry logic is a good approach for handling eventual consistency issues, but there are opportunities for improvement:

  1. Code duplication: The retry logic is duplicated between _mapAppStartedToState and _mapLoggedInToState
  2. Magic numbers: Retry count and delay should be configurable constants
  3. Logging: Consider removing or making the logging conditional for production

Extract the retry logic into a private method:

+ static const int _maxRetries = 3;
+ static const Duration _retryDelay = Duration(milliseconds: 300);
+
+ Future<void> _handleAuthenticationCheck(Emitter<AuthenticationState> emit, {bool logAttempts = false}) async {
+   int retries = 0;
+   
+   while (retries < _maxRetries) {
+     final (userLoggedIn, user) = await _authRepository.getUser();
+     if (logAttempts) {
+       log('User: $userLoggedIn, $user (attempt ${retries + 1})');
+     }
+     
+     if (userLoggedIn && user != null) {
+       emit(Authenticated(user.toEntity()));
+       return;
+     } else if (userLoggedIn && user == null) {
+       if (retries == _maxRetries - 1) {
+         emit(OnboardingIncomplete());
+         return;
+       }
+     } else {
+       emit(Unauthenticated());
+       return;
+     }
+     
+     retries++;
+     await Future.delayed(_retryDelay);
+   }
+   
+   emit(Unauthenticated());
+ }

Then simplify both methods:

 _mapAppStartedToState(
     AuthenticationEvent event, Emitter<AuthenticationState> emit) async {
   try {
-    // ... existing retry logic
+    await _handleAuthenticationCheck(emit, logAttempts: true);
   } catch (_) {
     emit(Unauthenticated());
   }
 }
📝 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
int retries = 0;
const maxRetries = 3;
const retryDelay = Duration(milliseconds: 300);
while (retries < maxRetries) {
final (userLoggedIn, user) = await _authRepository.getUser();
log('User: $userLoggedIn, $user (attempt ${retries + 1})');
if (userLoggedIn && user != null) {
emit(Authenticated(user.toEntity()));
return;
} else if (userLoggedIn && user == null) {
if (retries == maxRetries - 1) {
emit(OnboardingIncomplete());
return;
}
} else {
emit(Unauthenticated());
return;
}
retries++;
await Future.delayed(retryDelay);
}
emit(Unauthenticated());
// In AuthenticationBloc class
// Make retry settings configurable
static const int _maxRetries = 3;
static const Duration _retryDelay = Duration(milliseconds: 300);
// Extracted retry logic
Future<void> _handleAuthenticationCheck(
Emitter<AuthenticationState> emit, {
bool logAttempts = false,
}) async {
int retries = 0;
while (retries < _maxRetries) {
final (userLoggedIn, user) = await _authRepository.getUser();
if (logAttempts) {
log('User: $userLoggedIn, $user (attempt ${retries + 1})');
}
if (userLoggedIn && user != null) {
emit(Authenticated(user.toEntity()));
return;
} else if (userLoggedIn && user == null) {
if (retries == _maxRetries - 1) {
emit(OnboardingIncomplete());
return;
}
} else {
emit(Unauthenticated());
return;
}
retries++;
await Future.delayed(_retryDelay);
}
emit(Unauthenticated());
}
// Simplified mapping using the new helper
Future<void> _mapAppStartedToState(
AuthenticationEvent event,
Emitter<AuthenticationState> emit,
) async {
try {
await _handleAuthenticationCheck(emit, logAttempts: true);
} catch (_) {
emit(Unauthenticated());
}
}
🤖 Prompt for AI Agents
In lib/application/authentication/authentication_bloc.dart around lines 32 to
62, the retry logic is duplicated and uses hardcoded retry count and delay
values, with unconditional logging. Refactor by extracting the retry mechanism
into a private method that accepts configurable retry count and delay
parameters, and includes optional logging controlled by a flag. Then update both
_mapAppStartedToState and _mapLoggedInToState methods to call this new private
method, removing duplicated code and replacing magic numbers with constants or
parameters.

lib/main.dart Outdated
Comment on lines 29 to 36
try {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
debugPrint('Firebase initialized successfully');
} catch (e) {
debugPrint('Firebase initialization failed: $e');
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consider handling Firebase initialization failures more robustly.

Currently, the app continues running even if Firebase initialization fails. This could lead to runtime errors when Firebase services are accessed later in the app.

Consider either:

  1. Showing an error screen to the user
  2. Retrying initialization with exponential backoff
  3. At minimum, setting a flag to prevent Firebase service usage
  try {
    await Firebase.initializeApp(
      options: DefaultFirebaseOptions.currentPlatform,
    );
    debugPrint('Firebase initialized successfully');
  } catch (e) {
    debugPrint('Firebase initialization failed: $e');
+   // Consider showing an error screen or retrying
+   // throw Exception('Failed to initialize Firebase: $e');
  }
📝 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
try {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
debugPrint('Firebase initialized successfully');
} catch (e) {
debugPrint('Firebase initialization failed: $e');
}
try {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
debugPrint('Firebase initialized successfully');
} catch (e) {
debugPrint('Firebase initialization failed: $e');
// Consider showing an error screen or retrying
// throw Exception('Failed to initialize Firebase: $e');
}
🤖 Prompt for AI Agents
In lib/main.dart around lines 29 to 36, the current Firebase initialization
catches errors but allows the app to continue running, which may cause runtime
issues later. Improve robustness by implementing one of the suggested
strategies: show an error screen if initialization fails, implement a retry
mechanism with exponential backoff, or at least set a flag indicating Firebase
is not initialized to prevent usage of Firebase services until successful
initialization.

Comment on lines 106 to 116
final userData = {
'uid': user.uid,
'email': email,
'name': name,
'username': username,
'status': status,
'profilePictureUrl': profilePictureUrl,
'searchParams': searchParams,
'followers': [],
'following': [],
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add missing 'posts' field for consistency.

The userData map is missing the 'posts' field, which exists in UserModel. While the model handles this with a default value, it's better to be explicit for consistency with other methods.

      final userData = {
        'uid': user.uid,
        'email': email,
        'name': name,
        'username': username,
        'status': status,
        'profilePictureUrl': profilePictureUrl,
        'searchParams': searchParams,
        'followers': [],
        'following': [],
+       'posts': [],
      };
📝 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
final userData = {
'uid': user.uid,
'email': email,
'name': name,
'username': username,
'status': status,
'profilePictureUrl': profilePictureUrl,
'searchParams': searchParams,
'followers': [],
'following': [],
};
final userData = {
'uid': user.uid,
'email': email,
'name': name,
'username': username,
'status': status,
'profilePictureUrl': profilePictureUrl,
'searchParams': searchParams,
'followers': [],
'following': [],
'posts': [],
};
🤖 Prompt for AI Agents
In lib/data/repositories/firebase_authentication_repository.dart between lines
106 and 116, the userData map lacks the 'posts' field present in UserModel. Add
the 'posts' field explicitly to the userData map, initializing it appropriately
(e.g., as an empty list) to maintain consistency with other methods and the
model definition.

Comment on lines 118 to 122
// 4. Force synchronous document creation
await _database.collection('users').doc(user.uid).set(userData);

// 5. Add a short delay to allow Firestore propagation
await Future.delayed(const Duration(milliseconds: 200));
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider a more robust approach than fixed delay.

The 200ms delay is a workaround for Firestore's eventual consistency but may not be sufficient under poor network conditions or high load.

Consider one of these approaches:

  1. Use a transaction to ensure atomicity
  2. Verify document creation by reading it back
  3. Use Firestore's real-time listeners

Example of verification approach:

-     // 4. Force synchronous document creation
-     await _database.collection('users').doc(user.uid).set(userData);
-     
-     // 5. Add a short delay to allow Firestore propagation
-     await Future.delayed(const Duration(milliseconds: 200));
+     // 4. Create document and verify
+     await _database.collection('users').doc(user.uid).set(userData);
+     
+     // 5. Verify document exists with retry
+     DocumentSnapshot doc;
+     int retries = 0;
+     do {
+       doc = await _database.collection('users').doc(user.uid).get();
+       if (!doc.exists && retries < 3) {
+         await Future.delayed(const Duration(milliseconds: 100));
+         retries++;
+       }
+     } while (!doc.exists && retries < 3);
+     
+     if (!doc.exists) {
+       throw AuthenticationFailure('Failed to create user document');
+     }
📝 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
// 4. Force synchronous document creation
await _database.collection('users').doc(user.uid).set(userData);
// 5. Add a short delay to allow Firestore propagation
await Future.delayed(const Duration(milliseconds: 200));
// 4. Create document and verify
await _database.collection('users').doc(user.uid).set(userData);
// 5. Verify document exists with retry
DocumentSnapshot doc;
int retries = 0;
do {
doc = await _database.collection('users').doc(user.uid).get();
if (!doc.exists && retries < 3) {
await Future.delayed(const Duration(milliseconds: 100));
retries++;
}
} while (!doc.exists && retries < 3);
if (!doc.exists) {
throw AuthenticationFailure('Failed to create user document');
}
🤖 Prompt for AI Agents
In lib/data/repositories/firebase_authentication_repository.dart around lines
118 to 122, replace the fixed 200ms delay after setting the user document with a
more reliable method. Instead of awaiting a fixed delay, implement a
verification step by reading back the document after the set operation to
confirm its creation, or use a Firestore transaction to ensure atomicity, or
attach a real-time listener to detect when the document is available. This will
make the code more robust against network latency and Firestore's eventual
consistency.

@vnaik10
Copy link
Author

vnaik10 commented May 31, 2025 via email

@vnaik10
Copy link
Author

vnaik10 commented May 31, 2025 via email

@coderabbitai
Copy link

coderabbitai bot commented May 31, 2025

Tip

For best results, initiate chat on the files or code changes.

@vnaik10 You're absolutely right to prioritize fixing the core authentication issue first! 🎯

Your approach is sound - getting Issue #369 resolved with a working solution and then iterating on the architecture is good engineering practice. The 200ms delays may not be the most elegant solution, but if they're tested and working reliably for your use case, that's what matters for this PR.

I appreciate you taking the time to consider the suggestions for future improvements. The retry verification approach and code deduplication can definitely wait for a follow-up PR when you have more bandwidth or when maintainers request those enhancements.

Thanks for the thoughtful response, and great work getting the automatic login redirect working! The users will definitely appreciate not having to go through the extra login step after signup.

Feel free to tag me if you need any assistance when you do tackle those architectural improvements in the future. 🚀

@vnaik10
Copy link
Author

vnaik10 commented Nov 18, 2025

All merge conflicts have been resolved. The PR is now aligned with the latest Appwrite migration changes. Ready for review again.

@vnaik10 vnaik10 marked this pull request as draft November 22, 2025 01:29
@vnaik10 vnaik10 marked this pull request as ready for review November 22, 2025 01:29
Copy link

@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: 1

♻️ Duplicate comments (2)
lib/application/authentication/login_register/login_register_bloc.dart (2)

101-107: Delay after Google sign‑in is acceptable as a tactical fix but should be revisited.

The 200 ms sleep before dispatching LoggedIn is a pragmatic way to smooth out backend propagation, but it’s still a brittle heuristic and duplicates concerns already handled in AuthenticationBloc’s retry logic. Consider, in a follow‑up, moving this timing concern into the repository/AuthBloc (e.g., via completion signals or read‑back) and removing the hardcoded delay so login isn’t coupled to a magic number.


145-153: Signup delay + LoggedIn ordering works but comment and timing deserve cleanup later.

The 200 ms delay before LoggedIn followed by SignUpSuccess matches the intended “auto‑login after signup” behavior and appears to fix the race you were targeting. That said, it’s still a fixed‑delay workaround, and the inline “Firestore propagation” comment is now a bit misleading given the Appwrite‑backed repo. In a future pass, consider:

  • Replacing the delay with a more deterministic sync (repo‑level confirmation / AuthBloc retry only).
  • Updating the comment to describe generic backend propagation rather than Firestore specifically.

Not blocking this PR, but worth tracking as tech debt.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f3db9b7 and e48ec8b.

📒 Files selected for processing (4)
  • lib/application/authentication/login_register/login_register_bloc.dart (2 hunks)
  • lib/data/models/user_model.dart (9 hunks)
  • lib/domain/entities/user_entity.dart (3 hunks)
  • lib/main.dart (3 hunks)
🔇 Additional comments (5)
lib/main.dart (3)

9-13: Root AuthenticationBloc wiring aligns with the new auth‑driven routing.

Providing AuthenticationBloc at the top level via MultiBlocProvider and the service locator matches the new automatic login / routing flow and should keep auth state globally accessible without extra wrapper widgets, assuming no other conflicting AuthenticationBloc providers remain.

Please double‑check that any previous AuthenticationBloc providers (e.g., inside removed Wrapper or other shells) have been cleaned up so you don’t end up with multiple bloc instances in the tree.

Also applies to: 36-41


63-73: Centralized designSize logic looks consistent across platforms.

The new designSize branching on kIsWeb vs. (iOS/Android) vs. other platforms, with the width threshold at 530 px, is clear and should make responsive tuning easier going forward; no obvious edge cases stand out here.


91-94: Theme + ScreenUtil/breakpoints wiring remains coherent with the previous layout.

Adding a TabBarTheme and passing the computed designSize directly into ScreenUtilInit (while preserving the existing breakpoint definitions) keeps the responsive behavior intact and clarifies where typography/layout scaling is configured. Looks good; just ensure you’ve sanity‑checked on a small mobile width and a large desktop width.

Also applies to: 100-108

lib/data/models/user_model.dart (1)

19-20: searchParams and savedMonuments mappings are consistent end‑to‑end.

The new searchParams field and its defaults, plus the added mappings in fromEntity, toEntity, fromMap, and toMap are all symmetric and safe (they fall back to empty lists when absent). The refactor for savedMonuments to go through MonumentModel.fromJson / toJson also looks coherent with the rest of the model.

Also applies to: 35-36, 69-71, 99-100, 125-127, 129-133, 146-148, 172-173

lib/domain/entities/user_entity.dart (1)

19-20: New searchParams and savedMonuments support is wired correctly across entity and map.

The added searchParams field (with an empty‑list default) and its inclusion in props, fromDocument, fromMap, and toMap all line up. Likewise, the savedMonuments handling via MonumentEntity.fromMap(...) on read and .toMap() on write keeps the serialization round‑trip consistent. Defaults via List<String>.from(... ?? []) and the null‑aware savedMonuments mapping should also protect against missing fields in older documents.

Also applies to: 34-35, 52-71, 73-99, 106-131, 133-147

Comment on lines 102 to 104
factory UserEntity.fromSnapshot(DocumentSnapshot snap) {
return UserEntity.fromMap(snap.data() as Map<String, dynamic>);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Undefined DocumentSnapshot in fromSnapshot will break compilation unless imported or aliased.

UserEntity.fromSnapshot(DocumentSnapshot snap) references DocumentSnapshot, but this file only imports appwrite/models.dart and equatable.dart; there’s no visible import for the Firestore DocumentSnapshot type (or any local alias). This will cause a compile error unless DocumentSnapshot is defined elsewhere in your project’s imports.

You likely need to either:

  • Re‑add the appropriate Firestore import (e.g., import 'package:cloud_firestore/cloud_firestore.dart';) if this factory is still used, or
  • Remove/replace this factory entirely if your data layer has fully migrated to Appwrite Document and you no longer rely on Firestore snapshots.

Given this touches core user serialization, it should be fixed before merging.

Please verify with your analyzer/build that DocumentSnapshot resolves correctly in this file; if not, update the imports or remove this constructor.


I'll verify the review comment by examining the actual file and checking whether DocumentSnapshot is truly undefined.


---

🏁 Script executed:

```shell
#!/bin/bash
# Check full contents of the file to see all imports
cat lib/domain/entities/user_entity.dart

Length of output: 5095


🏁 Script executed:

#!/bin/bash
# Search for DocumentSnapshot definition or import across the codebase
rg -n "DocumentSnapshot" --type dart

Length of output: 1588


🏁 Script executed:

#!/bin/bash
# Check if fromSnapshot factory is used anywhere
rg -n "fromSnapshot" --type dart -C 2

Length of output: 1090


Remove the undefined fromSnapshot factory method—it references undefined DocumentSnapshot and is dead code.

The review comment is correct. Verification confirms:

  • DocumentSnapshot is not imported in user_entity.dart
  • The factory method at lines 102-104 references this undefined type, causing a compilation error
  • The method is dead code: only callers are commented out in firebase_social_repository.dart
  • Appwrite's Document type is already the primary data layer (see fromDocument factory)

Remove lines 102-104 entirely since the codebase has migrated from Firebase to Appwrite and this factory is no longer needed.

🤖 Prompt for AI Agents
In lib/domain/entities/user_entity.dart around lines 102 to 104, remove the
entire factory UserEntity.fromSnapshot(DocumentSnapshot snap) { return
UserEntity.fromMap(snap.data() as Map<String, dynamic>); } since
DocumentSnapshot is undefined and the factory is dead code after migrating from
Firebase to Appwrite; delete these lines and ensure no leftover references
remain (no new imports or usages added).

Copy link

@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: 0

🧹 Nitpick comments (1)
lib/domain/entities/user_entity.dart (1)

19-19: searchParams field added consistently.

The new field follows the same pattern as other list fields and is correctly integrated throughout the entity. Consider adding a documentation comment explaining its purpose and expected content for future maintainability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e48ec8b and 299f049.

📒 Files selected for processing (1)
  • lib/domain/entities/user_entity.dart (3 hunks)
🔇 Additional comments (3)
lib/domain/entities/user_entity.dart (3)

34-34: LGTM: Constructor parameter added correctly.

The searchParams parameter uses the same default empty list pattern as other collection fields, maintaining consistency.


86-86: Serialization paths correctly implemented.

The searchParams field is parsed and serialized consistently across fromDocument, fromMap, and toMap methods, using null-safe defaults and appropriate type conversions.

Also applies to: 113-113, 140-140


102-127: Past review comment appears resolved.

The previous review flagged an undefined fromSnapshot factory method at lines 102-104. In the current code, these lines contain the fromMap factory method, and no fromSnapshot method is present. The issue appears to have been addressed.

@vnaik10
Copy link
Author

vnaik10 commented Nov 22, 2025

Hi maintainers 👋
All merge conflicts are resolved and CodeRabbit checks have passed.
The PR is ready for review whenever you have time. Thank you!

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.

Improve Sign Up flow

1 participant