Integration tests for aggregation accuracy and org isolation
epic-periodic-summaries-foundation-task-011 — Write integration tests using a local Supabase test instance that seed two organisations with overlapping activity data, then invoke the ActivityAggregationRepository and assert that each organisation's aggregation results contain only their own data. Verify session counts and total hours match the seeded values exactly. Test offline fallback by disabling network and confirming SummaryCacheRepository returns stale cached data instead of throwing.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 5 - 253 tasks
Can start after Tier 4 completes
Implementation Notes
Use a dedicated Supabase test project (not production) — configure via environment variables `SUPABASE_TEST_URL` and `SUPABASE_TEST_ANON_KEY`. To simulate offline, override the HTTP client used by the Supabase client with a stub that throws `SocketException` — inject this via a test-only constructor parameter on the repository. Do NOT disable WiFi on the device — that would make the test environment-dependent. For seeding, use Supabase's service role key (server-side) to bypass RLS during setup, then test with the anon key (client-side) to verify RLS enforcement.
Tag these tests with `@Tags(['integration'])` so they can be skipped in fast unit test runs. Ensure the CI workflow has a `supabase start` step before the test step. Document the required Docker/Supabase version in the repo's CI readme.
Testing Requirements
Use `flutter_test` integration test runner. Set up a local Supabase instance (Docker or `supabase start`) for CI. In `setUp`: create two test users assigned to orgA and orgB respectively, insert 10 activity sessions for orgA and 8 for orgB with a 3-session date overlap in the target period. In `tearDown`: delete all seeded rows by test-run ID.
Test cases: (1) orgA aggregation returns exactly 10 sessions and correct total hours; (2) orgB aggregation returns exactly 8 sessions; (3) no session from orgB appears in orgA results; (4) unknown orgId returns zero aggregation; (5) cache populated after successful fetch; (6) offline mode returns cached data; (7) invalidated cache returns stale flag. Run with `flutter test integration_test/` in CI pipeline.
Supabase RLS policies for aggregation views are more complex than single-table policies. A misconfigured policy could silently allow a coordinator in one organisation to see data from another, causing a data breach and breaking trust with participating organisations.
Mitigation & Contingency
Mitigation: Write automated RLS integration tests that create two separate organisations with distinct data, then assert that queries authenticated as org-A users return only org-A rows. Run these tests in CI on every PR touching the database layer.
Contingency: If an RLS bypass is discovered post-deployment, immediately disable the periodic summaries feature flag, revoke affected sessions, audit access logs, notify affected organisations, and patch the policy before re-enabling.
Activity records may span multiple sessions types, proxy registrations, and coordinator bulk entries. Incorrect JOIN logic or missing filters in the aggregation query could double-count sessions or omit activity types, producing inaccurate summaries that erode user trust.
Mitigation & Contingency
Mitigation: Build a fixture dataset covering all activity registration paths (direct, proxy, bulk) and assert expected aggregated counts in integration tests before any UI consumes the repository.
Contingency: If inaccurate counts are reported post-launch, mark affected summaries as invalidated in the database and re-trigger generation once the query is corrected. Communicate transparently to affected users via an in-app banner.
The local cache must be invalidated when a new summary arrives via push notification. If the push token is stale or the FCM/APNs delivery is delayed, the device may show an outdated summary for an extended period, confusing users who see different numbers online versus offline.
Mitigation & Contingency
Mitigation: Implement a TTL on cached summaries (max 48 hours) so stale data is auto-cleared even without a push notification. Also trigger cache refresh on app foreground if the current period's summary is older than 24 hours.
Contingency: Provide a manual pull-to-refresh on the summary card that bypasses the cache and fetches directly from Supabase when a network connection is available.