critical priority low complexity backend pending backend specialist Tier 2

Acceptance Criteria

Incoming request body is parsed as JSON and validated against the Zod SupabaseWebhookPayload schema from task-001
Zod validation failures return HTTP 400 with a JSON body containing a human-readable 'error' field and a 'details' array of Zod issues
Non-UPDATE events (INSERT, DELETE) are detected and return HTTP 200 with a JSON body indicating the event was acknowledged but skipped (idempotent no-op)
Validated payload exposes mentorId (from record.id), oldStatus (from old_record.status), and newStatus (from record.status) as a typed ValidatedWebhookContext object
Null old_record on UPDATE events returns HTTP 400 (should not happen for peer_mentor_profiles updates but must be handled)
HMAC signature verification (if used by Supabase) is performed before Zod parsing to fail fast on invalid requests
All error responses follow a consistent JSON shape: { error: string, code: string }
Validation logic is extracted into a pure function validateWebhookPayload(body: unknown): Result<ValidatedWebhookContext, ValidationError> for unit testability

Technical Requirements

frameworks
Deno
Zod
Supabase Edge Functions
apis
Supabase Database Webhooks
data models
SupabaseWebhookPayload
ValidatedWebhookContext
peer_mentor_profiles
performance requirements
Validation must complete synchronously in under 2ms
security requirements
Never log raw webhook payload bodies — they may contain PII (peer mentor personal data)
Log only mentor ID and transition type for audit purposes
Reject payloads exceeding a maximum body size (e.g. 64KB) to prevent DoS

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use a Result pattern (either a simple { ok: true, value: T } | { ok: false, error: E } discriminated union or a library like neverthrow) rather than throwing exceptions inside the validation function. This keeps the function pure and easy to test. The safeParse() method on the Zod schema returns a discriminated union natively — use that rather than try/catch around parse(). Extract mentorId, oldStatus, newStatus into a ValidatedWebhookContext type immediately after parsing so downstream code never touches the raw payload.

Log { mentorId, transition: 'pause'|'resume' } at INFO level for observability.

Testing Requirements

Unit tests for validateWebhookPayload() covering: (1) valid UPDATE payload with active→paused returns ValidatedWebhookContext, (2) valid UPDATE payload with paused→active returns ValidatedWebhookContext, (3) INSERT payload returns skip result, (4) DELETE payload returns skip result, (5) missing record.status field returns ValidationError, (6) null old_record on UPDATE returns ValidationError, (7) unknown status value fails Zod enum check. Integration test: POST malformed JSON to running function → 400. All tests use Deno test runner.

Component
Pause Status Webhook Handler
infrastructure low
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.