Implement dual-recipient payload building
epic-pause-status-notifications-backend-pipeline-task-007 — Implement the payload construction step in the orchestrator that builds notification payloads for both recipients: the coordinator (assignment redistribution alert) and the peer mentor (confirmation of pause or resume). Integrate with the pause notification payload builder to produce correctly structured FCM and in-app payloads for each audience and transition direction.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Implement as two pure functions: `buildCoordinatorPayload(transition, mentorProfile, coordinatorResolution)` and `buildMentorPayload(transition, mentorProfile)`. Both return a `DualPayload` interface: `{ fcm: FcmPayload | null; inApp: InAppNotificationRecord }`. Keep the builder stateless and free of I/O — this makes it trivially testable. Define string templates as constants at the top of the file to enable easy localization later.
The FCM payload data object keys must match the Flutter app's notification router expectations — coordinate with the frontend team on key names (e.g., `notification_type`, `entity_id`, `screen_route`). For the PAUSE direction, the coordinator FCM body should use the mentor's first_name only (never full name in push payload) to minimize PII in transit logs.
Testing Requirements
Unit tests (pure functions, no mocks needed): (a) PAUSE transition produces correct coordinator and mentor payloads with expected title/body strings, (b) RESUME transition produces correct strings for both recipients, (c) not_found coordinator resolution produces null coordinator payload, (d) in-app record structure has all required fields with correct types, (e) FCM data object contains notification_type and entity_id. Snapshot tests for payload shapes to catch regressions. Run in Deno test runner.
Supabase Edge Functions have cold start latency that may push coordinator notification delivery beyond the 5-second SLA, particularly during low-traffic periods when the function is not warm.
Mitigation & Contingency
Mitigation: Keep the Edge Function lightweight — delegate all heavy logic to the orchestrator layer and avoid large dependency bundles. Measure p95 end-to-end latency in staging and document actual SLA achievable.
Contingency: If cold start latency consistently breaches 5 seconds, introduce a keep-warm ping from the nightly-scheduler or document the actual p95 latency in the feature spec and adjust the acceptance criterion to reflect the realistic bound.
Supabase database webhooks may fire duplicate events for a single status change under retry conditions, causing coordinators to receive multiple identical notifications for one pause event.
Mitigation & Contingency
Mitigation: Add idempotency checking in the webhook handler using the event timestamp and peer mentor ID. Store a notification dispatch record in the pause-status-record-repository and skip dispatch if a record for the same event already exists.
Contingency: If duplicates slip through in production, add a de-duplication filter in the notification centre UI layer so the coordinator sees at most one card per event, and implement a cleanup job for the notifications table.
A peer mentor with multi-chapter membership may have more than one responsible coordinator. The orchestrator design currently targets a single coordinator, and resolving multiple recipients may require schema changes to the org membership query.
Mitigation & Contingency
Mitigation: Review the multi-chapter-membership-service patterns before implementing the orchestrator's coordinator resolution. Design the dispatcher call to accept an array of coordinator IDs from the outset so adding multiple recipients is non-breaking.
Contingency: If multi-coordinator dispatch is out of scope for this epic, document the limitation and create a follow-up task. Default to the primary coordinator (lowest chapter hierarchy level) as the single recipient in the interim.