Skip to content

Conversation

@fulleni
Copy link
Member

@fulleni fulleni commented Nov 8, 2025

Status

READY

Description

This pull request introduces a robust and extensible push notification system, designed to enhance user engagement through timely and personalized alerts. It establishes a multi-provider architecture, initially supporting Firebase FCM and OneSignal, with dynamic configuration managed via RemoteConfig. Key features include editorial-driven breaking news alerts and the foundational elements for user-defined notification subscriptions, all backed by new database structures, access controls, and service integrations.

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🛠️ Bug fix (non-breaking change which fixes an issue)
  • ❌ Breaking change (fix or feature that would cause existing functionality to change)
  • 🧹 Code refactor
  • ✅ Build configuration change
  • 📝 Documentation
  • 🗑️ Chore

- Update core dependency in pubspec.yaml and pubspec.lock
- Change ref from e7c808c9d459233196e2eac3137a9c87d3976af3 to abd044bc891c562a2758ce85f9b3893e982a554a
- Add Firebase project credentials (project ID, client email, private key)
- Include OneSignal app ID and REST API key
- These variables are required for implementing push notification functionality
- Implement a new database migration to add the 'isBreaking' field to existing Headline documents
- Set default value to false for documents where the field is missing
- Ensure schema consistency for the introduction of breaking news feature
- Log the number of modified documents during the migration process
- Note: Downward migration is not supported for this change
- Import new migration file for adding isBreaking field to headlines
- Add migration to the allMigrations list
- Define a new abstract interface for push notification clients
- Specify the contract for sending push notifications through different providers
- Include method for sending notifications with device token, payload, and provider config
- Implement FirebasePushNotificationClient class
- Add sendNotification method to handle FCM message sending
- Include error handling and logging for various scenarios
- Ensure compatibility with existing IPushNotificationClient interface
Add OneSignalPushNotificationClient, a concrete implementation of
IPushNotificationClient for sending notifications via the OneSignal REST API.

- Implement sendNotification method to construct and send HTTP requests
- Include support for logging and error handling
- Require HttpClient with AuthInterceptor for API requests
- Support for optional image URL in notification payload
- Add IPushNotificationService abstract class
- Implement DefaultPushNotificationService
- Integrate with various data repositories for user subscriptions, device tokens, and remote config
- Support multiple push notification providers (Firebase, OneSignal)
- Handle breaking news notifications with configurable settings
- Add new permission constant 'push_notification.send_breaking_news'
- This permission allows sending breaking news push notifications
- Typically granted to roles like 'publisher' or 'admin' in the dashboard
- Add Permissions.pushNotificationSendBreakingNews to _dashboardPublisherPermissions set
- Allow dashboard publishers to send breaking news notifications
- Add getters for Firebase Project ID, Client Email, and Private Key
- Add getters for OneSignal App ID and REST API Key
- All new methods will throw a StateError if the required environment variable is not set
- Add PushNotificationService and related repositories to the middleware
- Include DataRepository for PushNotificationDevice and PushNotificationSubscription
- Provide IPushNotificationService for dependency injection
…astructure

- Add push notification device and subscription repositories
- Implement Firebase and OneSignal push notification clients
- Create push notification service interface and default implementation
- Update app dependencies to include new push notification components
- Initialize HTTP clients for push notification providers
- Implement push notification for breaking headlines
- Integrate IPushNotificationService to send breaking news notifications
- Add error handling for notification sending process
… field

- Replace exists('isBreaking').not() with notExists('isBreaking') for better readability
- Improve performance and code clarity in the updateMany query
…neSignal

