Implement DistancePrefillService read/write on LocalDistanceCache
epic-mileage-reimbursement-entry-data-layer-task-007 — Build DistancePrefillService that wraps LocalDistanceCache with typed read and write operations for the per-user last-used distance value. getLastDistance returns null for first-time users with no stored value, returning a typed Optional. saveLastDistance persists the value keyed by user id. Implement clearOnLogout to remove the stored distance when a logout event is detected via the auth session stream.
Acceptance Criteria
Technical Requirements
Implementation Notes
Define a LocalDistanceCache abstract interface with read(String key) → Future
The clearOnLogout method in this task is a simple imperative method; the auth stream subscription that calls it is wired in task-008 (the Riverpod provider layer). Keep this service unaware of Riverpod.
Testing Requirements
Unit tests (flutter_test): test getLastDistance returns null for a userId with no stored value; test saveLastDistance followed by getLastDistance returns the saved value; test clearOnLogout removes the value so subsequent getLastDistance returns null; test that different userId keys are independent (save for user A, get for user B returns null); test that saveLastDistance throws ArgumentError for distanceKm <= 0; test that getLastDistance returns null when LocalDistanceCache throws. Use a fake in-memory implementation of LocalDistanceCache (a simple Map-backed fake is sufficient).
If OrgRateConfigRepository caches the per-km rate aggressively and an admin updates the rate mid-session, ongoing form interactions will show the old rate until the Stream emits. This could result in the UI showing a rate that differs from what is stored when the claim is submitted, causing confusion or disputes.
Mitigation & Contingency
Mitigation: Subscribe to a Supabase Realtime channel for the org_configuration table so config changes propagate within seconds. Document the eventual-consistency window in code comments.
Contingency: If Realtime subscription proves unreliable in test, add a polling fallback with a configurable interval (default 5 minutes) and display a 'rate updated' toast when the stream emits a changed value.
The correction window within which a claim can be deleted or voided is not explicitly specified in the feature documentation. Implementing the wrong window (e.g. 24 hours vs 7 days) could lock users out of corrections or allow inappropriate post-approval modifications.
Mitigation & Contingency
Mitigation: Raise the correction window definition as a blocking question to the HLF product owner before implementing the delete/void path in MileageClaimRepository. Implement the window duration as an org-level configuration value rather than a hardcoded constant.
Contingency: If the question cannot be resolved before implementation, default to 24 hours as the most conservative option and flag the value for review in the first user-acceptance test.