critical priority low complexity backend pending backend specialist Tier 1

Acceptance Criteria

getActivityCountForPeriod(orgId, startDate, endDate) returns an int representing the total activity count for the specified period
getRangeBreakdown(orgId, startDate, endDate) returns a List<BufdirCategoryCount> with category code and count fields
Both methods call the corresponding Supabase RPC functions using supabase_flutter's .rpc() API
PostgrestException is caught and re-thrown as a typed domain exception (e.g. AggregationException) with a meaningful message
Passing endDate before startDate throws an ArgumentError before the network call is made
Return types use immutable Dart model classes with fromJson constructors and equatable support
Repository is registered as a Riverpod provider and is mockable for unit tests
Both methods include Dart doc comments documenting parameters, return type, and thrown exceptions

Technical Requirements

frameworks
Flutter
Riverpod
supabase_flutter
apis
Supabase RPC: get_bufdir_activity_count
Supabase RPC: get_bufdir_range_breakdown
data models
BufdirCategoryCount
ActivityAggregation
performance requirements
RPC calls must complete within 3 seconds on a 4G connection
Results should not be cached by the repository layer — caching is the caller's responsibility
security requirements
Organisation ID must be sourced from the authenticated session, not accepted as a raw user-supplied string without validation
No aggregate data must be logged to the console in production builds

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Use supabase_flutter's `supabase.rpc('get_bufdir_activity_count', params: {'org_id': orgId, 'start_date': startDate.toIso8601String(), 'end_date': endDate.toIso8601String()})` pattern. Define BufdirCategoryCount as a Dart class with final String categoryCode and final int count fields, implementing Equatable for value comparison in tests. Validate date ordering in the method body before invoking the RPC to produce a clear error message. Register via Riverpod alongside PeriodConfigurationRepository from task-002 in the same providers file.

Consider defining a BufdirAggregationRepositoryInterface abstract class so tests can inject mocks without depending on the concrete implementation.

Testing Requirements

Unit tests using flutter_test and Mockito. Mock the Supabase client's .rpc() call. Test cases: (1) successful RPC call returns correctly mapped BufdirCategoryCount list, (2) empty RPC result returns empty list, (3) PostgrestException maps to AggregationException, (4) network timeout maps to NetworkException, (5) endDate before startDate throws ArgumentError without making a network call, (6) getActivityCountForPeriod returns correct integer from RPC response. Achieve 90%+ line coverage.

Component
Bufdir Aggregation Repository
data low
Epic Risks (3)
high impact medium prob security

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.

medium impact medium prob technical

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.

medium impact medium prob technical

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.