high priority low complexity backend pending backend specialist Tier 4

Acceptance Criteria

When the user taps Cancel, the bottom sheet is dismissed and the activity wizard is shown with all previously entered fields intact
No database write or update occurs on the Cancel path
The draft object in memory is discarded after cancel — not retained in any cache or local storage
The wizard's current step is preserved on cancel — user is returned to the same wizard step they submitted from, not to step 1
BLoC emits DuplicateResolutionCancelled state, which triggers a navigator pop of the bottom sheet and no-op on the wizard
Cancel action completes synchronously — no loading indicator or async operation is needed
The wizard's submit button is re-enabled after cancel so the user can attempt resubmission after corrections
Cancellation does not re-trigger a duplicate check immediately — the user must manually tap Submit again after making changes
Back-gesture on the bottom sheet (swipe down) behaves identically to tapping Cancel

Technical Requirements

frameworks
Flutter
BLoC
data models
activity
performance requirements
Cancel action and sheet dismissal must complete within one frame (16ms) — fully synchronous
security requirements
Ensure no partial draft data is written to Supabase before or during the cancel path — verify no async operations are in-flight when cancel is called
ui components
Cancel button
Bottom sheet dismiss animation
Wizard submit button re-enabled state

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

The cancel path is intentionally simple — resist the temptation to add analytics, confirmations, or async operations. Implement cancel() on DuplicateResolutionHandler as a synchronous method that emits DuplicateResolutionCancelled. In the wizard BLoC, handle this event by resetting the submission state (isSubmitting = false) without clearing form field state. Use a Completer (same pattern as proceed/merge) so the wizard awaits the user's resolution choice — cancel simply completes the completer with DuplicateResolution.cancel.

Ensure the bottom sheet's onClosing callback and the Cancel button both route to the same handler to prevent divergent behavior on swipe vs. tap.

Testing Requirements

Write unit tests for DuplicateResolutionHandler.cancel() verifying: (1) DuplicateResolutionCancelled state is emitted; (2) no repository method is called; (3) wizard BLoC state retains all form field values after cancel. Write widget tests: (4) bottom sheet is no longer in the widget tree after cancel; (5) wizard form fields display the original values. Verify swipe-down dismiss triggers the same cancel handler via WillPopScope or onDismissed callback.

Component
Duplicate Resolution Handler
service medium
Epic Risks (3)
high impact medium prob technical

The merge resolution path requires identifying which fields from the draft differ from the existing record, applying those differences to the existing record, and cancelling the draft — all as an atomic operation. Partial failures (e.g., update succeeds but draft cancellation fails) could leave the system in an inconsistent state.

Mitigation & Contingency

Mitigation: Implement the merge path as a Supabase RPC transaction that updates the existing record and soft-deletes the draft in a single atomic call. The DuplicateResolutionHandler should never attempt field-level merge at the application layer.

Contingency: If the atomic RPC approach proves too complex for the initial release, simplify the merge path to: mark existing record as the canonical record and cancel the new submission without field merging, displaying a message to the user to manually verify the existing record's fields. Log a follow-up ticket for full field-merge in a later sprint.

medium impact medium prob integration

The DuplicateWarningBottomSheet must intercept the activity wizard's save action without disrupting the wizard's existing navigation stack. If the bottom sheet is implemented as a separate route rather than an overlay, back navigation could break the wizard's step state.

Mitigation & Contingency

Mitigation: Use a `showModalBottomSheet` overlay pattern so the bottom sheet sits above the wizard route without pushing a new route onto the Navigator stack. The wizard's CuBit/BLoC retains all draft state while the sheet is visible. Test this integration with the existing activity-registration-cubit before merging.

Contingency: If the overlay approach causes Z-order or focus issues with the wizard's keyboard-aware layout, route the duplicate check result back to the wizard as a state event (DuplicateDetected), and let the wizard render a local inline warning banner instead of a bottom sheet.

medium impact medium prob technical

The bottom sheet and comparison panel involve complex layouts with multiple interactive elements. Screen reader users (particularly relevant for Blindeforbundet) may struggle with the side-by-side comparison layout if semantics are not carefully ordered.

Mitigation & Contingency

Mitigation: Design the comparison panel with a single-column semantic order (read record A fully, then record B fully) regardless of visual layout. Use Flutter's `Semantics` widget with `sortKey` to enforce correct traversal order. Test with TalkBack and VoiceOver against the WCAG 2.2 AA reading order criteria.

Contingency: If side-by-side layout cannot achieve acceptable screen reader ordering, switch to a stacked tab layout (Tab A / Tab B) for the comparison panel that is semantically simple even if less visually immediate for sighted users.