Implement Way Forward Item Repository
epic-structured-post-session-report-form-engine-task-001 — Create the data layer repository for persisting way-forward items to Supabase. Define the WayForwardItem model with fields for action description, assignee, due date, priority, and status. Implement CRUD operations with RLS policies ensuring coordinators can read items created by their peer mentors.
Acceptance Criteria
Technical Requirements
Implementation Notes
Follow the existing repository pattern in the codebase — implement an abstract WayForwardItemRepository interface and a SupabaseWayForwardItemRepository concrete class to allow swapping in a fake for tests. Use freezed with @freezed annotation for WayForwardItem and generate copyWith, toJson, fromJson via build_runner. The status and priority fields should use Dart enums with a toJson() that serialises to the string values matching the Postgres enum — add a fromJson factory. Store updated_at as a server-side default (DEFAULT now()) and use a trigger (moddatetime extension) to auto-update it.
The Blindeforbundet formalisert rapportstruktur includes a 'veien videre' (way forward) section — this repository directly supports that feature, so ensure action_description supports multi-line text (text type, not varchar).
Testing Requirements
Write unit tests using a mock SupabaseClient (mockito or fake implementation) covering: create() returns a WayForwardItem with generated id; readById() returns null for unknown id; readByReportId() returns all items for the given report; update() mutates only the provided fields; delete() removes the item. Write a separate integration test (against local Supabase emulator) verifying the RLS policies: peer mentor can read own items, cannot read another mentor's items; coordinator can read all items in their org. Aim for 100% method coverage on the repository class.
Dynamically rendered form fields built from runtime JSON schema are significantly harder to make accessible than statically declared widgets — Flutter's Semantics tree must be correct for every possible field type and every validation state. Failures here block the entire feature for Blindeforbundet's visually impaired peer mentors.
Mitigation & Contingency
Mitigation: Define WCAG 2.2 AA semantics requirements for each field type before implementation and write widget tests using Flutter's SemanticsController for every type. Include a real-device VoiceOver test session in the acceptance gate for this epic before marking it done.
Contingency: If dynamic semantics prove too difficult to get right generically, implement field-type-specific Semantics wrappers (one per supported field type) instead of a single generic renderer, accepting slightly more code duplication in exchange for reliable accessibility.
The report-form-orchestrator must manage a complex state machine — schema loading, draft persistence, per-field validation, submission retries, and error recovery — across multiple async operations. Incorrect state transitions could result in lost user data, double submissions, or UI freezes.
Mitigation & Contingency
Mitigation: Define all Bloc states and events explicitly as sealed classes before writing any logic. Use a state machine diagram reviewed by the team before implementation. Write exhaustive Bloc unit tests covering every state transition, including concurrent events and network interruption mid-submission.
Contingency: If Bloc complexity becomes unmanageable, extract draft persistence into a separate DraftManagerCubit and keep report-form-orchestrator focused solely on the submit workflow. The additional granularity makes each component independently testable.
Organisations may require field types beyond the five currently specified (text, multiline, checkbox group, radio, date). If a new type is discovered during pilot testing, the dynamic-field-renderer must be extended, potentially requiring changes across multiple layers.
Mitigation & Contingency
Mitigation: Design dynamic-field-renderer as a registry of field-type renderers with a clear extension point. Document the pattern for adding a new field type so that it can be done in one file without touching existing renderers.
Contingency: If an unhandled field type is encountered at runtime, dynamic-field-renderer renders a labelled plain-text fallback widget and logs a warning so the missing type is surfaced in monitoring, preventing a crash while making the gap visible.