Skip to content

feat(observability): add Firebase Crashlytics with opt-in toggle in settings#32

Merged
using-system merged 17 commits intomainfrom
feat/firebase-crashlytics
Apr 21, 2026
Merged

feat(observability): add Firebase Crashlytics with opt-in toggle in settings#32
using-system merged 17 commits intomainfrom
feat/firebase-crashlytics

Conversation

@using-system
Copy link
Copy Markdown
Owner

@using-system using-system commented Apr 21, 2026

Summary

  • Integrate Firebase Crashlytics SDK (firebase_core, firebase_crashlytics) with Android Gradle plugin configuration
  • Add new Observability settings section (between General and Actions) with a crash reporting on/off toggle (default: off)
  • Firebase initialization wrapped in try-catch so the app runs normally on platforms without Firebase config (iOS)
  • Full i18n support across all 4 locales (en, fr, de, es)
  • 11 unit/widget tests covering storage, toggle tile, and section

Test plan

  • Verify toggle defaults to off on fresh install
  • Toggle on → check setCrashlyticsCollectionEnabled(true) called
  • Toggle off → persists across app restart
  • Force a crash with toggle on → verify crash appears in Firebase Console
  • Run on iOS without GoogleService-Info.plist → app launches normally, toggle has no effect
  • flutter test test/features/observability/ → 11 tests pass
  • flutter analyze → no new issues

🤖 Generated with Claude Code

using-system and others added 15 commits April 21, 2026 11:16
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…mport

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…and section

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 21, 2026 09:36
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds opt-in Firebase Crashlytics integration to the app, exposing a new “Observability” settings section with a crash reporting toggle and persisting the preference via SharedPreferences.

Changes:

  • Add Firebase Crashlytics + Firebase Core dependencies and Android Gradle plugin wiring.
  • Add an Observability settings section with a Crashlytics on/off toggle backed by Riverpod + SharedPreferences.
  • Add i18n strings and unit/widget tests for the new storage and UI.

Reviewed changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pubspec.yaml Adds firebase_core and firebase_crashlytics dependencies.
pubspec.lock Locks Firebase/Crashlytics transitive dependencies.
lib/main.dart Initializes Firebase/Crashlytics at startup and conditionally wraps runApp in a guarded zone.
lib/features/settings/presentation/settings_page.dart Inserts the Observability section between General and Actions.
lib/features/observability/data/crashlytics_preference_storage.dart Implements SharedPreferences read/write for the Crashlytics opt-in boolean.
lib/features/observability/providers.dart Adds Riverpod providers/notifier to read/write preference and call Crashlytics SDK.
lib/features/observability/presentation/crashlytics_toggle_tile.dart Adds the SwitchListTile UI + error snackbar on write failures.
lib/features/observability/presentation/observability_section.dart Groups observability settings tiles for the Settings page.
lib/l10n/app_en.arb Adds EN strings (and metadata) for Observability + Crashlytics toggle.
lib/l10n/app_fr.arb Adds FR strings for Observability + Crashlytics toggle.
lib/l10n/app_de.arb Adds DE strings for Observability + Crashlytics toggle.
lib/l10n/app_es.arb Adds ES strings for Observability + Crashlytics toggle.
android/settings.gradle.kts Adds Google Services + Crashlytics Gradle plugins (pluginManagement).
android/app/build.gradle.kts Applies Google Services + Crashlytics plugins to the Android app module.
android/app/google-services.json Adds Firebase Android config (currently committed).
SPEC.md Documents Crashlytics in the tech stack under Observability.
docs/superpowers/specs/2026-04-21-firebase-crashlytics-design.md Design doc for Crashlytics integration and toggle behavior.
docs/superpowers/plans/2026-04-21-firebase-crashlytics.md Step-by-step implementation plan for the feature.
test/features/observability/data/crashlytics_preference_storage_test.dart Tests for storage default/overwrite/corruption handling.
test/features/observability/presentation/crashlytics_toggle_tile_test.dart Widget tests for toggle UI and persistence.
test/features/observability/presentation/observability_section_test.dart Widget tests ensuring section contains tile and divider.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread android/app/google-services.json
Comment thread lib/main.dart Outdated
Comment thread lib/main.dart Outdated
Comment thread lib/features/observability/providers.dart
using-system and others added 2 commits April 21, 2026 11:41
…one mismatch

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d Crashlytics calls

The catch block now captures and logs the stack trace for easier
diagnosis. The provider guards setCrashlyticsCollectionEnabled behind
Firebase.apps.isNotEmpty so the toggle works as a no-op on platforms
without Firebase config.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 21, 2026 09:44
@using-system using-system merged commit bc2a853 into main Apr 21, 2026
5 checks passed
@using-system using-system deleted the feat/firebase-crashlytics branch April 21, 2026 09:46
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 21 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/main.dart
Comment on lines +42 to +43
(error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The zone error handler calls FirebaseCrashlytics.instance.recordError(...) unconditionally. If Firebase initialization was skipped/failed in the try block (e.g., missing config on iOS), this will likely throw ("no default Firebase app") and can cascade into additional unhandled errors. Guard this call behind a Firebase-initialized check (e.g., Firebase.apps.isNotEmpty) and/or wrap it in a try/catch with a fallback logger so the app remains stable when Firebase is unavailable.

Suggested change
(error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
(error, stack) async {
if (Firebase.apps.isEmpty) {
debugPrint('Unhandled zone error (Firebase unavailable): $error\n$stack');
return;
}
try {
await FirebaseCrashlytics.instance
.recordError(error, stack, fatal: true);
} catch (e, crashlyticsStack) {
debugPrint(
'Failed to report error to Crashlytics: $e\n$crashlyticsStack\n'
'Original error: $error\n$stack',
);
}

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +28
```
lib/features/observability/
├── data/
│ └── observability_storage.dart # SharedPreferences wrapper
├── domain/
│ └── crashlytics_preference.dart # Boolean preference type
├── presentation/
│ ├── observability_section.dart # Section widget for settings page
│ └── crashlytics_toggle_tile.dart # SwitchListTile for Crashlytics
└── providers.dart # Riverpod AsyncNotifier + provider
```
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

This spec’s module file map no longer matches the implemented code: it references observability_storage.dart and a domain/ preference type, but the PR introduces data/crashlytics_preference_storage.dart (and no domain/ layer). Please update the file map to reflect the actual paths/structure so future contributors don’t follow stale guidance.

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +18
## Prerequisites (manual)

The user must place the Firebase config files (these are gitignored and cannot be generated by code):
- `android/app/google-services.json` — download from Firebase Console
- `ios/Runner/GoogleService-Info.plist` — download from Firebase Console

Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

This plan states Firebase config files are gitignored and must be placed manually, but the PR also adds android/app/google-services.json to version control. Either update the plan to match the new approach, or (preferably) keep the config files out of the repo by gitignoring them and removing committed copies.

Copilot uses AI. Check for mistakes.
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