critical priority medium complexity backend pending backend specialist Tier 1

Acceptance Criteria

A static mapping table exists that covers all known internal activity_type values (individual_counselling, group_session, information_event, home_visit, phone_call, digital_meeting) to their canonical Bufdir category codes
Unmapped activity_type values are mapped to the Bufdir 'other' category code without throwing an exception
Every unmapped type produces a structured warning entry: { type: 'unmapped_activity_type', internal_value: string, assigned_code: 'other', timestamp: ISO8601 }
The mapper function is pure — given the same input it always returns the same output with no side effects
Mapping is case-insensitive so that 'Individual_Counselling' and 'individual_counselling' resolve identically
A dedicated unit test file covers: all mapped types return correct code, all unknown types return 'other', warning list is populated for unknowns, empty string input returns 'other' with warning, null input returns 'other' with warning
The mapping table is defined as a Dart const Map so it is compiled into the edge function with zero runtime overhead
The mapper returns both the Bufdir code and the full list of warnings so callers can propagate warnings without global state

Technical Requirements

frameworks
Dart (Supabase Edge Function / Deno runtime)
supabase_functions_dart or deno-compatible Dart
apis
Bufdir activity category enumeration (internal reference — confirm codes from Bufdir documentation)
data models
ActivityLog (activity_type field)
BufdirCategoryCode enum
MappingWarning record
performance requirements
Mapping lookup must be O(1) — use a const Map, not a switch chain
Zero heap allocations per mapping call (no new objects beyond the return tuple)
security requirements
Never log the activity content or personal data alongside the unmapped type warning
The mapping table must be code-defined (not database-driven) to prevent injection or tampering

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Define the mapping as a top-level Dart const: `const Map _activityTypeToBuffdirCode = { 'individual_counselling': 'IC', 'group_session': 'GS', ... }`. The mapper function signature should be: `BufdirCategoryResult mapActivityType(String? internalType)` returning a record/class with `{ String code, List warnings }`.

Normalise the input with `.toLowerCase().trim()` before lookup. Avoid placing the mapping in the database — Bufdir codes are defined by an external standard and change infrequently; a code-level const avoids a round-trip and keeps the edge function self-contained. When Bufdir updates their category list, update the const and redeploy. Coordinate with the team to confirm all active activity_type values used in production before finalising the mapping table.

Testing Requirements

Unit tests using flutter_test (or dart:test in edge function context). Test matrix: (1) each of the ~6 known activity types maps to the correct Bufdir code, (2) three distinct unknown types all map to 'other' and populate warnings, (3) empty string and null inputs are handled without exceptions, (4) calling the mapper twice with identical input returns identical output (idempotency), (5) warning list is empty when all types are mapped. Target 100% branch coverage for the mapper function. No integration tests needed at this layer.

Component
Bufdir Format Serializer
data medium
Epic Risks (3)
high impact medium prob technical

Supabase Edge Functions have a default execution timeout. For large national-scope exports aggregating tens of thousands of activities across 1,400 chapters, the edge function may time out before completing, leaving coordinators with a failed export and no partial output.

Mitigation & Contingency

Mitigation: Optimise the aggregation SQL using pre-materialised aggregation views or RPC functions that run inside the database rather than iterating records in Deno. Profile query execution time against realistic production data volumes early. Request an elevated timeout limit from Supabase if needed. Implement progress checkpointing so the export can be resumed from the last completed aggregation batch.

Contingency: For organisations exceeding a configurable threshold (e.g. >5,000 activities), switch to an asynchronous export pattern: the edge function writes a 'pending' audit record and enqueues the job; the client polls for completion and is notified via Supabase Realtime when the file is ready.

medium impact medium prob technical

Server-side PDF generation in a Deno Edge Function environment restricts library choices. Many popular PDF libraries require Node.js APIs not available in Deno, or produce large bundle sizes that exceed edge function limits. Choosing the wrong library could block the entire PDF generation path.

Mitigation & Contingency

Mitigation: Spike PDF library selection as the first task of this epic, evaluating at least two Deno-compatible options (e.g. pdf-lib, jsPDF with Deno compatibility shim). Test bundle size and basic rendering before committing to an implementation. Document the chosen library's constraints.

Contingency: If no suitable Deno-native PDF library is found, generate a well-structured HTML report from the edge function and use a headless Chromium service (e.g. Browserless, Gotenberg) for HTML-to-PDF conversion, or temporarily ship CSV-only export while the PDF path is resolved.

high impact high prob technical

Peer mentors affiliated with multiple chapters (a documented NHF scenario) must not be double-counted in participant totals. Incorrect deduplication logic would overreport participation figures to Bufdir, which could be discovered during audit and damage organisational credibility.

Mitigation & Contingency

Mitigation: Define and document the deduplication contract explicitly before coding: deduplication is per-person per-period, not per-activity. Build dedicated unit tests with fixtures containing the exact multi-chapter membership patterns described in NHF's documentation. Have a NHF representative validate test fixture outputs against known-good manual counts.

Contingency: If deduplication logic produces results that cannot be verified against manual counts before launch, surface a deduplication warning in the export preview listing the affected peer mentor IDs, and require explicit coordinator acknowledgement before finalising the export.