Skip to content

TF-4268 Cache Sentry config for FCM background re-initialization #4443

Open
dab246 wants to merge 3 commits intomasterfrom
features/tf-4268-fcm-sentry-cache
Open

TF-4268 Cache Sentry config for FCM background re-initialization #4443
dab246 wants to merge 3 commits intomasterfrom
features/tf-4268-fcm-sentry-cache

Conversation

@dab246
Copy link
Copy Markdown
Member

@dab246 dab246 commented Apr 7, 2026

Description

Persists SentryConfig and SentryUser to Hive so the FCM background isolate (which runs in a separate Dart isolate) can re-initialize Sentry without making a network call.

Summary by CodeRabbit

  • New Features

    • Encrypted local caching for Sentry configuration and user data with read/write APIs and model↔cache conversions.
    • New not-found exceptions for cached Sentry data.
    • Cache manager integrated into account-clear flows to remove Sentry data on mobile.
  • Improvements

    • Idempotent, guarded background initialization and stronger error logging across push/background flows.
    • Safer async resource cleanup.
    • Platform-aware Sentry setup (skipped on web; conditional on mobile).
    • Reduced default Sentry sampling rates for tracing/profiling.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 7, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 74b1959b-0255-47f7-9f3a-145cd785b913

📥 Commits

Reviewing files that changed from the base of the PR and between 376a8ea and 0848c6e.

📒 Files selected for processing (2)
  • lib/features/caching/manager/sentry_configuration_cache_manager.dart
  • lib/features/push_notification/presentation/services/fcm_receiver.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/features/caching/manager/sentry_configuration_cache_manager.dart

Walkthrough

Adds encrypted Hive-backed caching for Sentry: new cache entry models (SentryConfigurationCache, SentryUserCache) with Hive adapters and constants, encrypted Hive clients (SentryConfigurationCacheClient, SentryUserCacheClient), and two not-found exceptions. Introduces SentryConfigurationCacheManager and extensions to convert between domain Sentry types and cache types. Wires the manager into CachingManager (mobile-only) and dependency injection, and integrates cache reads/writes into Sentry setup and FCM background initialization flows. Also adjusts Sentry sampling defaults and related Sentry initialization control paths.

Possibly related PRs

Suggested reviewers

  • hoangdat
  • tddang-linagora
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main objective: caching Sentry configuration to enable FCM background re-initialization without network calls, which aligns with the central purpose of all changes across multiple files.
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
  • Commit unit tests in branch features/tf-4268-fcm-sentry-cache

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.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

This PR has been deployed to https://linagora.github.io/tmail-flutter/4443.

@dab246 dab246 closed this Apr 8, 2026
@hoangdat hoangdat reopened this Apr 9, 2026
@hoangdat hoangdat marked this pull request as ready for review April 9, 2026 07:17
codescene-delta-analysis[bot]

This comment was marked as outdated.

@hoangdat
Copy link
Copy Markdown
Member

hoangdat commented Apr 9, 2026

@CodeRabbit please review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 9, 2026

@hoangdat: I'll review the changes in this PR right away!


🧠 Learnings used
Learnt from: dab246
Repo: linagora/tmail-flutter PR: 4137
File: lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart:32-32
Timestamp: 2025-12-15T06:24:50.369Z
Learning: In lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart and lib/features/manage_account/presentation/manage_account_dashboard_controller.dart, SentryManager.instance.setUser() intentionally sends PII (account ID, display name, username, email) to Sentry for error tracking. The team plans to document this in the app's privacy policy for transparency and compliance.

