high priority medium complexity frontend pending frontend specialist Tier 3

Acceptance Criteria

On successful submission, a confirmation bottom sheet or modal appears with the message 'Report saved' (Norwegian: 'Rapporten er lagret') and a primary CTA to return to the previous screen.
The confirmation UI is announced as a live region to VoiceOver (iOS) and TalkBack (Android) using Semantics(liveRegion: true) so screen reader users hear 'Report submitted' without needing to navigate to the element.
After the user dismisses the confirmation, the app navigates back to the exact screen that initiated navigation to the report screen (activity detail or home), using GoRouter's pop or a named back route — no navigation stack leaks.
On submission failure, the bottom sheet or inline error message uses plain Norwegian and English language: 'Could not save the report. Please check your connection and try again.' — no raw error codes or Supabase exception messages are shown.
The retry button in the error state re-triggers the submission event from the orchestrator BLoC without requiring the user to re-fill the form.
If the user dismisses the error state without retrying, the form remains fully populated and editable so no data is lost.
The back navigation after confirmation correctly handles both entry points: from activity detail (pops to activity detail) and from home (pops to home tab).
Widget test verifies that Semantics(liveRegion: true) is present on the confirmation message node in the widget tree.

Technical Requirements

frameworks
Flutter
BLoC
data models
activity
performance requirements
Confirmation bottom sheet must appear within one frame (16ms) of receiving the success event from the BLoC — no artificial delays
security requirements
Error messages must never expose Supabase PostgrestException details, HTTP status codes, or database field names to the user
Confirmation bottom sheet must not display any personal data from the submitted report — only a generic success message
ui components
SubmissionConfirmationBottomSheet — success state with 'Report saved' message and back CTA
SubmissionErrorWidget — inline or bottom sheet error with plain-language message and retry button
Semantics(liveRegion: true) wrapper — wraps the confirmation message for screen reader announcement

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Handle success/error navigation purely via BlocListener — never inside a button onPressed handler. Use a sealed SubmissionState class with SubmissionSuccess, SubmissionError, and SubmissionRetrying variants. For the live region, wrap only the confirmation message Text widget in Semantics(liveRegion: true, child: ...) — do not wrap the entire bottom sheet as this causes unwanted announcements for all child elements. For back navigation, pass a returnRoute or backAction callback via the screen's constructor (or route extra) from the calling screen; the confirmation sheet invokes this callback on dismiss.

Map all PostgrestException codes to a small set of user-facing strings in a dedicated ErrorMessageMapper utility — never interpolate raw exception messages into the UI string. Norwegian Bokmål localisation strings must be added to the app's l10n ARB files for 'report_saved' and 'report_save_failed_retry' keys.

Testing Requirements

Widget tests (flutter_test): BlocListener triggers showModalBottomSheet when BLoC emits submissionSuccess state; confirmation bottom sheet contains Semantics node with liveRegion=true; tapping 'Back' on confirmation calls Navigator.pop or GoRouter.pop; error widget is shown when BLoC emits submissionError; retry button dispatches RetrySubmissionEvent to BLoC; form fields remain populated after error dismissal. BLoC unit tests: submissionSuccess event emitted after mock Supabase returns success; submissionError event emitted with user-friendly message on PostgrestException. Integration test: full submission success flow on Supabase test instance ends at correct previous screen.

Component
Post-Session Report Screen
ui high
Epic Risks (2)
medium impact high prob technical

End-to-end integration tests that span Flutter UI → Supabase → RLS → storage are inherently flaky in CI due to network timing, test database state, and Supabase cold-start latency. Flaky tests erode confidence and slow the release pipeline.

Mitigation & Contingency

Mitigation: Use a dedicated Supabase test project with seeded org and user fixtures. Wrap all E2E tests in retry logic with a fixed seed and tear-down hooks. Keep E2E tests in a separate test suite that runs on-demand rather than on every PR, with unit and widget tests as the primary CI gate.

Contingency: If E2E tests remain unreliable, replace the Supabase calls in integration tests with a verified fake (in-memory repository implementations) and promote the real Supabase tests to a nightly scheduled run rather than blocking PR merges.

high impact medium prob security

Health status, course interest, and assistive device fields contain personal health data. If any logger, analytics event, or crash reporter captures field values — through automated error serialisation or developer-added debug logs — the feature could violate GDPR and Blindeforbundet's data processor agreement.

Mitigation & Contingency

Mitigation: Audit all log statements in the report feature's code paths before the epic is marked done. Apply a PII-safe logging wrapper that strips field values from any serialised form state before it reaches the logger. Add a CI lint rule that flags direct logger calls within report-related files.

Contingency: If PII is found in logs post-launch, immediately disable the affected logging call and rotate any credentials that were exposed. Notify the data protection officer and document the incident per GDPR Article 33 requirements.