critical priority low complexity backend pending backend specialist Tier 1

Acceptance Criteria

Builder method `buildMentorConfirmationPayload` exists on the notification payload builder class and is reachable from the FCM dispatcher
Title and body strings are sourced from the organisation's localisation map; fallback to default Norwegian strings when a key is missing
Expected return date is interpolated into the body string using the assignment's `expected_return_date` field; if the field is null the body substitutes a configurable 'no date set' phrase
Body string is truncated to 178 characters before the deep-link suffix, preserving whole words, to stay within FCM visible-body limits
Notification data map includes `type: 'pause_confirmation'`, `assignment_id`, `peer_mentor_id`, and `deep_link_path` pointing to the pause status card screen
Organisation terminology substitution replaces generic tokens (e.g. `{peer_mentor_label}`) with the organisation's configured label for peer mentors
Method is pure (no side-effects) and returns a typed `NotificationPayload` value object
Builder does not call Supabase or FCM directly — all data is passed in as parameters
Method throws an `ArgumentError` if `peer_mentor_id` or `assignment_id` is null or empty

Technical Requirements

frameworks
Flutter
Dart
apis
Firebase Cloud Messaging (FCM) API v1
data models
assignment
contact
performance requirements
Method must complete synchronously in under 1 ms — no async I/O permitted
String interpolation must not allocate more than one intermediate buffer
security requirements
No PII (name, date-of-birth, etc.) included in FCM notification data map beyond the deep-link IDs
Payload must not include raw personnummer or contact email
Organisation label substitution must sanitise input to prevent injection into notification strings

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Model this builder as a static method or a thin value-object factory on an existing `PauseNotificationPayloadBuilder` class (created in task-011 for the coordinator payload). Accept a `PausedAssignment` record DTO, an `OrganisationLabels` map, and an optional `expectedReturnDate` parameter. Re-use the character-truncation helper already written for the coordinator payload (task-011) — do not duplicate it. The deep-link path format should match the router convention used elsewhere in the codebase (e.g.

`/pause-status/:assignmentId`). Keep the localisation key names consistent with the coordinator payload keys to simplify translation file maintenance.

Testing Requirements

Unit tests in flutter_test cover: (1) happy-path payload shape with all fields populated, (2) null `expected_return_date` substitution, (3) body truncation at exactly 178 characters preserving whole words, (4) organisation terminology substitution for at least two organisation label variants, (5) `ArgumentError` thrown on null/empty `peer_mentor_id`, (6) `ArgumentError` thrown on null/empty `assignment_id`. No integration or widget tests required for this isolated builder method.

Component
Pause Notification Payload Builder
service low
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.