Implement organization isolation filter logic
epic-bufdir-data-aggregation-data-layer-task-002 — Build the org-isolation filter layer inside the Aggregation Query Builder that automatically appends organization_id constraints to every RPC call and Supabase view query. Must support single-org and multi-org contexts, integrate with the tenant session store, and throw a typed exception if no org context is active. This filter must be applied before any query is dispatched to Supabase.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Implement the filter as a private method `_buildOrgConstraint(Map
Document clearly in code comments that this filter is the security boundary preventing cross-org data leakage — any future developer bypassing it must understand the consequences.
Testing Requirements
Unit tests using `flutter_test` and Mockito/mocktail must cover: (1) Single-org context: verify `applyOrgFilter` returns params with correct `organization_id` string value. (2) Multi-org context: verify params contain an `organization_id` list matching all session org IDs. (3) No-org context: verify `NoActiveOrgContextException` is thrown synchronously with a non-null message. (4) Passthrough test: verify that all pre-existing params keys are present and unchanged after filter application.
(5) Mock-injection test: stub AggregationQueryBuilder's Supabase client with a mock, call any public query method without an active org context, and assert the mock's RPC method was never called. Test coverage target: 100% of OrgIsolationFilter logic.
Supabase RPC functions return JSON with PostgreSQL numeric types (bigint, numeric) that do not map cleanly to Dart int/double. Silent truncation or JSON parsing errors could corrupt participant counts in the final Bufdir submission without any runtime exception.
Mitigation & Contingency
Mitigation: Define explicit Dart fromJson factories for all RPC result models with type-safe parsing and assertion checks. Add a contract test that compares raw RPC JSON output against expected Dart model values using a known seed dataset.
Contingency: If type mismatches are found in production metrics, expose a validation endpoint in BufdirMetricsRepository that re-fetches and compares raw RPC output against the persisted snapshot, flagging any discrepancies before export proceeds.
Persisted metric snapshots can become stale if additional activities are registered after the snapshot is saved but before the export is finalized. Coordinators might unknowingly export data that does not reflect the latest activity registrations.
Mitigation & Contingency
Mitigation: Store a snapshot_generated_at timestamp and a record_count_at_generation field in the snapshot. When the coordinator views cached results, compare the current activity count for the period against the snapshot value and display a 'Data updated since last aggregation — re-run?' warning if counts differ.
Contingency: Add a mandatory staleness check before the export confirmation dialog can proceed: if the snapshot is more than 24 hours old or the record count has changed, require the coordinator to re-run aggregation before the export button is enabled.