Manual trigger support for Sync Scheduler
epic-external-system-integration-configuration-backend-infrastructure-task-009 — Add manual trigger capability to the Sync Scheduler allowing coordinators and admins to initiate an integration sync outside the scheduled window. Expose a Supabase RPC function trigger_integration_sync(org_id, integration_type) that validates the caller's permissions, checks that no active run is already in progress for the integration, and invokes the same job trigger engine used by the scheduled path.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 4 - 323 tasks
Can start after Tier 3 completes
Handles integration between different epics or system components. Requires coordination across multiple development streams.
Implementation Notes
Implement the RPC as a SQL SECURITY DEFINER function in a migration file. The function should: (1) call auth.uid() and auth.jwt() to get caller identity — never trust function parameters for security checks; (2) join users/roles table to verify coordinator/admin role for the org; (3) check sync_run_log for active runs using EXISTS query; (4) check rate limit with SELECT COUNT(*) WHERE triggered_at > NOW() - INTERVAL '5 minutes'; (5) insert pending sync_run_log row with triggered_by = 'manual'; (6) invoke the Integration Edge Function asynchronously via pg_net.http_post() or return the run_id and let the caller poll. On the Flutter side, implement a SyncSchedulerRepository with a triggerManualSync method wrapping supabase.rpc(). Wire into a Riverpod AsyncNotifier.
The SyncStatusBanner should subscribe to Supabase Realtime changes on sync_run_log filtered by run_id to show real-time status updates without polling.
Testing Requirements
Unit tests (Dart flutter_test): (1) Riverpod provider calls supabase.rpc with correct params; (2) 'sync_already_in_progress' error surfaced as AsyncError with user-facing message; (3) successful return populates run_id state. Unit tests (Deno, RPC logic extracted to TS helper): (1) coordinator role allowed; (2) viewer role rejected; (3) cross-org org_id rejected; (4) rate limit: second trigger within 5 min rejected; (5) unknown integration_type rejected. Integration test: invoke RPC via Supabase local dev as coordinator user, assert sync_run_log row created with status 'pending', triggered_by = 'manual', triggered_by_user_id set. Widget test: ManualSyncButton shows CircularProgressIndicator while AsyncValue is loading.
Supabase Edge Functions have cold start latency that can cause the first sync invocation after idle periods to fail or timeout when the external API has a short connection window, leading to missed scheduled syncs that go undetected.
Mitigation & Contingency
Mitigation: Configure Edge Function memory and implement a warm-up ping mechanism before heavy sync invocations. Set generous timeout values on the external API calls. Log all cold-start incidents for monitoring.
Contingency: If cold starts cause consistent sync failures, migrate the sync scheduler to a persistent Supabase cron job that pre-warms the function 30 seconds before the scheduled sync time.
The sync scheduler must execute jobs at predictable times for financial reporting accuracy. Drift in cron execution timing (due to Supabase infrastructure delays) could cause syncs to run at wrong times, leading to missing data in accounting exports or duplicate exports across reporting periods.
Mitigation & Contingency
Mitigation: Implement idempotency keys based on integration ID + scheduled period, so re-runs of a delayed sync cannot create duplicate exports. Log actual execution timestamps vs scheduled timestamps and alert on drift exceeding 5 minutes.
Contingency: If scheduler reliability is insufficient, integrate with a dedicated cron service (e.g., pg_cron on Supabase) for millisecond-precise scheduling, replacing the application-level scheduler.
Aggressive health monitoring ping frequency could trigger rate limiting on external APIs (especially Xledger and Dynamics), causing legitimate export calls to fail after the monitor exhausts the API's request quota.
Mitigation & Contingency
Mitigation: Use lightweight health check endpoints (HEAD requests or vendor-specific ping/status endpoints) rather than data requests. Set health check frequency to once per 15 minutes minimum. Implement exponential backoff after consecutive failures.
Contingency: If rate limiting occurs, disable active health monitoring for the affected integration type and switch to passive health detection (mark unhealthy only when a scheduled sync fails).