high priority medium complexity testing pending testing specialist Tier 3

Acceptance Criteria

All unit tests pass with 100% coverage of ReportingPeriodService public methods
Boundary tests cover midnight UTC (00:00:00Z) and Norwegian local time (CET/CEST UTC+1/+2) transitions correctly
Tests verify Q1 (Jan 1–Mar 31), Q2 (Apr 1–Jun 30), Q3 (Jul 1–Sep 30), Q4 (Oct 1–Dec 31) period boundaries exactly
Overlapping period detection test: two periods sharing any datetime range must be flagged and test must assert the violation
Historical lookup test: querying a period from 2 years ago returns the same result as at time of creation (immutability guarantee)
Re-aggregation safety test: calling aggregate twice on the same period produces identical results with no side effects
DST (daylight saving time) transition tests: activities logged at 02:00 on the last Sunday of March and October fall into the correct quarter
Edge case: activity at exactly 23:59:59.999 on the last day of a quarter is attributed to that quarter, not the next
Edge case: empty period (no activities) returns zero count without error
Integration tests verify that period filters applied to Supabase queries return the correct rows using test data fixtures
Test suite runs in under 30 seconds on CI

Technical Requirements

frameworks
flutter_test
Flutter
Dart
apis
Supabase REST API (test instance)
Supabase client (flutter_supabase)
data models
ReportingPeriod
ActivityRecord
BufdirQuarterlyPeriod
performance requirements
Full test suite completes within 30 seconds
Each individual unit test completes within 100ms
Integration tests using Supabase test instance complete within 5 seconds each
security requirements
Integration tests must use a dedicated test Supabase project, never the production database
No real participant PII in test fixtures — use anonymized or synthetic identifiers

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Norwegian time zone handling is the highest-risk area: use the `timezone` Dart package (not just `DateTime.utc`) to correctly model CET (UTC+1) and CEST (UTC+2). ReportingPeriodService should store and compare all boundaries in UTC internally, only converting to local time for display. For Bufdir quarterly periods, define a `BufdirQuarter` enum with factory constructors that derive start/end DateTime from year + quarter number — this makes parameterized tests trivial. Re-aggregation safety should be tested by verifying that the service either uses idempotent upsert semantics in Supabase or reads from an immutable snapshot column — clarify this with the task-003 implementer before writing tests.

Use `setUp`/`tearDown` with Supabase test transactions that are rolled back after each test to avoid fixture pollution.

Testing Requirements

Unit tests using flutter_test for all pure Dart logic in ReportingPeriodService (boundary calculation, overlap detection, period lookup). Integration tests connecting to a Supabase test instance to verify SQL-level filtering. Use parameterized test cases (group/test with loops) for the 8 DST and quarter-boundary scenarios. Create a shared test fixture file with period definitions covering 4 quarters Ă— 2 years.

Verify immutability by capturing a snapshot of a period's aggregate result, mutating underlying data in the test DB, and confirming the historical lookup still returns the original value. Minimum 90% statement coverage measured by flutter test --coverage.

Component
Reporting Period Service
service medium
Epic Risks (4)
high impact high prob integration

NHF members can belong to up to 5 local chapters. When a participant has activities registered under different chapter IDs within the same reporting period, deduplication requires a reliable cross-chapter identity key. If national IDs are absent for some members (a known data quality issue in NHF's systems), the deduplication service may fail to identify duplicates, resulting in inflated counts submitted to Bufdir.

Mitigation & Contingency

Mitigation: Implement a multi-attribute identity matching strategy: primary match on national_id, fallback to (full_name + birth_year + municipality) composite key. Expose a low-confidence match list in DeduplicationAnomalyReport that coordinators can review and manually resolve before submission.

Contingency: If identity data quality is too poor for reliable automated deduplication for specific organisations, add an organisation-level config flag that disables cross-chapter deduplication for that org and requires coordinators to manually review the anomaly report before submitting.

high impact medium prob integration

The geographic distribution algorithm must resolve NHF's 1,400 local chapter hierarchy to regional aggregates. If the organizational unit hierarchy in the database is incomplete (missing parent-child relationships for some chapters), the geographic service will silently drop activities from unmapped chapters, producing an understated geographic breakdown.

Mitigation & Contingency

Mitigation: Add a hierarchy completeness validation step in GeographicDistributionService that counts activities without a resolvable region assignment and surfaces them as an 'unmapped_activities' field in the distribution result. Block export if unmapped_activities > 0.

Contingency: Provide a 'national' fallback bucket for activities from chapters with no region assignment, clearly labelled in the preview screen so coordinators are alerted to fix the org hierarchy data before re-running aggregation.

high impact low prob technical

BufdirAggregationService orchestrates four dependent services. If one service (e.g., GeographicDistributionService) throws mid-pipeline, the partially assembled metrics payload may be silently cached or returned as if complete, resulting in a Bufdir submission missing the geographic breakdown section.

Mitigation & Contingency

Mitigation: Implement the orchestrator as a transactional pipeline using Dart's Result type pattern: each stage returns Either<AggregationError, PartialResult>, and the orchestrator only proceeds if all stages succeed. The final payload is only assembled and persisted when all stages return success.

Contingency: If a partial failure state reaches the UI, the AggregationProgressIndicator must display a specific stage failure message with a retry option that re-runs only the failed stage rather than the full pipeline.

medium impact medium prob scope

Internal activity types that have no corresponding Bufdir category in the mapping configuration will cause the aggregation to silently exclude those activities from the final counts. Coordinators may not notice the omission until Bufdir queries why submission totals are lower than expected.

Mitigation & Contingency

Mitigation: BufdirAggregationService must produce an unmapped_activity_types list as part of its output. If any internal activity types are unmapped, display a blocking warning in the AggregationSummaryWidget listing the unmapped types before allowing the coordinator to proceed to export.

Contingency: Allow coordinators to temporarily assign unmapped activity types to a Bufdir 'other' catch-all category as an emergency workaround, with an audit flag indicating manual override was applied for that submission.