- Add dart_jsonwebtoken dependency for JWT handling
- Implement Firebase token provider using service account credentials
- Set up OneSignal token provider using REST API key
- Update HTTP client initialization for both providers
Update the method to read the correct environment variable name `ONESIGNAL_REST_API_KEY` instead of the previously incorrect `ONESIGNAL_API_KEY`.
- Add success log after triggering breaking news notification
- Improve code comments for better understanding of the notification process
- Implement subscription limit logic for premium, standard, and guest users
- Add notification subscription limit calculation based on remote config
- Update followed item limit logic to handle specific item types
- Refactor constructor formatting for better readability
- Add unique index on 'token' field for 'push_notification_devices' collection
- Add index on 'userId' field for 'push_notification_subscriptions' collection
- These indexes improve data integrity and query performance for push notification operations
- Introduce new method `sendBulkNotifications` to IPushNotificationClient
- Enhance efficiency for sending notifications to multiple devices
- Maintain consistency in method parameters with existing `sendNotification`
…h batch support

- Add sendBulkNotifications method for sending to multiple devices
- Implement chunking for batches larger than 500 tokens
- Use FCM v1 batch endpoint for efficient bulk sending
- Refactor existing sendNotification to delegate to new bulk method
- Update logging and error handling for bulk operations
- Add sendBulkNotifications method to OneSignalPushNotificationClient
- Delegate single notification sending to bulk method
- Implement batching for handling large numbers of device tokens
- Add error handling for non-HttpExceptions
- Update logging for batch processing
- Improve method documentation and comments
…very

- Refactor device lookup to use a single bulk query instead of per-user queries
- Group devices by provider and dispatch notifications in bulk
- Use environment variables for push notification provider configs
- Improve logging and error handling
- Optimize subscription filtering query
- Add comprehensive information about dynamic and personalized notifications
- Include details on editorial-driven alerts, user-crafted notification streams, and flexible delivery mechanisms
- Highlight provider-agnostic design and support for Firebase (FCM) and OneSignal
- Emphasize the advantage of enhanced user engagement and web dashboard management
- Replace the total notification subscription limit check with per-delivery-type limit enforcement.
- Simplify the limit assignment logic using ternary operators.
- Enhance code readability by adopting a more concise style.
- Remove unused notificationSubscriptionLimit variables.
- Remove userRepository from AppDependencies and DefaultPushNotificationService
- This change simplifies the push notification service by removing an unused dependency
- Removed the null check for pushConfig as it is not needed.
- This change simplifies the code structure and improves readability.
- Added notificationSubscriptions: const [] to the user seed data
- This ensures that new users created through database seeding have an empty notificationSubscriptions array by default
…lient

- Add Firebase token provider to create and exchange JWT for access token
- Introduce reusable HttpClient instance for token exchange
- Update OneSignal client initialization
@fulleni
Copy link
Member Author

fulleni commented Nov 8, 2025

/gemini review

Copy link

@gemini-code-assist gemini-code-assist 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 Review

This pull request introduces a comprehensive and well-architected push notification system. The multi-provider approach with support for Firebase and OneSignal, controlled via remote configuration, is excellent and provides great flexibility. The implementation of breaking news alerts is robust, using a "fire-and-forget" pattern to avoid blocking API responses, which is a great design choice. The new database migrations, indexes, and RBAC permissions are all well-implemented and support the new functionality effectively.

However, I found a critical configuration error in the app_dependencies.dart file where the HttpClient for OneSignal was incorrectly configured with Firebase credentials and endpoints. This would prevent the OneSignal provider from functioning. I've left a detailed comment with a suggested fix for this issue.

Overall, this is a fantastic feature addition. Once the configuration issue is resolved, this will be a solid and scalable notification system.

@fulleni
Copy link
Member Author

fulleni commented Nov 8, 2025

/gemini review

Copy link

@gemini-code-assist gemini-code-assist 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 Review

This is a well-executed and comprehensive implementation of a multi-provider push notification system. The architecture is robust, featuring a clear separation of concerns with interfaces for notification clients and a central service to orchestrate the logic. The database schema, migrations, and indexing are well-designed for performance and data integrity. Security is also well-handled, with correct permission setup and specific checks for user-owned resources. The use of "fire-and-forget" for sending notifications is a great choice for API responsiveness. I have a couple of suggestions for improvement regarding code structure and error handling in the Firebase client.

… function

