Implement Way Forward Task Service
epic-structured-post-session-report-services-task-006 — Build the service that converts submitted way-forward entries into structured coordinator follow-up tasks. On report submission, iterate way-forward items, persist them via way-forward-item-repository, create coordinator task records with due dates and assignment metadata, and signal the task queue. Implement idempotency to prevent duplicate tasks on retry.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Implement idempotency using a composite unique constraint in Supabase on (report_id, item_index) — the database enforces uniqueness at the insert level, avoiding race conditions from concurrent retries. In the service, use an upsert with onConflict: DoNothing and check affected rows to distinguish insert vs. already-exists. Wrap the full persist + task-queue signal in a Supabase database transaction or a logical transaction in Dart (persist all items first, then signal queue only on full success).
Define a WayForwardTaskCreationResult sealed class (created / alreadyExisted / failed) to give callers precise feedback. Due date calculation should be extracted into a pure function (daysToAdd: int, from: DateTime) → DateTime for easy unit testing. Note: this service is invoked synchronously within the report submission flow — keep it fast. If task queue signalling is slow, consider fire-and-forget with unawaited().
Testing Requirements
Unit tests with flutter_test and mockito covering: (1) successful creation of one coordinator task per way-forward item, (2) idempotency — second call with same report_id returns existing tasks without inserting, (3) repository failure causes full rollback with no partial records, (4) task queue signal is emitted exactly once per new task, (5) due date calculated correctly from submission date + configured offset, (6) coordinator assignment falls back to org default when report has no coordinator_id. Mock way-forward-item-repository and task queue. Validate that no real Supabase calls are made in unit tests. Target 90%+ line coverage.
Flutter's speech_to_text package behaviour differs meaningfully between iOS and Android — microphone permission flows, locale availability, background audio session interference, and partial-result timing all vary. Inconsistent behaviour could make voice input unreliable for the primary audience (visually impaired peer mentors on iOS VoiceOver).
Mitigation & Contingency
Mitigation: Test speech-to-text-adapter on physical iOS and Android devices from the start, not just simulators. Write platform-specific test cases for permission flows and locale detection. Design the adapter's public interface to be platform-agnostic so that a native bridge could replace the package if needed.
Contingency: If speech_to_text proves unreliable on a platform, implement a native-speech-api-bridge (already identified in the component catalogue) as a drop-in replacement within the adapter, keeping the external interface unchanged so no UI code needs to change.
The coordinator task queue notification mechanism is not fully specified. If the queue system is owned by another team or uses an external service, way-forward-task-service may block on an undefined integration contract, delaying this epic.
Mitigation & Contingency
Mitigation: Define the task queue notification interface as an abstract Dart interface early in the epic. Implement a stub that writes a flag to the database so coordinator list queries can detect new tasks, deferring the real notification integration to a later epic.
Contingency: If the queue integration remains undefined at implementation time, ship way-forward-task-service with database persistence only and add a TODO-flagged notification hook. Coordinators will still see items on next page load; push notification delivery is deferred.