Skip to main content

📊 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 InstaReportsBuildStatus collection (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 insert operations
  • 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:

  1. Bell - "Instareport build failed"
  2. 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:

  1. Bell - "Instareport build failed"
  2. 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=true in environment
  • Verify MongoDB replica set is properly configured
  • Check Firebase credentials are valid
  • Verify user has instareports notifications enabled

Issue: Too many failure notifications

Symptoms: User receives multiple notifications for same report

Cause: Retry logic creating multiple build status records

Solutions:

  1. Implement deduplication based on report_id and time window
  2. Group failures by report and send digest
  3. 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 CodeDescriptionUser Action
DATA_SOURCE_UNAVAILABLEAPI connection failedCheck integration status
TOKEN_EXPIREDOAuth token expiredReconnect integration
TEMPLATE_ERRORTemplate rendering failedContact support
PDF_GENERATION_ERRORPDF creation failedRetry build
INSUFFICIENT_PERMISSIONSMissing API permissionsUpdate integration permissions
QUOTA_EXCEEDEDAPI rate limit hitWait and retry
METRIC_NOT_FOUNDRequired metric missingUpdate 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

💬

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:31 AM