- Extracted Firebase access token retrieval logic into a separate private function
- Improved code readability and maintainability
- Reused the extracted function in the firebaseHttpClient initialization
…gging for batch sending

- Enhance logging to capture individual failures within a batch
- Refine error messages to better reflect partial failures
- Ensure all futures complete before processing results, even in case of errors
- Introduce more granular error handling for HTTP and unexpected exceptions
@fulleni
Copy link
Member Author

fulleni commented Nov 8, 2025

/gemini review

Copy link

@gemini-code-assist gemini-code-assist 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 Review

This pull request introduces a comprehensive push notification system with a multi-provider architecture supporting Firebase and OneSignal. The changes are extensive, including new database models, services for sending notifications, dependency injection setup, and RBAC permissions. The implementation is robust, with good abstractions and handling of asynchronous operations. I've identified a critical compilation error in the user preference limit service due to missing break statements in a switch block. I've also provided suggestions to improve maintainability by extracting complex logic from the dependency setup and to enhance error reporting in the Firebase client for better debuggability.

Extracts the Firebase JWT signing and token exchange logic from `app_dependencies.dart` into a new, dedicated `FirebaseAuthenticator` class.

This refactoring improves separation of concerns, enhances readability of the dependency setup, and makes the authentication flow testable in isolation.
Refactors `app_dependencies.dart` to use the new `FirebaseAuthenticator` service for obtaining Firebase access tokens.

This change removes the inline token generation logic, instantiates the new service, and provides it to the `firebaseHttpClient`. This improves separation of concerns and makes the dependency setup more readable and maintainable.
Updates the root middleware to provide the `IFirebaseAuthenticator` service to the request context. This makes the service available for injection throughout the application.
@fulleni
Copy link
Member Author

fulleni commented Nov 8, 2025

/gemini review

Copy link

@gemini-code-assist gemini-code-assist 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 Review

This is an excellent and comprehensive pull request that introduces a robust, multi-provider push notification system. The architecture is well-designed, with clear separation of concerns using interfaces for different notification clients (IPushNotificationClient) and a dedicated service (DefaultPushNotificationService) to orchestrate the logic. The use of RemoteConfig to dynamically switch providers is a great feature for flexibility. The database changes, including new collections, indexes, and migrations, are well-implemented and idempotent. The security considerations, such as RBAC for sending notifications and ownership checks for device registration, are also solid. I have a few minor suggestions for improving readability and noting a design trade-off for future scalability, but overall, this is a very high-quality contribution.

Modify `EnvironmentConfig` to allow missing push notification credentials. The getters now return `null` instead of throwing an error, allowing the application to start even if push notifications are not configured.
…lization

- Add null safety to firebaseAuthenticator and push notification clients
- Initialize FirebasePushNotificationClient only if credentials are present
- Initialize OneSignalPushNotificationClient only if credentials are present
- Move push notification client initialization before repository initialization
- Log appropriate messages for initialized and disabled push notification clients
Updates `DefaultPushNotificationService` to accept nullable `IPushNotificationClient` instances.

This change makes the service resilient to missing push notification credentials. It now checks if the configured primary provider's client was initialized before attempting to send a notification, logging a severe error and aborting if the client is unavailable. This fixes the compilation errors in `app_dependencies.dart`.
- Change REQUIRED to CONDITIONALLY REQUIRED for Firebase and OneSignal variables
- Add clarification that the server will start without these variables
- Emphasize the importance of these variables for their respective notification services
Adds a null-assertion operator to `firebasePrivateKey` within the `FirebaseAuthenticator`. This is safe as the authenticator is only created when all Firebase credentials are confirmed to be non-null, resolving the compile-time error.
Updates the root middleware to correctly provide the nullable `IFirebaseAuthenticator?` type, resolving a compile-time error. Also sorts the import directives to fix a lint warning.
@fulleni
Copy link
Member Author

fulleni commented Nov 8, 2025

/gemini review

Copy link

@gemini-code-assist gemini-code-assist 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 Review