Learnt from: dab246
Repo: linagora/tmail-flutter PR: 4393
File: lib/features/caching/manager/app_security_manager.dart:186-194
Timestamp: 2026-03-20T06:22:58.063Z
Learning: In `lib/features/caching/manager/app_security_manager.dart` (linagora/tmail-flutter), `AppSecurityManager._wipeSharePreferenceSafe()` intentionally calls `SharedPreferences.clear()` to perform a full reset of all app preferences. This is by design: when an inconsistent state is detected on Android (Hive data exists on disk but the encryption key is missing from secure storage — e.g. after an Android backup restore), the app wipes all local storage including SharedPreferences to force the user to re-authenticate and reach a consistent state. Do not flag this as an unintended broad data deletion.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@dab246 dab246 changed the base branch from features/tf-4268-enable-sentry-for-android to master April 9, 2026 08:03
Copy link
Copy Markdown
Contributor

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/features/caching/caching_manager.dart`:
- Around line 279-289: The new CachingManager::clearSentryConfiguration() is
never invoked from account- or full-reset flows, so cached SentryUser can
survive logout/account switch; update the account-scoped clear paths to call
CachingManager.clearSentryConfiguration() (specifically add calls in
clearAccountDataCached() and clearAll()/full-reset paths where account-scoped
caches are cleared) so _sentryConfigurationCacheManager is cleared during
logout/account switch/full reset; ensure this is invoked alongside other
account-cache clears and before any SentryManager.instance.setUser() calls that
might rehydrate user context.

In `@lib/features/caching/extensions/sentry_cache_extensions.dart`:
- Around line 6-22: The extension method
SentryConfigExtension.toSentryConfigurationCache currently omits the nullable
dist field; update to include dist when constructing SentryConfigurationCache
(add dist: dist) so the distribution is preserved, and then add a nullable dist
property to the SentryConfigurationCache class and its Hive adapter
implementation (ensure read/write and typeId handling include dist) so
serialization/deserialization round-trips the dist value.

In
`@lib/features/push_notification/presentation/controller/fcm_message_controller.dart`:
- Around line 126-132: The catch in FcmMessageController::initialAppConfig
currently only logs via logError and swallows failures, allowing the background
handler to continue with partially-initialized bindings/Hive; change this to
propagate the failure back to the caller by rethrowing the caught error (or
throwing a new descriptive exception) after logging so the background pipeline
can abort/cleanup, or alternatively return an explicit failure/result from
initialAppConfig that the background handler checks before calling
_getInteractorBindings(); update callers to handle the propagated error/result
accordingly.
- Around line 114-117: MainBindings().dependencies() is synchronous (returns
void) and cannot be passed to Future.wait which expects Futures; change the code
to call MainBindings().dependencies() before or after awaiting the asynchronous
HiveCacheConfig.instance.setUp(), or wrap the sync call in a Future (e.g.,
Future.sync) so only actual Futures are passed to Future.wait; locate the call
using the symbols MainBindings().dependencies(), Future.wait, and
HiveCacheConfig.instance.setUp() and modify the invocation so Future.wait
receives only Futures (or call dependencies() separately).

In `@lib/features/push_notification/presentation/services/fcm_service.dart`:
- Around line 35-48: The closeStream method currently wraps both
backgroundMessageStreamController?.close() and fcmTokenStreamController?.close()
in one try so if the first close throws the second is skipped; change it to
close each controller in its own try/catch (e.g., separate try blocks for
backgroundMessageStreamController?.close() and for
fcmTokenStreamController?.close()), await each close independently, and log
errors for each using logError with a contextual message (retain the existing
finally that sets backgroundMessageStreamController = null and
fcmTokenStreamController = null).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b5c9ea54-056a-4ebd-852e-2c70f8253d82

📥 Commits

Reviewing files that changed from the base of the PR and between c85662f and f596b0c.

📒 Files selected for processing (15)
  • lib/features/caching/caching_manager.dart
  • lib/features/caching/clients/sentry_configuration_cache_client.dart
  • lib/features/caching/clients/sentry_user_cache_client.dart
  • lib/features/caching/config/hive_cache_config.dart
  • lib/features/caching/entries/sentry_configuration_cache.dart
  • lib/features/caching/entries/sentry_user_cache.dart
  • lib/features/caching/exceptions/local_storage_exception.dart
  • lib/features/caching/extensions/sentry_cache_extensions.dart
  • lib/features/caching/manager/sentry_configuration_cache_manager.dart
  • lib/features/caching/utils/caching_constants.dart
  • lib/features/push_notification/presentation/controller/fcm_message_controller.dart
  • lib/features/push_notification/presentation/listener/email_change_listener.dart
  • lib/features/push_notification/presentation/services/fcm_receiver.dart
  • lib/features/push_notification/presentation/services/fcm_service.dart
  • lib/main/bindings/local/local_bindings.dart

…tion

Signed-off-by: dab246 <tdvu@linagora.com>
@dab246 dab246 force-pushed the features/tf-4268-fcm-sentry-cache branch from f596b0c to 1609fcb Compare April 9, 2026 09:22
codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

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

🧹 Nitpick comments (1)
lib/features/mailbox_dashboard/presentation/mixin/sentry_ecosystem_mixin.dart (1)

57-59: Include stack trace in cache-failure logging for diagnosis.

Current warning only logs $e; adding st would make production investigation much easier when cache writes fail.

🔧 Proposed adjustment
-    } catch (e) {
-      logWarning('SentryEcosystemMixin::_cacheSentryData: Cannot cache Sentry data: $e');
+    } catch (e, st) {
+      logError(
+        'SentryEcosystemMixin::_cacheSentryData: Cannot cache Sentry data',
+        exception: e,
+        stackTrace: st,
+      );
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@lib/features/mailbox_dashboard/presentation/mixin/sentry_ecosystem_mixin.dart`
around lines 57 - 59, The catch block in SentryEcosystemMixin::_cacheSentryData
only logs the error object `e`; change the catch to capture the stack trace
(catch (e, st)) and include the stack (`st`) in the call to logWarning so the
warning message contains both the error and its stack trace for diagnosis.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/features/caching/manager/sentry_configuration_cache_manager.dart`:
- Around line 47-50: The clearSentryConfiguration method currently stops if
_configurationCacheClient.clearAllData() throws, leaving _userCacheClient data
uncleared; update clearSentryConfiguration to attempt both clears independently
by wrapping each call to _configurationCacheClient.clearAllData() and
_userCacheClient.clearAllData() in their own try/catch blocks so the second
clear always runs, capture any thrown errors (or error messages) and after both
attempts either log the failures via the existing logger/Sentry utilities or
rethrow an aggregated error so callers know the operation failed while ensuring
no partial cache cleanup occurs.

In `@lib/features/push_notification/presentation/services/fcm_receiver.dart`:
- Around line 9-12: The background message handler currently calls
FcmService.instance.initialStreamController(),
FcmMessageController.instance.initialize(), await
FcmMessageController.instance.initialAppConfig(), and await
FcmMessageController.instance.setUpSentryConfiguration() on every message;
change this to run expensive DI/cache/Sentry setup only once per isolate by
adding a one-time async init gate (e.g., a static Future<void>? or boolean +
Future) inside the FcmMessageController (or the top-level handler) that ensures
initialAppConfig() and setUpSentryConfiguration() are awaited only on the first
invocation while still calling lightweight initialization like
initialStreamController()/initialize() per message as needed; reference
FcmMessageController.instance.initialAppConfig and
FcmMessageController.instance.setUpSentryConfiguration as the methods guarded by
the gate.
- Around line 61-65: The token dedupe check uses a stale `token` variable so
repeated identical refresh events still pass; update the baseline after handling
or re-read the current token before comparing. In the
`FirebaseMessaging.instance.onTokenRefresh.listen` handler (and/or in the
surrounding initializer that defines `token`), after calling
`FcmService.instance.handleToken(newToken)` set the stored `token` to `newToken`
(or fetch the latest token from FirebaseMessaging and compare against that) so
subsequent refresh events are deduplicated correctly.

---

Nitpick comments:
In
`@lib/features/mailbox_dashboard/presentation/mixin/sentry_ecosystem_mixin.dart`:
- Around line 57-59: The catch block in SentryEcosystemMixin::_cacheSentryData
only logs the error object `e`; change the catch to capture the stack trace
(catch (e, st)) and include the stack (`st`) in the call to logWarning so the
warning message contains both the error and its stack trace for diagnosis.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 24e0574d-89a2-47ee-b8e7-4fbc30ecc436

📥 Commits

Reviewing files that changed from the base of the PR and between f596b0c and 1609fcb.

📒 Files selected for processing (18)
  • core/lib/utils/sentry/sentry_config.dart
  • lib/features/caching/caching_manager.dart
  • lib/features/caching/clients/sentry_configuration_cache_client.dart
  • lib/features/caching/clients/sentry_user_cache_client.dart
  • lib/features/caching/config/hive_cache_config.dart
  • lib/features/caching/entries/sentry_configuration_cache.dart
  • lib/features/caching/entries/sentry_user_cache.dart
  • lib/features/caching/exceptions/local_storage_exception.dart
  • lib/features/caching/extensions/sentry_cache_extensions.dart
  • lib/features/caching/manager/sentry_configuration_cache_manager.dart
  • lib/features/caching/utils/caching_constants.dart
  • lib/features/mailbox_dashboard/presentation/extensions/ai_scribe/setup_scribe_prompt_url_extension.dart
  • lib/features/mailbox_dashboard/presentation/mixin/sentry_ecosystem_mixin.dart
  • lib/features/push_notification/presentation/controller/fcm_message_controller.dart
  • lib/features/push_notification/presentation/listener/email_change_listener.dart
  • lib/features/push_notification/presentation/services/fcm_receiver.dart
  • lib/features/push_notification/presentation/services/fcm_service.dart
  • lib/main/bindings/local/local_bindings.dart
✅ Files skipped from review due to trivial changes (6)
  • lib/features/caching/config/hive_cache_config.dart
  • lib/features/caching/clients/sentry_configuration_cache_client.dart
  • lib/features/caching/clients/sentry_user_cache_client.dart
  • lib/features/caching/entries/sentry_user_cache.dart
  • lib/features/caching/utils/caching_constants.dart
  • lib/features/push_notification/presentation/listener/email_change_listener.dart
🚧 Files skipped from review as they are similar to previous changes (3)
  • lib/features/caching/caching_manager.dart
  • lib/features/caching/entries/sentry_configuration_cache.dart
  • lib/features/push_notification/presentation/controller/fcm_message_controller.dart

…tialization

Signed-off-by: dab246 <tdvu@linagora.com>
codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (1)
lib/features/caching/manager/sentry_configuration_cache_manager.dart (1)

48-59: Add local error logging for user-cache clear failure path.

At Line 58, a thrown error currently bubbles up without a local logError(..., stackTrace: ...), which makes cleanup failures harder to diagnose in production. Mirror the guarded logging pattern used for configuration clear.

🔧 Proposed minimal change
   Future<void> clearSentryConfiguration() async {
     try {
       await _configurationCacheClient.clearAllData();
     } catch (e, st) {
       logError(
         'SentryConfigurationCacheManager::clearSentryConfiguration: Failed to clear config cache',
         exception: e,
         stackTrace: st,
       );
     }
-    await _userCacheClient.clearAllData();
+    try {
+      await _userCacheClient.clearAllData();
+    } catch (e, st) {
+      logError(
+        'SentryConfigurationCacheManager::clearSentryConfiguration: Failed to clear user cache',
+        exception: e,
+        stackTrace: st,
+      );
+      rethrow;
+    }
   }

Based on learnings, SentryManager.instance.setUser() intentionally carries account/user/email identifiers, so user-cache clear failures should be explicitly diagnosable.

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

In `@lib/features/caching/manager/sentry_configuration_cache_manager.dart` around
lines 48 - 59, The clearSentryConfiguration method currently catches and logs
failures for _configurationCacheClient.clearAllData but not for
_userCacheClient.clearAllData, so any exception from _userCacheClient will
bubble without local diagnostics; wrap the await _userCacheClient.clearAllData()
call in its own try/catch and call logError with a descriptive message (e.g.,
'SentryConfigurationCacheManager::clearSentryConfiguration: Failed to clear user
cache'), passing exception: e and stackTrace: st to mirror the existing logging
pattern used for the configuration clear.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/features/push_notification/presentation/services/fcm_receiver.dart`:
- Around line 13-29: The current _backgroundInitCompleter/Completer pattern
should be replaced with a lazy-initialized Future that wraps the initialization
sequence (FcmService.instance.initialStreamController(),
FcmMessageController.instance.initialize(),
FcmMessageController.instance.initialAppConfig(),
FcmMessageController.instance.setUpSentryConfiguration()) so errors are
propagated to the original caller and consistently logged via the same logError
path; add a configurable timeout around the combined Future (e.g.,
timeoutDuration) so a hung initialAppConfig() or setUpSentryConfiguration() will
throw and allow recovery, and ensure on timeout or error the cached Future is
cleared so subsequent calls retry (i.e., reset the stored future to null on
failure) rather than leaving isolates blocked.

