critical priority medium complexity testing pending testing specialist Tier 2

Acceptance Criteria

Test suite covers the scenario where a peer mentor is registered in two chapters (contact_chapter records) and registers the same activity — deduplication retains exactly one activity record in the query result
Test covers the scenario where the same activity is submitted by both a coordinator (on behalf of) and the peer mentor directly — the result contains exactly one activity, and the canonical record is the peer mentor's own submission
Boundary test: two activities with identical `date` timestamps but different `activity_type_id` values are NOT deduplicated — both appear in results
Boundary test: two activities with identical `date` timestamps AND identical `activity_type_id` values from the same peer mentor — deduplicated to one
Test covers an activity that legitimately spans multiple chapters (e.g. a multi-chapter event) — it appears once in the result with a multi-chapter annotation or flag
Each test uses clearly named mock datasets with comments explaining the business scenario being tested
All deduplication logic paths in `BufdirActivityQueryService` are covered — branch coverage must be at least 90% for the deduplication method
Tests are fully isolated — no shared mutable state between test cases; each test constructs its own mock data
Test names follow the pattern `givenX_whenY_thenZ` or equivalent descriptive naming convention
All tests pass with `flutter test` in under 10 seconds total for the suite
A summary comment block at the top of the test file documents the deduplication business rules being validated, referencing the NHF requirement for duplicate warning detection from the workshop documentation

Technical Requirements

frameworks
Flutter
flutter_test
mocktail (or mockito) for Supabase client mocking
apis
Supabase PostgreSQL (mocked — no real database calls in unit tests)
data models
activity
contact_chapter
assignment
activity_type
performance requirements
Full test suite for deduplication scenarios must complete in under 10 seconds
Each individual test must complete in under 500 ms — no real network calls or file I/O permitted
security requirements
Test data must use synthetic UUIDs (e.g. `'00000000-0000-0000-0000-000000000001'` pattern) — no real personnummer, names, or PII from production
Mock Supabase client must not be configured with real credentials — use placeholder strings only

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use `mocktail` for mocking the Supabase client since it does not require code generation unlike `mockito`. Create a `_buildActivity({required String id, required String peerId, required String typeId, required DateTime date, String? coordinatorSubmittedBy})` helper factory at the top of the test file to reduce boilerplate. For the multi-chapter scenario, construct `contact_chapter` mock records linking one `contact_id` (peer mentor) to two `organisation_unit_id` values, then assert the query service de-duplicates correctly.

For the coordinator-vs-peer-mentor scenario, the mock data should include two activity records with the same `peer_mentor_id`, `activity_type_id`, and `date` but different `submitter_role` values — assert the service returns the peer mentor's record as canonical. Document each test group with a `// Business rule:` comment explaining which requirement from the NHF workshop (duplicate warning detection, multi-chapter membership) it validates. Use `setUp` and `tearDown` properly to reset mock state between tests. Avoid `expect(...

, equals(... ))` on entire lists — use `expect(result.length, equals(1))` and then assert specific fields to produce clearer failure messages.

Testing Requirements

This task IS the testing task — the output is the test file itself. The test file must be located at `test/orchestration/bufdir_activity_query_service_test.dart` (or equivalent path matching the source structure). Required test groups: (1) `group('deduplication — same peer mentor, two chapters')` with at least 3 tests; (2) `group('deduplication — coordinator vs peer mentor submission')` with at least 2 tests; (3) `group('boundary — timestamp collisions')` with at least 3 tests; (4) `group('multi-chapter events')` with at least 2 tests; (5) `group('empty and edge inputs')` covering null period, zero activities, and single activity (no deduplication needed). Run `flutter test --coverage` and assert the deduplication method reaches 90%+ branch coverage.

The test file itself must pass `dart analyze` with zero warnings.

Component
Bufdir Activity Query Service
service high
Epic Risks (3)
high impact medium prob technical

NHF contacts can belong to up to five local chapters simultaneously. If the deduplication logic in the activity query service incorrectly attributes cross-chapter activities, organisations will either under-report or over-report to Bufdir, which could trigger grant clawback or compliance investigations.

Mitigation & Contingency

Mitigation: Implement deduplication using the existing multi-chapter membership service as the source of truth for chapter affiliation. Write test fixtures covering all known multi-chapter edge cases and validate outputs against manually prepared reference exports from NHF.

Contingency: If deduplication cannot be made deterministic for complex hierarchies before release, gate the export behind an org-level feature flag and require NHF to validate a preview export against their manual Excel before enabling in production.

medium impact medium prob dependency

Server-side Dart libraries for Excel generation are less mature than equivalents in Node.js or Python. The chosen library may lack support for Bufdir-required formatting features (merged cells, data validation, specific date formats), requiring significant workaround effort or a library switch mid-implementation.

Mitigation & Contingency

Mitigation: Evaluate the top two Dart xlsx libraries (excel, spreadsheet_decoder) against a Bufdir template sample file before committing. Identify all required formatting features and verify library support in a spike.

Contingency: If no Dart library meets requirements, implement the Excel generation as a Supabase Edge Function in TypeScript using the well-supported ExcelJS library, exposing it to the Dart backend via an internal RPC call.

medium impact medium prob integration

The attachment bundler must retrieve documents from Supabase Storage that were uploaded by the document attachments feature. If storage paths, RLS policies, or signed URL expiry have not been standardised across features, the bundler may fail to retrieve attachments at export time.

Mitigation & Contingency

Mitigation: Audit the document attachments feature's storage schema and RLS policies before implementing the bundler. Agree on a stable internal service-account access pattern for cross-feature storage reads.

Contingency: If cross-feature storage access cannot be made reliable, implement the bundler to include only attachments that can be retrieved successfully and produce a manifest listing any attachments that could not be bundled, rather than failing the entire export.