high priority medium complexity testing pending testing specialist Tier 3

Acceptance Criteria

Generated PDF bytes begin with the '%PDF-' magic header, confirming a structurally valid PDF document
All required Bufdir section headings (organization name, reporting period, activity summary table, totals row) are present as searchable text strings in the PDF byte stream
Dates are formatted in Norwegian long format (e.g., '15. januar 2025') throughout the document
Numeric totals use Norwegian locale formatting (period as thousands separator, comma as decimal separator)
Zero-activity organization produces a valid PDF with a summary section explicitly stating zero activities β€” no null reference exceptions
Large dataset (500+ activities) produces a multi-page PDF without truncation of any activity rows
Multi-page report includes page numbers in footer on every page
Test suite achieves 85%+ line coverage of BufdirPdfGenerator class
All tests are fully isolated β€” no file I/O or network calls

Technical Requirements

frameworks
flutter_test
pdf (Dart PDF generation package)
intl
data models
BufdirActivityRecord
BufdirOrganizationReport
BufdirReportingPeriod
performance requirements
PDF generation for 500 activity records completes in under 3 seconds in test environment
Unit tests must not render to a Flutter widget tree β€” operate at the PDF document model level
security requirements
Synthetic test data only β€” no real organization names or participant details
PDF metadata (author, creator fields) must not leak developer machine identity in tests

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

The pdf Dart package (pub.dev/packages/pdf) builds a Document tree before serialization β€” this is the ideal seam for assertions. Create a PdfTestHelper class with methods like extractTextContent(Uint8List pdfBytes) that searches raw bytes for UTF-8 text strings; this avoids a full PDF parser dependency in tests. For Norwegian date formatting, assert that DateFormat('d. MMMM y', 'nb_NO').format(date) produces the expected string and that this value appears in the PDF content.

For multi-page test: generate with enough records to force page break (depends on row height), then count page occurrences of the PDF 'Page' object keyword in raw bytes. Zero-activity edge case is the highest-risk crash scenario β€” prioritize this test. If the generator uses Flutter widgets internally (e.g., via printing package), wrap in flutter_test's pumpWidget and capture the document via a callback rather than direct instantiation.

Testing Requirements

Unit tests using flutter_test. Since the pdf Dart package produces Document objects before serialization, test at two levels: (1) document model level β€” assert pages, widgets, and text content on the Document object before calling save(); (2) byte level β€” call save() and parse the resulting bytes to confirm validity and text presence. Use a lightweight PDF text extractor utility (or regex on raw bytes for ASCII section headers) to assert required strings exist. Test groups: happy path (10 activities), zero activities, single activity, large dataset (500 activities for multi-page), Norwegian date formatting, Norwegian number formatting.

Mock any external font loading with in-memory font bytes to keep tests hermetic.

Component
Bufdir PDF Report Generator
infrastructure medium
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.