critical priority low complexity backend pending backend specialist Tier 1

Acceptance Criteria

AccessibilitySettingsRepository is implemented with a clear abstract interface and a concrete SharedPreferences-backed implementation
Stream<AccessibilitySettings> settings stream emits the current value immediately upon subscription
Stream emits a new value whenever updateSettings() is called
AccessibilitySettings? readSync() returns the last persisted settings synchronously (or null if never saved)
Future<void> updateSettings(AccessibilitySettings) persists settings to SharedPreferences and updates the stream
Settings survive app restart — loading at startup emits the previously persisted value
If no settings exist in storage, stream emits AccessibilitySettings.defaults()
Repository is exposed as a Riverpod StreamProvider<AccessibilitySettings>
Repository can be overridden in tests with a fake implementation via Riverpod's override mechanism
No data loss occurs if updateSettings is called multiple times rapidly (last write wins, stream reflects final state)

Technical Requirements

frameworks
Flutter
Riverpod
apis
SharedPreferences
data models
AccessibilitySettings
performance requirements
Initial settings load must complete within 100ms of app startup
updateSettings() must persist and emit within 50ms under normal conditions
security requirements
SharedPreferences storage key must be namespaced: 'accessibility_settings_v1' to avoid collisions
No user-identifiable information stored in preferences

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Use a StreamController.broadcast() internally. On repository construction, load from SharedPreferences asynchronously and add to the controller — expose a Future initialize() method called during app startup (e.g., in main() before runApp). Store settings as a single JSON string under the namespaced key. Prefer SharedPreferences over Hive to minimize dependencies unless Hive is already in the project.

The abstract interface (AccessibilitySettingsRepository) enables test injection via Riverpod overrides. For the Riverpod provider: use StreamProvider that reads from the repository's stream. The concrete repository instance should be created once (not per provider read) — use a singleton pattern or a top-level provider.

Testing Requirements

Write unit tests using flutter_test with a fake/in-memory implementation of the repository interface: (1) stream emits defaults when storage is empty, (2) updateSettings persists and stream emits new value, (3) multiple rapid updates result in correct final value, (4) readSync returns null before first write and correct value after. Write an integration test using real SharedPreferences (via shared_preferences_platform_interface test helpers) verifying persistence across simulated restart. Minimum 85% branch coverage.

Epic Risks (2)
high impact medium prob technical

Flutter's SemanticsService behaves differently between iOS (VoiceOver) and Android (TalkBack) in edge cases — e.g., announcement queuing, focus-gain timing, and attribute support. If the facade does not correctly abstract these differences, announcements may be silent or misfired on one platform, causing regression on the other platform to go unnoticed until device testing.

Mitigation & Contingency

Mitigation: Write platform-divergence unit tests early using SemanticsServiceFacade mocks. Validate announcement delivery on a physical iPhone (VoiceOver) and Android device (TalkBack) at the end of each sprint. Document known platform differences in the facade's inline API comments.

Contingency: If a platform difference cannot be abstracted cleanly, expose a platform-specific override path in the facade and implement targeted workarounds per platform, accepting the added complexity in exchange for correct behaviour.

medium impact medium prob scope

Accessibility preferences stored in local storage may need new fields as higher-tier epics are implemented (e.g., announcement verbosity, sensitive-field guard toggle). Schema changes to an already-persisted store risk data migration failures or silent defaults on existing installs, breaking user preferences.

Mitigation & Contingency

Mitigation: Design the AccessibilitySettingsRepository with a versioned JSON schema from the start, using merge-with-defaults on read so new fields fall back gracefully. Define the full expected field list upfront based on all downstream epic requirements before writing the first record.

Contingency: If migration fails on a live install, fall back to full reset-to-defaults with a one-time in-app notification informing the user that accessibility preferences have been reset and inviting them to reconfigure.