critical priority medium complexity backend pending backend specialist Tier 0

Acceptance Criteria

A Dart file `lib/domain/models/bufdir/bufdir_payload.dart` (or equivalent canonical path) defines all payload model classes with full null-safety annotations
The top-level `BufdirPayload` model includes: organisation_id (String, non-null), scope_level (enum: chapter/region/national), period_start (DateTime), period_end (DateTime), generated_at (DateTime), and peer_mentor_records (List<BufdirPeerMentorRecord>)
The `BufdirPeerMentorRecord` model includes: peer_mentor_id (String), peer_mentor_name (String), total_sessions (int), total_minutes (int), and activity_type_breakdowns (List<BufdirActivityTypeBreakdown>)
The `BufdirActivityTypeBreakdown` model includes: activity_type_id (String), activity_type_label (String), session_count (int), total_minutes (int)
The `BufdirOrgRollUpMetadata` model includes: child_org_ids (List<String>), roll_up_level (enum matching scope_level), contributing_chapter_count (int)
The `BufdirDuplicateFlag` model includes: original_record_id (String), duplicate_record_id (String), peer_mentor_id (String), contact_id (String), date (DateTime), and overlap_description (String)
Every model that may contain duplicate-flagged data includes a `duplicate_warnings` field (List<BufdirDuplicateFlag>, defaults to empty list)
All models implement `fromJson` and `toJson` methods compatible with Dart's json_serializable or equivalent code generation (if used) for consistent serialization across CSV, PDF, and API output channels
The `scope_level` enum values exactly match the string literals expected by the aggregation service step that produces them
A brief DartDoc comment on each class and field explains its purpose and any constraints (e.g., `period_end must be the last day of the reporting period inclusive`)
The file compiles without errors or warnings with `flutter analyze`

Technical Requirements

frameworks
Dart (latest null-safe)
flutter (for build_runner if json_serializable is used)
json_annotation / json_serializable (if code-gen pattern is already established in the project)
apis
Bufdir reporting API schema (reference Bufdir's specification document for canonical field names and types)
data models
BufdirPayload
BufdirPeerMentorRecord
BufdirActivityTypeBreakdown
BufdirOrgRollUpMetadata
BufdirDuplicateFlag
ScopeLevel (enum)
performance requirements
Models must be value-equality compatible (implement == and hashCode or use a package like equatable/freezed) to support reliable test assertions and BLoC state comparison
security requirements
No PII (peer mentor full names, contact details) should appear in logs — ensure toString() overrides on models omit sensitive fields or use redacted placeholders
Models must not expose internal Supabase row IDs directly to external consumers — use domain-level IDs

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Place all Bufdir domain models in a dedicated folder (`lib/domain/models/bufdir/`) to make the contract boundary explicit and easy to locate. If the project already uses `freezed` for immutable models and union types, use it here for consistency — it auto-generates copyWith, ==, hashCode, and toJson. If not using code generation, implement these manually and note the decision in a comment so future developers don't add a second pattern. The `ScopeLevel` enum should use lowercase string values for JSON (`chapter`, `region`, `national`) matching what Supabase Edge Functions will produce.

Avoid importing Flutter widgets or platform channels in this file — it must be pure Dart so it is usable in both Flutter mobile and any future server-side Dart context. This file is the single source of truth: any time the Bufdir specification changes, update these models first and let the compiler surface all required downstream changes.

Testing Requirements

Unit tests in `test/domain/models/bufdir/bufdir_payload_test.dart` covering: (1) round-trip serialization — construct a model, call toJson, then fromJson, and assert equality; (2) null/empty list defaults — confirm duplicate_warnings defaults to [] when absent from JSON; (3) enum parsing — confirm fromJson correctly maps all scope_level string values and throws or returns null for unknown values; (4) boundary values — period_start equal to period_end (single-day report) is accepted; negative session counts should either be prevented by constructor assertion or rejected by fromJson with a descriptive error. All tests use flutter_test.

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.