Define notification payload models and constraints
epic-pause-status-notifications-foundation-task-010 — Define Dart payload models for coordinator and peer mentor pause notification recipients. Establish character constraints (title ≤ 65 chars, body ≤ 240 chars), localisation key contracts, and recipient type enum distinguishing coordinator vs peer mentor payloads.
Acceptance Criteria
Technical Requirements
Implementation Notes
Use Dart 3 sealed classes so callers are forced to handle both coordinator and peerMentor cases exhaustively in switch expressions. Define the character limit constants as static const at the class level (not as magic numbers in validation logic) so they can be referenced in tests and in UI validation layers without duplication. Implement PayloadValidationException as a custom exception class with a field violatedField (String) and actualLength (int) so callers can produce user-facing error messages without string parsing. The toFcmPayloadMap() method should produce the FCM data payload format (not the notification object format) so the app can handle display logic client-side — this is important for WCAG 2.2 AA compliance where notification display may need to be customised.
Use const constructors on enum and on models where all fields can be const.
Testing Requirements
Unit tests using flutter_test. Required test cases: (1) valid CoordinatorPausePayload constructed successfully, (2) title exceeding 65 chars throws PayloadValidationException, (3) body exceeding 240 chars throws PayloadValidationException, (4) toFcmPayloadMap() returns correct keys and values for each subclass, (5) fromJson round-trips correctly for both subclasses, (6) recipientType is serialised correctly in FCM map. All tests are pure (no async, no network).
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.
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.
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.