---

Nitpick comments:
In `@lib/features/caching/manager/sentry_configuration_cache_manager.dart`:
- Around line 48-59: The clearSentryConfiguration method currently catches and
logs failures for _configurationCacheClient.clearAllData but not for
_userCacheClient.clearAllData, so any exception from _userCacheClient will
bubble without local diagnostics; wrap the await _userCacheClient.clearAllData()
call in its own try/catch and call logError with a descriptive message (e.g.,
'SentryConfigurationCacheManager::clearSentryConfiguration: Failed to clear user
cache'), passing exception: e and stackTrace: st to mirror the existing logging
pattern used for the configuration clear.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 927dec63-3ae0-427f-8952-8959a2e60d1c

📥 Commits

Reviewing files that changed from the base of the PR and between 1609fcb and 376a8ea.

📒 Files selected for processing (3)
  • lib/features/caching/manager/sentry_configuration_cache_manager.dart
  • lib/features/mailbox_dashboard/presentation/mixin/sentry_ecosystem_mixin.dart
  • lib/features/push_notification/presentation/services/fcm_receiver.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/features/mailbox_dashboard/presentation/mixin/sentry_ecosystem_mixin.dart

… re-initialization

Signed-off-by: dab246 <tdvu@linagora.com>
Copy link
Copy Markdown

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

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

Code Health Improved (3 files improve in Code Health)

Gates Passed
3 Quality Gates Passed

See analysis details in CodeScene

View Improvements
File Code Health Impact Categories Improved
sentry_config.dart 9.69 → 10.00 Complex Conditional
fcm_message_controller.dart 8.82 → 10.00 Code Duplication, Complex Conditional
email_change_listener.dart 8.21 → 10.00 Complex Method, Complex Conditional

Quality Gate Profile: The Bare Minimum
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.

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.

2 participants