critical priority high complexity integration pending integration specialist Tier 0

Acceptance Criteria

HLFWebsiteSyncService class is implemented in Dart with a clearly defined interface exposing removeMentor(mentorId) and restoreMentor(mentorId) methods
Internal peer mentor UUID is reliably mapped to the corresponding Dynamics portal contact record ID before any API call is made; mapping failure throws a typed MentorMappingException
removeMentor() correctly calls the Dynamics portal API endpoint to delist the mentor from the HLF public chapter website listing
restoreMentor() correctly calls the Dynamics portal API endpoint to re-list the mentor on the HLF public chapter website listing
4xx client errors (400, 403, 404, 409) are distinguished from 5xx server errors; 4xx errors are not retried and surface a non-retryable SyncClientException
5xx server errors and network timeouts trigger exponential backoff retry with configurable max attempts (default 3) and base delay (default 2 seconds)
Jitter is applied to backoff intervals to prevent thundering herd on the Dynamics API
All Azure AD OAuth2 token acquisition and refresh is delegated to 395-dynamics-portal-client; HLFWebsiteSyncService never handles raw credentials
Service is implemented as a Supabase Edge Function (Deno/TypeScript) callable server-side only — no Azure AD credentials are bundled in the Flutter app binary
Unit tests cover: successful remove flow, successful restore flow, mentor ID not found in mapping, 403 non-retryable path, 503 retryable path with backoff assertion
Integration smoke test verifies end-to-end call reaches the mocked Dynamics endpoint and parses the response correctly

Technical Requirements

frameworks
Flutter (Dart client caller)
Supabase Edge Functions (Deno runtime for server-side execution)
BLoC (state management for any UI status reflection)
apis
Microsoft Dynamics 365 REST API (via 395-dynamics-portal-client)
Supabase Edge Functions REST invocation from Flutter client
Supabase PostgreSQL for mentor-to-Dynamics ID mapping table
data models
assignment
certification
contact
performance requirements
Single sync operation (remove or restore) must complete within 10 seconds under normal Dynamics API latency
Backoff retry sequence must not exceed 60 seconds total wall-clock time before final failure
ID mapping lookup must complete within 100ms (indexed database query)
security requirements
Azure AD credentials for Dynamics 365 stored server-side only in Edge Function environment secrets — never in Flutter app or Supabase database
OAuth2 access tokens obtained by 395-dynamics-portal-client are ephemeral and never persisted to database
All Dynamics API calls transmitted over TLS 1.2+
Edge Function validates JWT claims (organisation = HLF) before executing any sync operation
Mentor personal data (name, contact details) must not appear in Edge Function logs — log only mentor UUID and operation type

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

This service must be implemented as a Supabase Edge Function, not a Flutter-side service, because Azure AD credentials must never leave the server. The Flutter app calls the Edge Function via Supabase Functions SDK. The Edge Function in turn uses 395-dynamics-portal-client (a Deno module) to call Dynamics. The mentor ID mapping (internal UUID → Dynamics contact record ID) should be stored in a dedicated Supabase table populated during the HLF onboarding sync — query this table at sync time rather than doing a live Dynamics search.

Use exponential backoff pattern: delay = baseDelay * 2^(attempt-1) + random jitter(0..500ms). Distinguish retryable errors (5xx, network timeout, ECONNRESET) from non-retryable errors (400 bad request, 403 forbidden, 404 not found) — retrying 4xx errors wastes quota and masks bugs. Consider using a typed Result return type instead of throwing exceptions to make error handling explicit at call sites.

Testing Requirements

Unit tests (flutter_test + mockito): mock 395-dynamics-portal-client to return success, 4xx, and 5xx scenarios; assert correct method calls, correct exception types thrown, correct retry counts. Integration tests: deploy Edge Function to Supabase test project, use a WireMock or similar HTTP mock server to simulate Dynamics portal responses; assert request payloads match expected Dynamics API contract; assert mentor ID mapping resolves correctly. Test coverage target: 90% on HLFWebsiteSyncService core logic. All tests must be runnable in CI without real Dynamics credentials.

Component
HLF Website Sync Service
service high
Epic Risks (4)
high impact medium prob technical

The nightly expiry checker may run multiple times due to scheduler retries or infrastructure issues, causing duplicate auto-transitions and duplicate coordinator notifications that erode trust in the notification system.

Mitigation & Contingency

Mitigation: Implement idempotency via a unique constraint on (mentor_id, threshold_day, certification_expiry_date) in the cert_expiry_reminders table. Auto-transitions should be wrapped in a Postgres RPC that checks current status before applying, making repeated invocations safe.

Contingency: Add a compensation query in the reconciliation log that detects duplicate log entries for the same certification period and alerts the operations team for manual review within 24 hours.

high impact medium prob integration

The HLF Dynamics portal API may have eventual-consistency behaviour or rate limits that cause website listing updates to lag behind status changes, leaving expired mentors visible on the public website for an unacceptable window.

Mitigation & Contingency

Mitigation: Design the sync service to be triggered immediately on status transitions (event-driven via database webhook) in addition to the nightly batch run. Implement a reconciliation job that verifies sync state against app state and re-triggers any divergent records.

Contingency: If real-time sync cannot be guaranteed, implement a manual 'force sync' action in the coordinator dashboard so coordinators can trigger an immediate re-sync for urgent cases. Document the expected sync lag in coordinator onboarding materials.

medium impact medium prob scope

Stakeholder requests to extend the expiry checker to handle additional certification types, grace periods, or organisation-specific threshold configurations may significantly increase scope beyond what is designed here, delaying delivery.

Mitigation & Contingency

Mitigation: Parameterise threshold day values (30, 14, 7) via configuration repository rather than hard-coding them, enabling per-organisation customisation without code changes. Document that grace period logic and additional cert types are out of scope for this epic and require a dedicated follow-up.

Contingency: Deliver the feature with hard-coded HLF-standard thresholds first and introduce the configuration repository as a follow-up task in the next sprint, using a feature flag to enable per-org threshold overrides.

high impact low prob security

Dynamics portal API credentials stored as environment secrets in Supabase Edge Function configuration may be rotated or invalidated by HLF IT without notice, causing silent sync failures that go undetected for multiple days.

Mitigation & Contingency

Mitigation: Implement credential health-check calls on each scheduler run and emit an immediate alert on auth failure rather than only alerting after N consecutive failures. Document the credential rotation procedure with HLF IT and establish a rotation notification protocol.

Contingency: Maintain a break-glass manual sync script accessible to HLF administrators that can re-execute the Dynamics sync with newly provided credentials while the automated system is restored.