Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions backend/docs/specs/monthly_report/checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Checklist

- [x] `pdfkit`, `nodemailer`, `node-cron` installed.
- [x] `reportService.js` implemented and generating valid PDFs.
- [x] `monthlyReportJob.js` scheduling correctly (1st of month).
- [x] Email sending functionality verified (mocked or tested).
- [x] Report contains correct data aggregation (tokens claimed per employee).
- [x] Environment variables documented in `.env.example`.
- [x] Unit tests passing.
34 changes: 34 additions & 0 deletions backend/docs/specs/monthly_report/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Monthly Claims Report Specification

## Overview
This feature implements a monthly PDF report that summarizes token claims by employees. The report is automatically generated and emailed to the DAO Admin on the 1st of every month.

## Requirements
1. **PDF Generation**: Use `pdfkit` to generate a PDF document.
2. **Scheduling**: Use `node-cron` to schedule the task for the 1st of every month.
3. **Email Delivery**: Use `nodemailer` to send the PDF as an email attachment.
4. **Content**: The report must show the total tokens claimed by employees in the previous month.

## Architecture
### New Components
1. **`src/services/reportService.js`**: Responsible for querying claim data and generating the PDF.
2. **`src/jobs/monthlyReportJob.js`**: Responsible for scheduling the monthly execution and triggering the email service.
3. **Email Configuration**: Add environment variables for email service credentials.

### Data Flow
1. Cron job triggers on the 1st of the month.
2. `reportService` queries `ClaimsHistory` for claims in the previous month.
3. `reportService` aggregates the data (total claimed per user/token).
4. `reportService` generates a PDF stream/buffer.
5. `nodemailer` sends an email with the PDF attached to the DAO Admin.

## Database
- **Table**: `claims_history`
- **Query**: Select claims where `claim_timestamp` is within the previous month range.

## Configuration
New environment variables:
- `EMAIL_SERVICE`: The email service provider (e.g., 'gmail').
- `EMAIL_USER`: The email address used to send the report.
- `EMAIL_PASS`: The password or app password for the email account.
- `DAO_ADMIN_EMAIL`: The recipient email address for the report.
13 changes: 13 additions & 0 deletions backend/docs/specs/monthly_report/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Tasks

1. [x] Install dependencies: `pdfkit`, `nodemailer`, `node-cron`.
2. [x] Create `src/services/reportService.js` with methods to:
- Fetch monthly claim data from `ClaimsHistory`.
- Generate a PDF summary using `pdfkit`.
3. [x] Create `src/jobs/monthlyReportJob.js` to:
- Schedule the task using `node-cron`.
- Configure `nodemailer` transporter.
- Send the email with the generated PDF.
4. [x] Update `src/index.js` to initialize the cron job on server start.
5. [x] Update `.env.example` with new email configuration variables.
6. [x] Add unit tests for `reportService`.
159 changes: 159 additions & 0 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"graphql-ws": "^5.14.3",
"node-cron": "^4.2.1",
"nodemailer": "^8.0.1",
"pdfkit": "^0.17.2",
"pg": "^8.11.3",
"redis": "^4.6.12",
"sequelize": "^6.35.2",
Expand Down
8 changes: 8 additions & 0 deletions backend/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,14 @@ const startServer = async () => {
console.log('Continuing without Discord bot...');
}

// Initialize Monthly Report Job
try {
monthlyReportJob.start();
} catch (jobError) {
console.error('Failed to initialize Monthly Report Job:', jobError);
}

// Start the HTTP server
httpServer.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
console.log(`REST API available at: http://localhost:${PORT}`);
Expand Down
Loading