This pull request introduces a comprehensive and well-architected push notification system with support for Firebase and OneSignal. The changes include new database collections, migrations, provider-specific clients, and an orchestrating service. The implementation demonstrates strong attention to performance, security, and robustness, with features like fire-and-forget notification dispatching and conditional dependency injection. My review identified one high-severity issue where empty environment variables could lead to runtime errors and one medium-severity issue regarding an incomplete database migration rollback. Overall, this is an excellent contribution that adds significant new functionality to the application.

@fulleni
Copy link
Member Author

fulleni commented Nov 8, 2025

/gemini summary

@gemini-code-assist
Copy link

Summary of Changes

This pull request delivers a robust and extensible push notification system aimed at significantly boosting user engagement through timely and personalized alerts. It establishes a multi-provider architecture, initially supporting Firebase FCM and OneSignal, with dynamic configuration capabilities managed via RemoteConfig. The system enables editorial-driven breaking news alerts and lays the groundwork for user-defined notification subscriptions, all supported by new database structures, refined access controls, and integrated services.

Highlights

  • Multi-Provider Notification Engine: A new, comprehensive push notification system has been integrated, offering out-of-the-box support for Firebase Cloud Messaging (FCM) and OneSignal, designed for flexible and provider-agnostic operation.
  • Breaking News Alerts: Functionality to dispatch immediate, high-priority "breaking news" alerts to subscribed users when a headline is created and marked as breaking.
  • User Device & Subscription Management: New mechanisms and endpoints are introduced for users to register and unregister their push notification devices, alongside foundational elements for user-defined notification subscriptions based on content filters.
  • Dynamic Configuration: Push notification settings, including the primary provider and delivery type configurations, are now managed dynamically via RemoteConfig, allowing for remote adjustments without code deployments.
  • Database & Access Control Updates: Database schema enhancements include a new isBreaking field for headlines and a pushNotificationConfig for RemoteConfig. Role-Based Access Control (RBAC) has been updated with new permissions for sending breaking news and managing user devices.
  • Subscription Limit Enforcement: The user preference limit service has been extended to include checks for notification subscriptions, ensuring adherence to account-type specific limits for various delivery types.
Changelog
  • .env.example
    • Added new environment variables for configuring Firebase (project ID, client email, private key) and OneSignal (app ID, REST API key) credentials.
  • README.md
    • Updated documentation to include a new section detailing the "Dynamic & Personalized Notifications" feature, outlining its capabilities and benefits.
  • lib/src/config/app_dependencies.dart
    • Integrated new push notification services and clients, including conditional initialization of Firebase and OneSignal clients based on environment variables.
    • Declared new data repositories for notification devices and subscriptions.
    • Initialized DefaultPushNotificationService with the new repositories and clients.
  • lib/src/config/environment_config.dart
    • Enhanced environment variable handling to treat empty strings as missing values.
    • Added new static getters for Firebase and OneSignal credentials.
  • lib/src/database/migrations/20251107000000_add_is_breaking_to_headlines.dart
    • Introduced a new database migration to add an isBreaking boolean field to existing Headline documents, defaulting to false.
  • lib/src/database/migrations/20251108103300_add_push_notification_config_to_remote_config.dart
    • Added a migration to ensure the remote_configs document contains a default pushNotificationConfig structure.
  • lib/src/database/migrations/all_migrations.dart
    • Updated the list of all database migrations to include the newly added AddIsBreakingToHeadlines and AddPushNotificationConfigToRemoteConfig migrations.
  • lib/src/rbac/permissions.dart
    • Defined new permissions for managing push notifications, specifically for sending breaking news and for users to manage their own notification devices.
  • lib/src/rbac/role_permissions.dart
    • Assigned the new push notification device management permissions to guest users.
    • Assigned the breaking news sending permission to dashboard publishers.
  • lib/src/registry/data_operation_registry.dart
    • Modified the headline creation process to trigger a breaking news notification if applicable, using unawaited for fire-and-forget.
    • Added custom creation/deletion logic for push notification devices with ownership checks.
  • lib/src/registry/model_registry.dart
    • Registered the push_notification_device model with specific access permissions, allowing authenticated users to create and delete their own device registrations.
  • lib/src/services/auth_service.dart
    • Updated user preference initialization to include an empty list for notificationSubscriptions.
  • lib/src/services/database_seeding_service.dart
    • Added new MongoDB indexes for push_notification_devices and push_notification_subscriptions collections to optimize queries and ensure data integrity.
  • lib/src/services/default_user_preference_limit_service.dart
    • Refactored preference limit checks for clarity.
    • Introduced new logic to enforce subscription limits based on user roles and delivery types.
  • lib/src/services/firebase_authenticator.dart
    • Added a new service responsible for authenticating with Firebase and obtaining OAuth2 access tokens for FCM.
  • lib/src/services/firebase_push_notification_client.dart
    • Implemented a client for sending push notifications via Firebase Cloud Messaging (FCM), supporting bulk sends and handling batching.
  • lib/src/services/onesignal_push_notification_client.dart
    • Implemented a client for sending push notifications via the OneSignal REST API, including bulk sending capabilities.
  • lib/src/services/push_notification_client.dart
    • Introduced an abstract interface IPushNotificationClient for generic push notification sending, enabling provider-agnostic implementation.
  • lib/src/services/push_notification_service.dart
    • Created the core IPushNotificationService and its default implementation to orchestrate the entire push notification process, from fetching configurations to dispatching messages.
  • pubspec.lock
    • Updated dependency lock file to reflect changes in core and http_client packages.
  • pubspec.yaml
    • Updated version references for core and http_client dependencies.
  • routes/_middleware.dart
    • Extended the application's middleware to provide access to the newly introduced push notification repositories and services.
