📊 InstaReports Notifications
📖 Overview
The InstaReports Notifications module handles notifications for the InstaReports automated reporting product, specifically monitoring build failures during report generation.
Environment Flag: INSTAREPORTS_ENABLED=true
Trigger Types:
- Change Stream on
InstaReportsBuildStatuscollection (build failures)
Notification Types: bell (FCM), browser push
Location: notifications/services/instareports/
🏗️ Architecture
System Flow
graph TB
subgraph "Trigger"
BUILD[Build Failure<br/>Status Insert]
end
subgraph "Processing"
DETECT[Detect Build Failure]
FETCH[Fetch User & Domain]
VERIFY[Verify Preferences]
CREATE[Create Notifications]
end
subgraph "Delivery"
BELL[Bell Notification]
BROWSER[Browser Push]
end
BUILD --> DETECT
DETECT --> FETCH
FETCH --> VERIFY
VERIFY --> CREATE
CREATE --> BELL
CREATE --> BROWSER
⚙️ Configuration
Environment Variables
# Module flag
INSTAREPORTS_ENABLED=true # Enable InstaReports notifications
# External dependencies (inherited)
GENERAL_SOCKET=http://localhost:4000 # For bell notifications
FIREBASE_CREDENTIALS=... # For browser push
Change Stream Configuration
const buildFailureStream = InstaReportsBuildStatus.watch(
[
{
$match: {
operationType: 'insert',
'fullDocument.status': 'failed',
},
},
],
{
fullDocument: 'updateLookup',
},
);
buildFailureStream.on('change', async data => {
await processFailedNotification(data);
});
Stream Filters:
- Only
insertoperations - Only build status records with
status: 'failed' - Excludes successful builds and in-progress builds
📧 Notification Templates
Build Failed
Trigger: InstaReport build/generation process fails
Type: bell, browser push
Recipients: Report creator
Notification Content:
{
title: "Instareport build failed",
body: "A instareport build is failed.",
click_action: "https://app.dashclicks.com/instareports/my-instareports",
module: "instareports",
type: "build_fail",
subType: "bell" // or "browser"
}
Typical Failure Reasons:
- Data source unavailable (API timeout)
- Insufficient permissions to access analytics data
- Template rendering error
- PDF generation failure
- Missing required metrics
🔍 Processing Logic
Build Failure Notification
// From services/instareports/failed-notifications.js
async function processFailedNotification(data) {
try {
const buildStatus = data.fullDocument;
// 1. Fetch user who created the report
const user = await User.findById(buildStatus.created_by);
if (!user) {
logger.warn({
message: 'User not found for InstaReport build failure',
build_status_id: buildStatus._id,
created_by: buildStatus.created_by,
});
return;
}
// 2. Get active domain for the account
const domainName = await getActiveDomain({
accountId: buildStatus.account_id?.toString(),
proto: true,
});
const baseURL = `${domainName}/instareports/my-instareports`;
// 3. Send bell notification
await processFCMv2({
verification: {
module: 'instareports',
type: 'build_fail',
subType: 'bell',
},
content: {
title: 'Instareport build failed',
body: 'A instareport build is failed.',
click_action: baseURL,
},
recipient: {
accountID: buildStatus.account_id,
users: [user._id],
},
user_check: true, // Verify user preferences
});
// 4. Send browser push notification
await processFCMv2({
verification: {
module: 'instareports',
type: 'build_fail',
subType: 'browser',
},
content: {
title: 'Instareport build failed',
body: 'A instareport build is failed.',
click_action: baseURL,
},
recipient: {
accountID: buildStatus.account_id,
users: [user._id],
},
user_check: true,
});
logger.info({
message: 'InstaReport build failure notification sent',
build_status_id: buildStatus._id,
user_id: user._id,
report_id: buildStatus.report_id,
});
} catch (err) {
logger.error({
initiator: 'notification/instareports/failed-notification',
message: 'Error in instareports failed notification',
error: err,
});
}
}
🚨 Error Handling
Change Stream Management
// Graceful shutdown
process.on('SIGINT', async () => {
logger.log({
initiator: 'notifications/instareports',
message: 'Closing InstaReports stream',
});
await buildFailureStream.close();
process.exit(0);
});
// Stream error handling
buildFailureStream.on('error', error => {
logger.error({
initiator: 'notifications/instareports/failed-stream',
message: 'Change stream error',
error: error,
});
});
// MongoDB connection monitoring
mongoose.connection.on('disconnected', () => {
logger.warn({
initiator: 'notifications/instareports',
message: 'MongoDB connection lost - stream will reconnect',
});
});
mongoose.connection.on('reconnected', () => {
logger.log({
initiator: 'notifications/instareports',
message: 'MongoDB reconnected - stream active',
});
});
💡 Examples
Example 1: Data Source Error
Trigger Event:
// InstaReportsBuildStatus insert
{
operationType: 'insert',
fullDocument: {
_id: ObjectId("507f1f77bcf86cd799439011"),
account_id: ObjectId("507f1f77bcf86cd799439012"),
report_id: ObjectId("507f1f77bcf86cd799439013"),
created_by: ObjectId("507f1f77bcf86cd799439014"),
status: "failed",
error_code: "DATA_SOURCE_UNAVAILABLE",
error_message: "Google Analytics API returned 401: Token expired",
build_duration: 15,
retry_count: 3,
created_at: new Date("2025-10-13T14:30:00Z")
}
}
Resulting Notifications:
- Bell - "Instareport build failed"
- Browser - Same content via web push
Expected User Action:
- Navigate to InstaReports dashboard
- Reconnect Google Analytics integration
- Retry report generation
Example 2: Template Rendering Error
Trigger Event:
// InstaReportsBuildStatus insert
{
operationType: 'insert',
fullDocument: {
_id: ObjectId("507f1f77bcf86cd799439011"),
account_id: ObjectId("507f1f77bcf86cd799439012"),
report_id: ObjectId("507f1f77bcf86cd799439013"),
created_by: ObjectId("507f1f77bcf86cd799439014"),
status: "failed",
error_code: "TEMPLATE_ERROR",
error_message: "Failed to render chart: Missing required metric 'sessions'",
build_duration: 32,
created_at: new Date("2025-10-13T14:30:00Z")
}
}
Resulting Notifications:
- Bell - "Instareport build failed"
- Browser - Same content via web push
Example 3: Successful Build (No Notification)
Trigger Event:
// InstaReportsBuildStatus insert with success
{
operationType: 'insert',
fullDocument: {
_id: ObjectId("507f1f77bcf86cd799439011"),
status: "completed", // NOT "failed"
build_duration: 45,
created_at: new Date("2025-10-13T14:30:00Z")
}
}
Result: No notification sent (filtered by change stream status: 'failed' matcher)
📈 Metrics
Key Metrics:
- Report generation success rate: ~92%
- Build failures per day: ~25
- Average report build time: 3-5 minutes
- Most common failure: API token expiration (40%)
Monitoring:
// Build failures today
db.getCollection('instareports.build_status').count({
status: 'failed',
created_at: { $gte: new Date(Date.now() - 24 * 60 * 60 * 1000) },
});
// Successful builds today
db.getCollection('instareports.build_status').count({
status: 'completed',
created_at: { $gte: new Date(Date.now() - 24 * 60 * 60 * 1000) },
});
// Failure reasons breakdown
db.getCollection('instareports.build_status').aggregate([
{
$match: {
status: 'failed',
created_at: { $gte: new Date(Date.now() - 24 * 60 * 60 * 1000) },
},
},
{ $group: { _id: '$error_code', count: { $sum: 1 } } },
{ $sort: { count: -1 } },
]);
// Notifications sent
db.getCollection('notifications.queue').count({
origin: 'instareports',
created_at: { $gte: new Date(Date.now() - 24 * 60 * 60 * 1000) },
});
🔧 Troubleshooting
Issue: Build failure notifications not received
Symptoms: Report build fails but user not notified
Diagnosis:
// 1. Verify build status record exists
db.getCollection('instareports.build_status').findOne({
report_id: ObjectId('report_id'),
status: 'failed',
});
// 2. Check user exists and is active
db.getCollection('users').findOne(
{
_id: ObjectId('user_id'),
},
{ name: 1, email: 1, status: 1 },
);
// 3. Verify change stream is running
// Check logs for: "InstaReports failed stream started"
// 4. Check notification preferences
db.getCollection('users').findOne(
{
_id: ObjectId('user_id'),
},
{ notification_preferences: 1 },
);
Solutions:
- Ensure
INSTAREPORTS_ENABLED=truein environment - Verify MongoDB replica set is properly configured
- Check Firebase credentials are valid
- Verify user has
instareportsnotifications enabled
Issue: Too many failure notifications
Symptoms: User receives multiple notifications for same report
Cause: Retry logic creating multiple build status records
Solutions:
- Implement deduplication based on
report_idand time window - Group failures by report and send digest
- Add cooldown period between notifications for same report
Enhanced Logic:
// Check for recent notification
const recentNotification = await NotificationQueue.findOne({
origin: 'instareports',
'content.data.report_id': buildStatus.report_id.toString(),
created_at: { $gte: new Date(Date.now() - 10 * 60 * 1000) }, // Last 10 minutes
});
if (recentNotification) {
logger.info({
message: 'Skipping duplicate failure notification',
report_id: buildStatus.report_id,
});
return;
}
Issue: Generic error message not helpful
Symptoms: Notification doesn't provide actionable information
Enhancement: Include error details in notification:
// Enhanced notification body
const errorSummary = getErrorSummary(buildStatus.error_code);
await processFCMv2({
content: {
title: 'Instareport build failed',
body: `Report generation failed: ${errorSummary}`,
click_action: baseURL,
},
// ... rest of config
});
function getErrorSummary(errorCode) {
const summaries = {
DATA_SOURCE_UNAVAILABLE: 'Data source connection failed',
TOKEN_EXPIRED: 'Please reconnect your integration',
TEMPLATE_ERROR: 'Report template issue',
PDF_GENERATION_ERROR: 'PDF creation failed',
INSUFFICIENT_PERMISSIONS: 'Missing data access permissions',
};
return summaries[errorCode] || 'Unknown error occurred';
}
🔗 Integration Points
InstaReports Product Integration
- Data Collection - Pulls from Google Analytics, Facebook, etc.
- Template Engine - Renders custom report templates
- PDF Generation - Creates downloadable PDFs
- Scheduling - Automated recurring reports
- White Label - Custom branding for reports
Queue Manager Integration
InstaReports builds are processed by Queue Manager:
- Build jobs queued with priority
- Status updates written to
InstaReportsBuildStatus - Failures trigger notification change stream
- Retry logic for transient failures
Analytics Integration Dependencies
Common failure points:
- Google Analytics API (token expiration)
- Facebook Ads API (permissions)
- Google Ads API (quota limits)
- Custom integrations (data format changes)
📊 Common Error Codes
| Error Code | Description | User Action |
|---|---|---|
DATA_SOURCE_UNAVAILABLE | API connection failed | Check integration status |
TOKEN_EXPIRED | OAuth token expired | Reconnect integration |
TEMPLATE_ERROR | Template rendering failed | Contact support |
PDF_GENERATION_ERROR | PDF creation failed | Retry build |
INSUFFICIENT_PERMISSIONS | Missing API permissions | Update integration permissions |
QUOTA_EXCEEDED | API rate limit hit | Wait and retry |
METRIC_NOT_FOUND | Required metric missing | Update report template |
Module Type: Change Stream
Environment Flag: INSTAREPORTS_ENABLED
Dependencies: MongoDB (replica set), Firebase (FCM)
Notification Channels: Bell, Browser Push (no email)
Primary Use Case: Automated reporting status monitoring
Status: Active - critical for reporting product reliability