Wire CSV and PDF Generation into Edge Function Finalize Mode
epic-bufdir-report-export-core-backend-task-013 — Implement the finalize export path in the edge function that runs aggregation, serialization, then invokes either the CSV or PDF generation service based on the requested format. Upload the resulting binary to the Supabase export storage bucket under a deterministic path (org_id/year/period/filename). Record the export in the generated_reports repository with metadata (requested_by, scope, period, format, file_path, file_size, generated_at). Return a signed download URL valid for 24 hours.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 6 - 158 tasks
Can start after Tier 5 completes
Implementation Notes
Structure the finalize path as: (1) check idempotency via DB query, (2) run aggregation + serialization (reuse preview pipeline), (3) branch to CSV or PDF generator, (4) upload to storage with streaming, (5) insert generated_reports record + audit log in a single transaction, (6) generate signed URL, (7) return response. Implement rollback logic: wrap steps 4-5 in a try/catch; on step 5 failure, delete the uploaded file. For CSV, use Deno's std/csv for encoding. For PDF, evaluate pdf-lib (pure Deno compatible) — keep the PDF layout simple: header with org/period metadata, then a table of activity rows.
The deterministic path structure (org_id/year/period_slug/uuid.ext) ensures files are logically organised but UUID prevents guessing adjacent exports. Period slug format: YYYY-QN for quarterly, YYYY-HN for half-year, YYYY for annual.
Testing Requirements
Unit test CSV generation: provide known aggregated data, assert output is valid CSV with correct column order, BOM present, all rows encoded correctly, special characters escaped. Unit test PDF generation: assert output bytes start with %PDF, file is non-empty, and title metadata matches org/period. Integration test the full finalize pipeline: call edge function with format=csv, assert HTTP 200, download the signed URL and verify the file contents match the input data. Integration test idempotency: call the same export twice and assert the second call returns the same export_id with a new signed URL.
Test failure rollback: mock storage upload failure and assert no generated_reports record was created. Test audit log is created even on failure. Use Deno test with a real Supabase test project for integration scenarios.
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.
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.
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.