high priority medium complexity backend pending backend specialist Tier 5

Acceptance Criteria

Push notification is dispatched to the driver's registered FCM token within 5 seconds of the declaration upload completion event
Notification title is: '<org_name>: New Declaration Requires Your Signature'
Notification body is: '<declaration_title> — tap to review and acknowledge'
Notification data payload includes: { type: 'DECLARATION', declaration_id: '<uuid>', deep_link: 'app://declarations/<uuid>/acknowledge' }
If the driver has no registered FCM token, the dispatch is skipped and a WARN log entry is written — no error is thrown upstream
If FCM returns a token-not-registered error, the stale token is removed from the driver profile and no retry is attempted
Notification dispatch is triggered via Supabase Database Webhook or Postgres trigger on declarations table INSERT event
The notification service function is idempotent: re-triggering for the same declaration_id within 60 seconds does not send a duplicate push
FCM API key is stored as a Supabase secret (environment variable), never hardcoded

Technical Requirements

frameworks
Supabase Edge Functions (Deno)
Firebase Cloud Messaging REST API v1
Flutter (handles incoming FCM message and routes deep link to AcknowledgementScreen via GoRouter)
apis
FCM HTTP v1 API: POST https://fcm.googleapis.com/v1/projects/{project_id}/messages:send
Supabase Database Webhook → Edge Function trigger on declarations table INSERT
data models
Declaration (id, title, org_id, driver_id, status)
DriverProfile (id, fcm_token)
Organisation (id, name)
performance requirements
FCM dispatch must complete within 3 seconds (FCM SLA)
Edge Function must not block the declaration upload response — trigger asynchronously via webhook
security requirements
FCM service account credentials stored in Supabase Vault, accessed via Deno.env — never in code
Deep link must use the app's registered custom scheme to prevent open-redirect abuse
Notification body must never include sensitive personal information (address, medical data) — only declaration title and org name
ui components
AcknowledgementScreen (Flutter) must be registered as deep-link target for app://declarations/:id/acknowledge

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Use FCM HTTP v1 (not legacy) — it requires OAuth2 access tokens generated from the service account JSON. Cache the access token in memory for the Edge Function instance lifetime (1 hour expiry) to avoid re-fetching on every call. Idempotency: store dispatched declaration_ids in a `notification_dispatch_log` table with a unique constraint on (declaration_id, notification_type) — skip dispatch if row already exists. On the Flutter side, use `firebase_messaging` package; handle both foreground (show in-app banner) and background (system tray) messages.

Deep link routing must work even when the app is terminated (cold start from notification tap).

Testing Requirements

Unit tests (Deno test): (1) notification payload is constructed correctly from declaration + org + driver data; (2) missing FCM token skips dispatch without throwing; (3) FCM 404 token-not-registered response triggers token cleanup. Integration test against local Supabase: insert a declarations row and verify the Edge Function is invoked and a mock FCM endpoint receives the correct payload. Flutter widget test: verify that receiving a FCM data message with type=DECLARATION navigates to the correct AcknowledgementScreen.

Epic Risks (4)
high impact medium prob security

Org-scoped encryption key management is complex. If keys are not correctly isolated per organization, a breach in one org's key could expose another org's declarations. Additionally, key rotation is not specified but may be needed for compliance, and the current implementation may not support it.

Mitigation & Contingency

Mitigation: Use Supabase Vault or a dedicated secrets management approach for org-scoped key storage. Define the key derivation strategy (per-org master key) in a security design document reviewed before implementation begins. Include key isolation tests in the test suite.

Contingency: If a full per-org key management system cannot be safely implemented within the sprint, fall back to a single platform-level encryption key with strict RLS isolation as a temporary measure, flagging the key rotation gap as a security debt item with a defined resolution milestone.

medium impact medium prob integration

Push notification delivery to drivers depends on FCM token availability and device connectivity. If a driver has not granted notification permissions or has an expired FCM token, the declaration delivery notification will silently fail, leaving the coordinator unaware and the declaration unacknowledged.

Mitigation & Contingency

Mitigation: Implement delivery status tracking in declaration-notification-service. Fall back to in-app notification and SMS (if configured) when push delivery fails. Expose delivery failure status in the declaration status badge so coordinators can identify and manually follow up.

Contingency: If push delivery proves unreliable, implement a polling-based in-app notification fallback where drivers see pending declarations on next app open, ensuring the workflow can complete even without push notifications.

medium impact medium prob technical

The acknowledgement service is meant to validate that the driver has fully scrolled through the declaration before confirming. Implementing reliable scroll completion detection in Flutter across different screen sizes and font sizes is technically non-trivial and could be bypassed.

Mitigation & Contingency

Mitigation: Implement scroll position tracking using ScrollController with a threshold (e.g., 95% of content height reached) and record the validated state server-side before allowing acknowledgement submission. Document the approach in the legal sign-off checkpoint noted in the feature documentation.

Contingency: If reliable scroll detection cannot be implemented within the sprint, add a mandatory reading delay timer (e.g., estimated reading time based on word count) as an alternative validation mechanism, pending legal review of the approach.

medium impact low prob dependency

The driver assignment service must coordinate with the threshold-based expense approval workflow for fees above configured thresholds. If the expense approval workflow interface changes or is not yet stable, the integration point could break or produce incorrect routing behavior.

Mitigation & Contingency

Mitigation: Define a clear interface contract between driver-assignment-service and the expense approval workflow before implementation. Use dependency injection so the expense workflow client can be mocked in tests. Monitor the expense approval feature for interface changes.

Contingency: If the expense approval workflow interface is not stable, implement a direct database insert to the expense records table as a temporary bypass, with a flag indicating manual review is needed, until the stable interface is available.