Implement PeriodConfigurationRepository
epic-bufdir-report-period-selection-foundation-task-002 — Build the Dart repository class that reads and writes period configuration presets to Supabase. Include offline caching via local storage so previously loaded presets are available without a network connection. Expose methods: fetchPresetsForOrg, savePreset, deletePreset, and clearCache.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Define a PeriodPresetLocalCache abstraction (backed by SharedPreferences or Hive) so the caching strategy can be swapped independently. Store cached presets as JSON-encoded strings keyed by orgId. Use supabase_flutter's `.from('period_presets').select().eq('org_id', orgId)` pattern and map rows to strongly typed Dart models using a fromJson factory. Wrap all Supabase calls in try/catch blocks and translate PostgrestException codes to domain exceptions.
Register the repository as a Riverpod Provider
Testing Requirements
Unit tests using flutter_test and Mockito. Mock the Supabase client at the interface boundary. Test cases: (1) online fetch returns mapped PeriodPreset list, (2) offline path returns cached data, (3) cache miss + network error throws NetworkException, (4) savePreset upserts and updates cache, (5) deletePreset removes from Supabase and cache, (6) RLS-denied response (403) maps to PermissionException, (7) empty result set returns empty list without error. Target 90%+ line coverage on the repository class.
Supabase RLS policies for period preset configuration may be missing or incorrectly scoped, causing one organisation's presets to leak to another or write operations to fail silently.
Mitigation & Contingency
Mitigation: Define and review RLS policies for the bufdir_period_presets table in the migration file before any repository code is written. Include an integration test that verifies cross-organisation isolation using two distinct org credentials.
Contingency: If RLS is misconfigured in production, immediately disable the period preset fetch endpoint and fall back to hardcoded global presets until the policy is corrected and redeployed.
The activities table may lack a composite index on (organisation_id, activity_date), causing the range count query in BufdirAggregationRepository to perform a full table scan and exceed acceptable response time for large organisations.
Mitigation & Contingency
Mitigation: Add a migration that creates a composite index on (organisation_id, activity_date) as part of this epic. Benchmark the count query against a representative dataset (10 000+ rows) before marking the epic complete.
Contingency: If query latency is unacceptable after indexing, move the count query to a Supabase RPC function that leverages a materialised view or partial index, accepting a slight staleness window.
Flutter's native date picker widgets have known accessibility gaps (missing semantic labels, non-standard focus traversal) that may prevent WCAG 2.2 AA compliance out of the box, requiring a custom implementation.
Mitigation & Contingency
Mitigation: Evaluate third-party accessible date picker packages (e.g., table_calendar with custom semantics) against WCAG 2.2 AA criteria before beginning implementation. Document the chosen approach in the epic kick-off.
Contingency: If no package meets accessibility requirements, implement a simple text-field-based date entry with explicit semantic labels and format hints as an accessible fallback, deferring a fully visual calendar to a later iteration.