critical priority low complexity infrastructure pending backend specialist Tier 0

Acceptance Criteria

Abstract FcmNotificationDispatcher interface is defined with methods: dispatch(NotificationPayload payload) and dispatchToToken(String fcmToken, NotificationPayload payload)
NotificationPayload Dart class is defined with fields: title (String), body (String), data (Map<String, String>), channel (NotificationChannel enum: push/inApp), recipientId (String)
NotificationChannel enum covers: push (FCM push to device), inApp (Supabase Realtime in-app event)
FcmDispatcherConfig class is defined with fields: maxRetryAttempts (int, default 3), backoffIntervalSeconds (int, default 5), tokenValidationEnabled (bool, default true)
FcmTokenValidator abstract interface is defined with method: isValid(String fcmToken) returning bool
Channel selection logic is documented: push channel used when coordinator has a valid FCM token; inApp channel used as fallback or when coordinator has no FCM token
All interfaces and config models are in lib/features/pause_status/domain/fcm/ with no Flutter or Supabase imports (pure Dart)
Code compiles without warnings via flutter analyze

Technical Requirements

frameworks
Flutter
Dart
apis
FCM HTTP v1 API (interface contract only — no implementation here)
data models
NotificationPayload
FcmDispatcherConfig
NotificationChannel
performance requirements
Config model must support runtime override of retry parameters to allow per-environment tuning without a code change
security requirements
FCM tokens are treated as sensitive credentials — the dispatcher interface must not log token values
NotificationPayload.data map must not carry PII — enforce via documentation contract on the interface

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

This task is intentionally limited to interface and config definition — no FCM SDK imports or HTTP calls. The concrete FcmNotificationDispatcherImpl will be built in a later task and injected via Riverpod. Define the FcmDispatcherConfig as a const-constructible class so it can be provided as a compile-time constant in tests. The channel selection rule (push → fallback inApp) should be encoded as a static method on FcmDispatcherConfig or as a standalone ChannelSelector class for testability.

Align the NotificationPayload.data map key names with whatever the FCM notification handler on the Flutter client expects — coordinate with the frontend team on the payload contract before finalising field names.

Testing Requirements

Unit tests for config models: (1) FcmDispatcherConfig uses correct defaults when constructed without arguments. (2) FcmDispatcherConfig.copyWith overrides only the specified field. (3) NotificationPayload fromJson/toJson round-trip preserves all fields. (4) NotificationChannel enum covers all expected string values used by the concrete implementation.

No mocking required for this task — pure model and interface tests only. Tests located at test/features/pause_status/domain/fcm/.

Component
FCM Notification Dispatcher
infrastructure medium
Epic Risks (3)
high impact medium prob integration

The org membership table structure used to resolve coordinator relationships may differ from what the repository assumes, causing incorrect coordinator lookup or missing rows for mentors in multi-chapter scenarios.

Mitigation & Contingency

Mitigation: Review the existing org membership table schema and RLS policies before writing repository queries. Align query logic with the patterns already used by peer-mentor-status-repository and multi-chapter-membership-service.

Contingency: If schema differs, add an adapter layer in the repository that normalises the membership resolution and document the discrepancy for the data team. Fall back to coordinator lookup via the feature's own stored coordinator_id field if org membership join fails.

high impact medium prob technical

Device tokens stored in the database may be stale or unregistered, causing FCM dispatch failures that silently drop coordinator notifications — the primary coordination safeguard of this feature.

Mitigation & Contingency

Mitigation: Implement token validation on every dispatch call and handle FCM's NOT_REGISTERED error by flagging the token as invalid in the database. Reuse the token refresh pattern already established by fcm-token-manager.

Contingency: If push delivery fails after retry, ensure the in-app notification record is always written regardless of push outcome so coordinators can still see the event in the notification centre.

medium impact low prob technical

The optional reason field may contain special characters, emoji, or non-Latin scripts that exceed the 200-character byte limit when FCM encodes the payload, causing delivery failures.

Mitigation & Contingency

Mitigation: Enforce the 200-character limit on Unicode code point count, not byte count, in the payload builder. Add a unit test with multi-byte input strings.

Contingency: If an oversized payload is detected at dispatch time, strip the reason field from the push notification body and note 'See in-app notification for full reason' to preserve delivery.