high priority medium complexity backend pending backend specialist Tier 4

Acceptance Criteria

SummaryShareService.share(destination, animationCompleteStream) method exists and is callable from BLoC layer
Method awaits an animation-complete signal before proceeding to capture — premature calls must not produce a screenshot
Screenshot capture returns a non-null Uint8List of at least 1 KB; if null or empty, ShareResult.failure is returned with a user-facing error message
Platform detection correctly identifies iOS vs Android at runtime with no hard-coded platform assumptions
On iOS: photos_library permission is requested before gallery save; if denied, a settings-redirect dialog is presented and ShareResult.permissionDenied is returned
On Android: WRITE_EXTERNAL_STORAGE (API ≤ 29) or MediaStore API (API 30+) path is used; share sheet is invoked with image/png MIME type
Clipboard destination copies raw PNG bytes and triggers a brief confirmation SnackBar or Toast visible for at least 2 seconds
System share sheet destination opens the native share sheet with the screenshot file attached
ShareResult contains: success (bool), destination (enum), userMessage (String), and optional errorCode (String?)
A Riverpod AsyncNotifier<ShareResult?> exposes sharing state; BLoC observes this notifier and emits corresponding UI states
All error paths (permission denied, capture failed, share sheet dismissed) are handled gracefully with no unhandled exceptions
Service is injectable via Riverpod and testable via constructor injection of its collaborators

Technical Requirements

frameworks
Flutter
Riverpod
BLoC
apis
platform_channel (permission APIs)
MediaStore API (Android 30+)
PHPhotoLibrary (iOS)
Clipboard API
data models
ShareResult
ShareDestination (enum)
AnimationCompleteSignal
performance requirements
Share workflow must complete within 3 seconds on mid-range devices after animation-complete signal
Screenshot capture must not block the UI thread — use compute() or Isolate if encoding exceeds 16 ms
security requirements
Screenshot must not include any sensitive personal data fields (e.g., personnummer, contact names) unless explicitly permitted by privacy settings
Temporary image files written to disk must be stored in the app cache directory, not public storage, and deleted after share completes
Permission requests must follow platform guidelines — no double-requesting after permanent denial

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Use a StreamSubscription on the animationCompleteStream with a timeout (e.g., 5 s) to avoid hanging indefinitely. Wrap all platform channel calls in try/catch with PlatformException handling. Define ShareDestination as a sealed class or enum with values: gallery, clipboard, shareSheet. The Riverpod AsyncNotifier should use state = AsyncLoading() at the start of share() and AsyncData(result) or AsyncError on completion — this lets the BLoC watch(ref) without polling.

For iOS gallery save use image_gallery_saver or equivalent plugin; for Android share sheet use share_plus. Do not store business logic in the notifier — keep it as a thin state bridge. Ensure the service follows the interface defined in task-011 so the BLoC depends on the abstraction, not the concrete class.

Testing Requirements

Integration tests cover the six platform flow scenarios listed in task-016. Unit tests (flutter_test) must cover: (1) share() called before animation-complete signal returns ShareResult.notReady, (2) null screenshot bytes returns ShareResult.failure, (3) each ShareDestination enum value routes to the correct internal method, (4) ShareResult fields are populated correctly for both success and failure paths. Mock all platform channels and permission APIs using Mockito or manual fakes. Target 85%+ branch coverage on SummaryShareService.

Component
Summary Share Service
service medium
Epic Risks (3)
high impact medium prob integration

Activity records may contain duplicate entries (as evidenced by the duplicate-detection feature dependency) or proxy-registered activities that should be attributed differently. Including duplicates or mis-attributed records would produce inflated stats, undermining trust in the summary.

Mitigation & Contingency

Mitigation: Implement the aggregation query to join against the deduplication-reviewed-flag on activity records and filter out unresolved duplicates. Coordinate with the duplicate-detection feature team to confirm the authoritative flag field before implementing the RPC. Include a data-quality warning in the summary when unresolved duplicates are detected.

Contingency: If deduplication state is unreliable at release time, add a prominent disclaimer in the summary UI noting that figures reflect all registered activities and may include duplicates pending review. Track a follow-up task to re-aggregate after deduplication runs.

medium impact high prob scope

Each organisation wants to define their own milestone thresholds (e.g., NHF's counting model differs from HLF's certification model). Implementing configurable thresholds may expand scope significantly if the configuration UI is expected in this epic.

Mitigation & Contingency

Mitigation: Scope this epic strictly to the evaluation engine and a hardcoded default threshold set. Define the MilestoneDefinition interface with an organisation_id discriminator so per-org configs can be loaded from the database in a later sprint. Build the admin configuration UI as a separate follow-on task outside this epic.

Contingency: If stakeholders require per-org milestone configuration before launch, deliver a JSON-based configuration file per org as an interim solution, loaded from Supabase storage, until a full admin UI is built.

medium impact medium prob technical

Android 13+ restricts access to media collections and requires READ_MEDIA_IMAGES permission for gallery saves, while older Android versions use WRITE_EXTERNAL_STORAGE. Handling both permission models correctly across the device matrix is error-prone.

Mitigation & Contingency

Mitigation: Use the permission_handler Flutter package with version-aware permission requests abstracted behind the summary-share-service interface. Write platform-specific unit tests for both Android API levels in the test harness. Test on a minimum of three Android versions (API 29, 32, 34) in CI.

Contingency: If gallery save is broken on specific Android versions at launch, disable the 'Save to gallery' option on affected API levels and surface only clipboard and system share sheet, which require no media permissions.