high priority medium complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

Widget renders a scrollable ListView of WayForwardItem cards; empty state shows a descriptive placeholder, not a blank area
Each card displays: action text (truncated to 2 lines with ellipsis), optional assignee chip (hidden if null), and a status badge (open/in-progress/done) using design token colors
Tapping a card opens an Edit bottom sheet pre-populated with the item's current values
A clearly labeled 'Add item' button/FAB opens an Add bottom sheet with an empty form
The Add/Edit bottom sheet contains: a multi-line text field with SpeechToTextFieldOverlay trigger, an optional assignee picker, and a status selector
Submitting the Add/Edit sheet dispatches the appropriate event to the form orchestrator and the sheet closes
Each card has a swipe-to-delete gesture OR a visible remove icon button; a confirmation snackbar with undo is shown after deletion
All interactive elements (card tap, add button, remove button, sheet submit) have minimum 44×44dp touch targets
Every card and action button has a Semantics widget with a descriptive label including the item's action text (e.g., 'Edit way forward item: Follow up with coordinator')
Focus order follows visual top-to-bottom, left-to-right order; focus does not escape the bottom sheet while it is open
Widget reads items from the form orchestrator state (not internal local state) and dispatches mutations via orchestrator events
Widget renders correctly with 0, 1, and 20+ items without overflow or performance issues

Technical Requirements

frameworks
Flutter
BLoC (flutter_bloc)
flutter_test
apis
WayForwardTaskService (via form orchestrator)
SpeechToTextFieldOverlay
data models
WayForwardItem (id, actionText, assigneeId, status)
performance requirements
ListView must use itemBuilder with keys for efficient re-renders when items are added/removed
Bottom sheet open animation must complete in ≤300ms
security requirements
Assignee picker must only show users within the same org_id — never cross-org data
Action text input must be sanitized before dispatching to orchestrator (strip control characters)
ui components
WayForwardItemCard
WayForwardAddEditBottomSheet
SpeechToTextFieldOverlay (from dependency task-009)
StatusBadge
AssigneeChip

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use a stateless widget that reads WayForwardItems from the BlocBuilder listening to the form orchestrator. Keep the bottom sheet as a separate widget class (WayForwardAddEditBottomSheet) with its own local ephemeral state (TextEditingController, selected status) to avoid polluting the orchestrator state with unsaved draft sheet values. Use showModalBottomSheet with isScrollControlled: true and padding for keyboard avoidance. For accessibility, wrap the entire bottom sheet in a FocusScope and restore focus to the triggering element on close.

Status badge colors must come from design tokens — never hardcoded hex. Use AnimatedList or a key-based ListView for smooth add/remove animations.

Testing Requirements

Widget tests using flutter_test. Test: (1) empty state renders placeholder text; (2) list with 3 items renders all 3 cards with correct text/badge; (3) tapping add button opens bottom sheet; (4) submitting add sheet dispatches AddWayForwardItem event to mock orchestrator; (5) swipe-to-delete dispatches RemoveWayForwardItem event and shows snackbar; (6) tapping undo in snackbar dispatches UndoRemoveWayForwardItem; (7) all Semantics labels are present and non-empty (use tester.getSemantics); (8) touch targets verified to be ≥44dp using tester.getSize. Also include a golden test for the card in each status variant (open, in-progress, done).

Component
Way Forward Section Widget
ui medium
Epic Risks (3)
high impact medium prob technical

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.

high impact medium prob technical

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.

medium impact low prob scope

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.