Implement OrgRateConfigRepository with Supabase and Stream cache
epic-mileage-reimbursement-entry-data-layer-task-002 — Build the concrete OrgRateConfigRepository that fetches the per-km rate and auto-approval threshold from Supabase via the supabase-mileage-adapter. Implement an internal BehaviorSubject-backed Stream so downstream consumers receive push updates when an admin changes the rate config without requiring manual refresh. Include in-memory caching with TTL and error propagation to the Stream.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Use `rxdart` package's `BehaviorSubject` for the internal stream. Maintain a `Map
For Supabase Realtime: use `supabase.channel('org_rate_config:$orgId').onPostgresChanges(...)` to receive INSERT/UPDATE events and update the BehaviorSubject. If Realtime is unavailable, implement a polling fallback with a configurable interval. Wrap all Supabase calls in try-catch and add the error to the subject via `subject.addError()` (which emits OrgRateConfigError downstream via map). Ensure `dispose()` is called by the Riverpod provider's `onDispose` callback (wired in task-003).
Testing Requirements
Write unit tests with a mock Supabase adapter: (1) first call fetches and emits OrgRateConfigLoaded, (2) second call within TTL emits cached value without calling Supabase, (3) call after TTL expiry re-fetches from Supabase, (4) Supabase error propagates as OrgRateConfigError on stream, (5) real-time push update emits new OrgRateConfigLoaded to all active subscribers. Use `fake_async` for TTL tests to avoid real time delays. Write one integration test that connects to the Supabase test instance and verifies a full fetch-and-stream cycle. Tag integration tests with `@Tags(['integration'])`.
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.