critical priority high complexity testing pending testing specialist Tier 7

Acceptance Criteria

Integration test suite covers the full pipeline from PeerMentorStatsAggregator → RecognitionTierService → BadgeAwardService with at least one test per pipeline stage transition
Test database is seeded with deterministic activity records that produce known stats (e.g., exactly 3 honorar assignments triggering first milestone, exactly 15 triggering second)
Tests assert that the correct badge IDs are written to the earned_badges table after each threshold is crossed
Idempotency test: running the full pipeline twice on the same seeded data produces exactly one badge record per badge type — no duplicates
Tests verify that the atomic write in BadgeAwardService either fully commits or fully rolls back (test rollback path by simulating a constraint violation mid-write)
All pipeline tests pass in isolation and in sequence without shared mutable state between test cases
Test teardown cleans all seeded data so the Supabase test schema is left in a pristine state after each run
Pipeline correctly handles the boundary: peer mentor with 14 honorar assignments earns no second-tier badge; one with 15 earns it
Test output includes clear assertion messages identifying which stage failed when a test fails
CI integration: tests run headlessly via flutter test with no manual Supabase setup required beyond environment variables

Technical Requirements

frameworks
Flutter
flutter_test
Riverpod
apis
Supabase REST API
Supabase RLS policy layer
data models
PeerMentorStats
RecognitionTier
EarnedBadge
HonorarRecord
performance requirements
Full pipeline integration test suite completes within 60 seconds
Each individual test case completes within 15 seconds including Supabase round-trips
Database seed and teardown operations complete within 5 seconds
security requirements
Test Supabase credentials must be loaded from environment variables — never hardcoded
Test schema must be isolated from production schema (separate Supabase project or dedicated test schema with RLS)
No real peer mentor PII may appear in seed data — use synthetic identifiers

Execution Context

Execution Tier
Tier 7

Tier 7 - 84 tasks

Can start after Tier 6 completes

Implementation Notes

Structure tests in three groups: (A) unit-style pipeline stage isolation (mock adjacent services), (B) pairwise integration (Aggregator + TierService, TierService + AwardService), (C) full end-to-end pipeline. For idempotency, use Supabase upsert with a unique constraint on (peer_mentor_id, badge_definition_id) and verify the constraint is tested explicitly. Seed data should be expressed as a SQL migration file committed to the repo under test/fixtures/. Use a testContainer helper that provisions a ProviderContainer with real Supabase client pointing at the test URL.

Avoid flutter_riverpod ProviderScope in integration tests — instantiate the container manually for determinism. The honorar counting logic for Blindeforbundet (3rd = office honorar, 15th = higher rate) must be captured as named constants in the production service and referenced by name in test assertions to avoid magic numbers.

Testing Requirements

Integration tests using flutter_test targeting a dedicated Supabase test environment. Seed data must be version-controlled as SQL fixture files. Cover: (1) stats aggregation correctness at each honorar threshold (3, 15 for Blindeforbundet), (2) tier eligibility evaluation returning correct tier at boundary values, (3) BadgeAwardService atomic write on success, (4) idempotency — pipeline re-run produces no duplicate badge records, (5) rollback on partial failure. Use setUp/tearDown hooks to insert and delete fixture rows.

No mocking of Supabase — all calls must hit the real test instance.

Component
Badge Award Service
service medium
Epic Risks (3)
high impact medium prob technical

peer-mentor-stats-aggregator must compute streaks and threshold counts across potentially hundreds of activity records per peer mentor. Naive queries (full table scans or N+1 patterns) will cause slow badge evaluation, especially when triggered on every activity save for all active peer mentors.

Mitigation & Contingency

Mitigation: Design aggregation queries using Supabase RPCs with window functions or materialised views from the start. Add database indexes on (peer_mentor_id, activity_date, activity_type) before writing any service code. Profile all aggregation queries against a dataset of 500+ activities during development.

Contingency: If query performance is insufficient at launch, implement incremental stat caching: maintain a peer_mentor_stats snapshot table updated on each activity insert via a database trigger, so the aggregator reads from pre-computed values rather than scanning raw activity rows.

medium impact low prob technical

badge-award-service must be idempotent, but if two concurrent edge function invocations evaluate the same peer mentor simultaneously (e.g., from a rapid double-save), both could pass the uniqueness check before either commits, resulting in duplicate badge records.

Mitigation & Contingency

Mitigation: Rely on the database-level uniqueness constraint (peer_mentor_id, badge_definition_id) as the final guard. In the service layer, use an upsert with ON CONFLICT DO NOTHING and return the existing record. Add a Postgres advisory lock or serialisable transaction for the award sequence during the edge function integration epic.

Contingency: If duplicate records are discovered in production, run a deduplication migration to remove extras (keeping earliest earned_at) and add a unique index if not already present. Alert engineering via Supabase database webhook on constraint violations.

medium impact medium prob scope

The badge-configuration-service must validate org admin-supplied criteria JSON on save, but the full range of valid criteria types (threshold, streak, training-completion, tier-based) may not be fully enumerated during development, leading to either over-permissive or over-restrictive validation that frustrates admins.

Mitigation & Contingency

Mitigation: Define a versioned Dart sealed class hierarchy for CriteriaType before writing the validation logic. Review the hierarchy with product against all known badge types across NHF, Blindeforbundet, and HLF before implementation. Build the validator against the sealed class so new criteria types require an explicit code addition.

Contingency: If admins encounter validation rejections for legitimate criteria, expose a 'criteria_raw' escape hatch (JSON passthrough, admin-only) with a product warning, and schedule a sprint to formalise the new criteria type properly.