Skip to content

feat: campaign analytics report export to pdf - #775

Merged
dotunv merged 1 commit into
Savitura:mainfrom
Stanley-Owoh:campaign-analytics-report-export-to-pdf-765
Aug 31, 2026
Merged

feat: campaign analytics report export to pdf#775
dotunv merged 1 commit into
Savitura:mainfrom
Stanley-Owoh:campaign-analytics-report-export-to-pdf-765

Conversation

@Stanley-Owoh

Copy link
Copy Markdown

feat: Campaign analytics report export to PDF

Overview

Adds campaign creator analytics export to PDF, complementing the existing CSV export (#408). Creators can now generate a polished, printable financial and engagement report for their campaign, and share it via an expiring signed URL.

Changes

Backend

New: backend/src/services/campaignReportService.js

  • Assembles all report data in a single payload via parallel DB queries: campaign summary, financials (raised vs goal, platform fees, net received, average/largest contribution), engagement (total contributions, unique contributors, asset breakdown), top contributors (wallet keys truncated for privacy), milestone status, and status-change timeline.
  • Signed URL generation/verification: HMAC-signed, expiring (24h), and bound to the campaign id. Verification uses constant-time comparison with explicit length checks.

New: backend/src/services/campaignReportPdf.js

  • Renders the report to PDF with pdfkit, including: campaign summary, raised vs goal (with progress bar), fee breakdown, contributor count, top contributors, milestone status, and funding/status timeline.
  • streamCampaignReportPdf pipes PDF bytes directly to the HTTP response (no large in-memory buffer) as required by the issue.
  • Handles an empty campaign gracefully (no contributors / no milestones → placeholder text).
  • generateCampaignReportPdfBuffer provided for tests / object-storage flows.

backend/src/routes/campaigns.js — new routes:

  • GET /api/campaigns/:id/report/export — streams a PDF attachment; requires authentication and owner (or admin) membership.
  • GET /api/campaigns/:id/report/share — returns an expiring signed share URL; requires authentication and owner (or admin) membership.
  • GET /api/campaigns/:id/report/share/:token — serves the PDF via a validated signed token (shareable link, no auth required, token-expiry enforced).

backend/package.json — added pdfkit dependency.

Frontend

  • frontend/src/pages/CreatorCampaignAnalytics.jsx — added a "Download Report" button beside the existing CSV export, with loading state.
  • frontend/src/services/api.js — added exportCampaignReport() blob download helper.

Tests

New: backend/src/services/campaignReportService.test.js

  • Report assembly (financials, milestones, top contributors)
  • Empty campaign handled gracefully
  • Signed URL generation and validation
  • Expired token rejection
  • Tampered signature rejection
  • Wrong-campaign token rejection

backend/src/routes/campaigns.test.js — added route coverage:

  • Owner streams PDF (200, correct headers/body)
  • Non-owner rejected (403)
  • Auth required (401)
  • Signed URL generation endpoint
  • Valid signed token serves PDF
  • Invalid/expired token rejected (403)

All backend tests pass (39 tests).

Closes #765

@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@Stanley-Owoh Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@dotunv
dotunv merged commit 6ee5bfa into Savitura:main Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Campaign analytics report export to PDF

2 participants