high priority low complexity testing pending testing specialist Tier 2

Acceptance Criteria

Test file is located at test/repositories/generated_reports_repository_test.dart and runs with flutter test
createAuditRecord returns the created GeneratedReport model when Supabase insert succeeds
updateStatus(id, ExportStatus.completed, fileUrl: '...') correctly calls Supabase update with completed status and file URL, returns updated record
updateStatus(id, ExportStatus.failed, error: '...') correctly stores error message, returns failure-state record
fetchByOrgId(orgId, dateRange) returns only records matching both org_id and the date range — verified with mock returning mixed data
fetchByOrgId with a date range whose start equals end (single day) returns records for that day
fetchByOrgId with an inverted date range (start > end) returns typed failure or throws ArgumentError — behavior must be documented and tested
Supabase PostgrestException is caught and wrapped in a typed ReportRepositoryFailure (not rethrown as raw exception)
Query from a different org_id (simulated by mock returning empty list) returns an empty list — no exception
All public methods of GeneratedReportsRepository have at least one passing test
Test suite passes with flutter test --coverage; coverage report shows 100% method coverage for the repository class

Technical Requirements

frameworks
Flutter
flutter_test
mockito or mocktail
apis
Supabase PostgREST client (mocked)
data models
GeneratedReport
ExportStatus (enum)
ReportRepositoryFailure
performance requirements
All unit tests complete in under 2 seconds total (no real network calls)
security requirements
Test fixtures must not contain real org_id values or PII — use synthetic UUIDs
Verify that the repository never exposes raw Supabase error messages to callers

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Inject the Supabase client via constructor so the mock can be substituted without reflection. Define a sealed class or freezed union ReportRepositoryFailure with variants for network errors, not-found, and permission-denied so callers can pattern-match. In the RLS simulation test, configure the mock to return an empty list rather than throwing — RLS at the DB level silently filters rows, so the repository should handle empty gracefully. Use const GeneratedReport fixtures to keep tests readable.

Avoid testing Supabase internals (e.g., HTTP headers); only assert the repository's public contract. If using mocktail, prefer when().thenAnswer() with async closures to avoid synchronous mock pitfalls.

Testing Requirements

Pure unit tests using flutter_test. Mock the Supabase client with mockito or mocktail — do not hit a real database. Use setUp to build a fresh repository instance with a fresh mock before each test. Group tests by method (createAuditRecord, updateStatus, fetchByOrgId).

Assert both the returned value and the exact Supabase method call signature (table name, column names, values). Verify exception-wrapping by throwing PostgrestException in the mock and asserting the return type is ReportRepositoryFailure. Generate coverage with flutter test --coverage and confirm 100% method coverage.

Component
Generated Reports Repository
data low
Epic Risks (3)
high impact medium prob technical

NHF's three-level hierarchy (national / region / chapter) with 1,400 chapters may have edge cases such as chapters belonging to multiple regions, orphaned nodes, or missing parent links in the database. Incorrect scope expansion would silently under- or over-report activities, which could invalidate a Bufdir submission.

Mitigation & Contingency

Mitigation: Obtain a full hierarchy fixture export from NHF before implementation begins. Write exhaustive unit tests covering boundary cases: single chapter, full national roll-up, chapters with no activities, and chapters assigned to multiple regions. Validate resolver output against a known-good manual count.

Contingency: If hierarchy data quality is too poor for automated resolution at launch, implement a manual scope override in the coordinator UI that allows the coordinator to explicitly select org units from a tree picker, bypassing the resolver.

medium impact high prob dependency

The activity_type_configuration table may not cover all activity types currently in use, leaving a subset unmapped at launch. Bufdir submissions with unmapped categories will be incomplete and may be rejected by Bufdir.

Mitigation & Contingency

Mitigation: Run a query against production activity data before implementation to enumerate all distinct activity type IDs. Cross-reference with Bufdir's published category schema (request from Norse Digital Products). Flag every gap as a known issue and build the warning surface into the preview panel.

Contingency: Implement a fallback 'Other' category bucket for unmapped types and surface a prominent warning in the export preview requiring coordinator acknowledgement before proceeding. Log unmapped types for post-launch cleanup.

high impact low prob security

Supabase RLS policies on generated_reports and the storage bucket must enforce strict org isolation. A misconfigured policy could allow a coordinator from one organisation to read another organisation's export files, creating a serious data breach with GDPR implications.

Mitigation & Contingency

Mitigation: Write RLS integration tests that attempt cross-org reads with explicitly different JWT tokens and assert that all attempts return empty sets or 403 errors. Include RLS policy review in the pull request checklist. Use Supabase's built-in policy tester during development.

Contingency: If a policy gap is discovered post-deployment, immediately revoke all signed URLs for affected exports, audit the access log for unauthorised reads, and issue a coordinated disclosure to affected organisations per GDPR breach notification requirements.