high priority low complexity backend pending backend specialist Tier 1

Acceptance Criteria

getLastUsedActivityTypeId() returns null when no value has ever been saved (first-time user scenario)
saveLastUsedActivityTypeId(id) persists the value such that a subsequent getLastUsedActivityTypeId() call returns the same id
After saving multiple times, only the most recently saved id is returned
The store compiles without errors and is injectable via Riverpod
The store delegates all storage I/O to LocalStorageAdapter and contains no direct SharedPreferences calls
The storage key used is a private constant (not a magic string at call sites)
Saving an empty string is treated as a valid operation (does not throw)
The class is documented with a single-line doc comment explaining its purpose in the two-tap happy path

Technical Requirements

frameworks
Flutter
Riverpod
data models
ActivityType
performance requirements
Both read and write operations must complete in under 50ms on device (SharedPreferences is synchronous after init)
security requirements
Store only the activity type ID (non-sensitive), never store PII or auth tokens in this store
Key name must be namespaced (e.g., 'reg_prefs_last_activity_type_id') to avoid collisions with other SharedPreferences consumers

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Keep this class thin — it is a typed facade over LocalStorageAdapter, not a caching layer. Define a single private constant for the storage key. The two public methods are the entire public API; resist the temptation to add clearPreferences() or getAll() without a concrete consumer requirement. Use a const storage key like `_kLastActivityTypeKey = 'reg_prefs_last_activity_type_id'`.

The Riverpod provider (defined in task-006) should expose this as a simple `Provider` since the store has no async initialization of its own — initialization is owned by LocalStorageAdapter. Null return on missing key is the correct design; callers (BLoC/use-case layer) decide the fallback, not this store.

Testing Requirements

Unit tests using flutter_test with SharedPreferences.setMockInitialValues. Minimum test cases: (1) getLastUsedActivityTypeId returns null on empty store, (2) save then get round-trips correctly, (3) overwrite with new value returns latest, (4) store delegates to LocalStorageAdapter (verify via mock/spy, not real SharedPreferences). 100% branch coverage on the store class. No integration tests required for this component.

Component
Registration Preferences Store
data low
Epic Risks (3)
high impact medium prob technical

The optimistic insert pattern requires reconciling temporary local IDs with server-assigned IDs after the async Supabase write completes. If reconciliation logic is incorrect, the UI may display stale records, duplicate entries may appear, or subsequent operations (edit, delete) may target the wrong record ID, corrupting data integrity.

Mitigation & Contingency

Mitigation: Define a clear contract for temporary ID generation (e.g., UUID prefixed with 'local-') and implement a dedicated reconciliation method in ActivityRepository that atomically swaps the temporary ID. Write integration tests that simulate the full optimistic → confirm cycle.

Contingency: If reconciliation proves too complex, fall back to a simpler non-optimistic insert with a loading spinner for the network round-trip. The UX degrades slightly but correctness is preserved. Re-introduce optimistic behaviour once the pattern is stable.

high impact medium prob integration

Supabase row-level security policies on the activities table may not be configured to match the access patterns required by the client. If RLS blocks inserts or selects for the authenticated peer mentor session, all activity registration operations will silently fail or return empty results, which is difficult to diagnose in production.

Mitigation & Contingency

Mitigation: Define and test RLS policies in a dedicated Supabase migration script as part of this epic. Create integration tests that execute against a local Supabase instance with RLS enabled, covering insert, select by peer mentor ID, and denial of cross-mentor access.

Contingency: Maintain a fallback service-role client path (server-side only) that can be activated via a feature flag if client-side RLS is blocking legitimate operations while policies are corrected.

medium impact low prob technical

SharedPreferences on Flutter can become corrupted if the app crashes mid-write or if the device runs out of storage. A corrupted last-used activity type preference would cause the defaults manager to return null or an invalid ID, breaking the zero-interaction happy path.

Mitigation & Contingency

Mitigation: Wrap all LocalStorageAdapter reads in try/catch with typed safe defaults. Validate the retrieved activity type ID against the known list before returning it. Use atomic write operations where the platform supports them.

Contingency: If the preference store is corrupted, silently reset to the hardcoded default (first activity type alphabetically or 'general') and log a warning. The user loses their last-used preference but the app remains functional.