high priority medium complexity backend pending backend specialist Tier 2

Acceptance Criteria

All dates in generated PDFs render in DD.MM.YYYY format using the nb_NO locale, with no ISO 8601 or US-format dates present anywhere in the output
Currency values (NOK) render with correct Norwegian formatting: period as thousands separator, comma as decimal separator (e.g. 1.234,50 kr), using the nb_NO locale
Norwegian special characters æ, ø, å (uppercase and lowercase) render correctly in all PDF text regions: headers, body paragraphs, table cells, and footer
Embedded font subset covers the full Latin Extended-A Unicode block (U+0100–U+017F) to support Norwegian and other Nordic characters without fallback glyphs
PDFs open and render identically on iOS, Android, macOS, and Windows — no tofu boxes or missing character placeholders
Month and day names appearing in any date label use Norwegian bokmål (e.g. 'januar', 'mandag'), not English
PDF file size does not increase by more than 150 KB compared to the pre-locale baseline due to font embedding
A locale configuration value (e.g. 'nb_NO') is read from a single constant or config object — not hardcoded in multiple places
Existing PDF layout and structure from task-006 are preserved; only locale and encoding behaviour changes
Unit test asserting that a date input of DateTime(2025, 3, 26) formats to the string '26.03.2025' in PDF output

Technical Requirements

frameworks
Flutter
dart_pdf (pdf package)
printing package
data models
activity
annual_summary
performance requirements
Font subsetting must keep embedded font delta under 150 KB per document
Locale formatting operations must add no more than 50 ms to total PDF generation time for a 100-activity report
security requirements
No PII is introduced or exposed via font metadata or PDF document properties
Font files sourced from the app bundle or a vetted open-source repository (e.g. Google Fonts Noto) — no runtime CDN download

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use the `intl` package (already in most Flutter projects) with `DateFormat('dd.MM.yyyy', 'nb_NO')` and `NumberFormat.currency(locale: 'nb_NO', symbol: 'kr')`. For the pdf package, embed a font via `PdfTtfFont` — use Noto Sans or Source Sans Pro from the assets bundle since both cover Latin Extended-A. Add the font file to `pubspec.yaml` assets and load it with `rootBundle.load()` before constructing the PdfDocument. Define a single `NorwegianPdfLocale` constants class so locale strings are never scattered.

Avoid using `dart:intl`'s default system locale which may differ per device — always pass the locale string explicitly. Ensure `initializeDateFormatting('nb_NO')` is awaited during app startup or lazily before first PDF generation. The font must be subset to avoid bloating the file — the dart_pdf package handles this automatically when you use `PdfTtfFont` with character subsetting enabled.

Testing Requirements

Unit tests (flutter_test) must cover: (1) date formatting — parametrized test with at least 6 date inputs verifying DD.MM.YYYY output including edge cases Jan 1 and Dec 31; (2) currency formatting — parametrized test covering zero, sub-threshold (49.00), threshold-boundary (50.00), and large values (12 345,67 kr); (3) character encoding — render a string containing all six Norwegian special characters and assert no replacement characters (U+FFFD) appear in the resulting PDF byte stream. One integration test should generate a full PDF from a mock activity dataset and open it through the printing package's rasteriser to visually assert glyph presence. Test coverage for the locale utility class must reach 100%.

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.