Activity
  • gemini-code-assist[bot] provided an initial summary of the pull request.
  • fulleni requested multiple /gemini review commands.
  • fulleni requested a /gemini summary command.
  • gemini-code-assist[bot] provided review comments on lib/src/config/app_dependencies.dart regarding tokenClient reuse and OneSignal HttpClient configuration.
  • gemini-code-assist[bot] provided a critical review comment on lib/src/services/firebase_push_notification_client.dart about error handling in _sendBatch.
  • gemini-code-assist[bot] provided a medium priority review comment on lib/src/config/app_dependencies.dart suggesting extracting Firebase token generation logic into a separate class.
  • gemini-code-assist[bot] provided a critical review comment on lib/src/services/default_user_preference_limit_service.dart about missing break; statements and readability of ternary operators.
  • gemini-code-assist[bot] provided a medium priority review comment on lib/src/services/default_user_preference_limit_service.dart suggesting refactoring nested ternary operators for clarity.
  • gemini-code-assist[bot] provided a medium priority review comment on lib/src/services/firebase_push_notification_client.dart discussing trade-offs of parallel individual requests versus batch endpoints.
  • gemini-code-assist[bot] provided a high priority review comment on lib/src/config/environment_config.dart suggesting _getEnv should return null for empty environment variables.
  • gemini-code-assist[bot] provided a medium priority review comment on lib/src/database/migrations/20251107000000_add_is_breaking_to_headlines.dart suggesting implementing a true down migration.
  • gemini-code-assist[bot] provided a medium priority review comment on lib/src/services/firebase_push_notification_client.dart suggesting enhancing OperationFailedException with more details.

Updates the `_getEnv` helper to return `null` if an environment variable is found but is an empty string. This makes the configuration handling more robust by preventing services from being initialized with invalid empty credentials, which would cause runtime failures.
@fulleni fulleni merged commit 7f69079 into main Nov 8, 2025
1 check failed
@fulleni fulleni deleted the feat/integrate-with-notification-service-provider branch November 8, 2025 14:47
@github-project-automation github-project-automation bot moved this from Backlog to Done in Flutter News App Project Nov 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

feat: Integrate with Notification Service Provider

2 participants