high priority high complexity testing pending testing specialist Tier 6

Acceptance Criteria

A seed SQL script exists at supabase/seed/badge-evaluation-seed.sql populating: 1 Blindeforbundet org, 3 peer mentors, badge_definitions for 3rd-honorar and 15th-honorar thresholds, and activity records for each test scenario
Test: inserting a 3rd activity for a peer mentor triggers the edge function and results in the 3rd-honorar badge appearing in the peer_mentor_badges table
Test: inserting a 15th activity for a peer mentor triggers the edge function and results in the 15th-honorar badge being awarded
Test: awarding a badge a second time (peer mentor already has badge) does not create a duplicate row in peer_mentor_badges — idempotency verified
Test: each badge award results in a badge_evaluation_logs row with correct peer_mentor_id, org_id, and badges_awarded list
Test: FCM dispatch is verified by asserting the mock FCM endpoint received a POST with the correct badge name in the notification body
Test: a peer mentor with 2 activities does not receive the 3rd-honorar badge — criteria not yet met
All tests run against the seeded test database and reset state between test cases using transactions or table truncation
Tests are executable via a single command documented in the runbook (e.g. `deno test --allow-net --allow-env supabase/functions/badge-criteria-edge-function/tests/`)
All 8 test scenarios pass consistently with no flakiness across 3 consecutive runs

Technical Requirements

frameworks
Deno test runner (built-in)
Supabase JS client v2 (for test setup and assertion queries)
Supabase CLI (for local test environment)
apis
Supabase Edge Functions (invoke locally via supabase functions serve)
Supabase PostgreSQL (seed and assertion queries)
FCM API v1 (mocked via local HTTP intercept)
data models
badge_definition
activity
assignment
bufdir_export_audit_log
device_token
performance requirements
Full integration test suite must complete within 3 minutes
Each individual test case must complete within 30 seconds including edge function invocation latency
Seed script must execute in under 10 seconds against a local Supabase instance
security requirements
Test database must use a separate Supabase project or local Supabase CLI instance — never run tests against production
Service role key for test environment stored in .env.test file excluded from version control via .gitignore
Test seed data must not include real personnummer or real contact PII — use generated test UUIDs and placeholder names

Execution Context

Execution Tier
Tier 6

Tier 6 - 158 tasks

Can start after Tier 5 completes

Implementation Notes

Structure tests in `supabase/functions/badge-criteria-edge-function/tests/` directory. Write a shared `test-helpers.ts` with functions: `seedBlindeforbundetOrg()`, `seedBadgeDefinitions()`, `seedPeerMentor(n_activities)`, `truncateTestTables()`. Use Deno's `Deno.serve` to spin up a mock FCM server on a configurable port during tests, recording all incoming POST requests for assertion. Configure the edge function to use the mock FCM URL via an environment variable during test runs.

For the duplicate-award test, insert the badge row in peer_mentor_badges before triggering the evaluation and assert only 1 row exists after. Consider using Supabase's local development stack (`supabase start`) as documented in supabase CLI docs for a fully isolated test environment. Tag each test with `// @scenario: threshold-3` comments for traceability back to acceptance criteria.

Testing Requirements

Integration test suite structure: describe blocks per scenario (threshold-3, threshold-15, duplicate-prevention, audit-log, fcm-dispatch, criteria-not-met). Each test: (1) truncate affected tables, (2) insert seed data for scenario, (3) invoke edge function directly or simulate DB webhook, (4) query database to assert expected state. Use Deno's `beforeEach` hooks for state reset. Mock FCM by running a local HTTP server that records incoming requests and returns 200.

Assert FCM mock received request with correct structure. Use `supabase functions serve` for local edge function execution during tests. Document how to run tests in the deployment runbook created in task-015.

Component
Badge Criteria Edge Function
infrastructure medium
Epic Risks (3)
medium impact medium prob technical

Supabase Edge Functions may experience cold start latency of 500ms–2s when they have not been invoked recently. If evaluation latency consistently exceeds the 2-second UI expectation, the celebration overlay timing SLA cannot be met without the optimistic UI fallback from the UI epic.

Mitigation & Contingency

Mitigation: Keep the edge function warm by scheduling a lightweight health-check invocation every 5 minutes in production. Optimise the function size to minimise Deno module load time. Implement the optimistic UI path in badge-bloc (from the UI epic) as the primary UX path so cold start only affects server-side reconciliation, not perceived responsiveness.

Contingency: If cold starts remain problematic, migrate badge evaluation to a Supabase database function (pl/pgsql) triggered directly by a database trigger on activity insert, eliminating the Edge Function overhead entirely for the evaluation logic while keeping Edge Function only for FCM notification dispatch.

high impact low prob integration

Supabase database webhooks can fail silently if the edge function returns a non-2xx response or times out. A missed webhook means a peer mentor does not receive a badge they earned, which is both a functional defect and a trust issue for organisations relying on milestone tracking.

Mitigation & Contingency

Mitigation: Implement idempotent webhook processing: the edge function reads the activity ID from the webhook payload and checks whether evaluation for this activity has already run (via an audit log query) before proceeding. Add Supabase webhook retry configuration (3 retries with exponential backoff). Monitor webhook failure rates via Supabase logs alert.

Contingency: Implement a nightly reconciliation job (Supabase scheduled function) that scans all activities from the past 24 hours, re-evaluates badge criteria for any peer mentor with no corresponding evaluation log entry, and awards any missing badges. Alert operations if reconciliation awards more than 5% of badges, indicating systematic webhook failure.

high impact low prob security

The evaluation service loads badge definitions per organisation, but a misconfigured RLS policy or incorrect organisation scoping in the edge function could cause one organisation's badge criteria to be evaluated against another organisation's peer mentor activity data, leading to incorrect or cross-contaminated badge awards.

Mitigation & Contingency

Mitigation: The edge function must extract organisation_id from the webhook payload activity record and pass it explicitly to every database query. Write a security test that seeds two organisations with distinct badge definitions and verifies that evaluating a peer mentor in org A never reads or awards org B definitions. Use Supabase service role key only within the edge function, never the anon key.

Contingency: If cross-org contamination is detected in audit logs, immediately disable the edge function webhook, run a targeted SQL query to identify and revoke incorrectly awarded badges, notify affected organisations, and perform a full security review of all RLS policies on badge-related tables before re-enabling.