critical priority medium complexity backend pending backend specialist Tier 3

Acceptance Criteria

For a PAUSE transition, the coordinator receives a payload with title 'Peer mentor paused' and body identifying the mentor (by first name only, no last name in push payload body) and instruction to review assignments.
For a RESUME transition, the coordinator receives a payload with title 'Peer mentor resumed' and body confirming availability restored.
For a PAUSE transition, the peer mentor receives a confirmation payload with title 'Pause confirmed' and body confirming their status is paused.
For a RESUME transition, the peer mentor receives a payload with title 'You are active again' and body confirming reactivation.
Each payload includes an in-app notification record structure with: recipient_user_id, notification_type ('pause_status_change'), entity_type ('assignment'), entity_id (mentor's assignment ID), transition_direction ('paused'|'resumed'), is_read (false), created_at (server timestamp).
Each payload includes an FCM push structure with: title, body, data object containing notification_type and entity_id for deep link routing.
When coordinator resolution returned not_found, coordinator payload is null and the orchestrator skips coordinator dispatch without failing.
Payload builder is invoked with a typed TransitionEvent and CoordinatorResolutionResult — no raw database rows passed to builder.
Payload building completes synchronously (no async I/O) and returns within 10ms.
All string content in payloads is sanitized — no raw user input interpolated without escaping.

Technical Requirements

frameworks
Supabase Edge Functions (Deno)
apis
Firebase Cloud Messaging (FCM) API v1 payload schema
data models
assignment
contact
performance requirements
Payload construction is synchronous CPU-only work — must complete in under 10ms.
No database calls inside payload builder — all required data passed as arguments.
security requirements
FCM data payload must not include full name, personnummer, or any sensitive PII — only UUIDs and transition type.
In-app notification record must not include contact personal details in the notification body field — only display-safe strings.
Payload builder must reject or sanitize any string longer than 256 characters in title/body fields to prevent push notification abuse.

Execution Context

Execution Tier
Tier 3

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.

Component
Pause Notification Orchestrator
service medium
Epic Risks (3)
medium impact medium prob technical

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.

medium impact medium prob technical

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.

medium impact low prob scope

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.