Skip to main content

Analytics

Overview​

The Analytics service provides comprehensive revenue and ROI metrics for managed services, calculating profits, retention rates, time savings, and cost savings based on active subscriptions and product configurations.

Source Files:

  • Service: internal/api/v1/projects/services/analytics.service.js
  • Controller: internal/api/v1/projects/controllers/analytics.controller.js
  • Utilities: internal/api/v1/projects/utils/analytics.js

Key Capabilities:

  • Calculate total and monthly profit from subscriptions
  • Compute average retention months
  • Calculate time saved based on product hours
  • Calculate cost savings based on hourly rates
  • Product-level breakdowns with month counts
  • Current month vs all-time comparisons

Collections Used​

_store.orders​

Operations: Read (aggregation)
Model: shared/models/store-order.js
Usage: Primary source for active order analytics

Key Fields:

{
_id: ObjectId,
status: 'active',
seller_account: ObjectId,
buyer_account: ObjectId,
subscription: ObjectId,
metadata: {
product_type: String,
product_name: String,
price_name: String,
images: [String]
},
acc_price: {
monthly_cost: Number
},
created_at: Date
}

_store.subscriptions​

Operations: Read (lookup)
Usage: Subscription details for profit and retention calculations

Key Fields:

{
_id: ObjectId,
plan: {
amount: Number,
nickname: String,
metadata: {
product_type: String
},
interval_count: Number
},
status: String, // 'active', 'trialing', 'past_due', 'canceled'
canceled_at: Number, // Unix timestamp (seconds)
created: Number, // Unix timestamp (seconds)
start_date: Number // Unix timestamp (seconds)
}

Business Logic & Functions​

Service Layer​

getAnalytics({ accountId })​

Purpose: Calculates comprehensive analytics metrics for an agency account's managed services.

Parameters:

  • accountId (ObjectId) - Seller/agency account ID

Returns: Analytics object with all calculated metrics

{
total_profit: Number, // Lifetime profit (cents)
this_month_profit: Number, // Current month profit (cents)
averageRetentionMonths: Number, // Average months retained
total_time_saved: Number, // Total hours saved
this_month_time_saved: Number, // Current month hours saved
total_cost_saving: Number, // Total cost saved (cents)
this_month_cost_saving: Number // Current month cost saved (cents)
}

Aggregation Pipeline Logic:

Stage 1: Match Active Orders

{
$match: {
status: 'active',
seller_account: accountId,
buyer_account: { $ne: null },
'metadata.product_type': { $in: MANAGED_SUBSCRIPTIONS }
}
}

Stage 2: Lookup Subscription

{
$lookup: {
from: '_store.subscriptions',
let: { subscription_id: '$subscription' },
pipeline: [
{ $match: { $expr: { $eq: ['$_id', '$$subscription_id'] } }},
{ $project: {
'plan.amount': 1,
'plan.nickname': 1,
'plan.metadata.product_type': 1,
'plan.interval_count': 1,
canceled_at: 1,
created: 1,
start_date: 1,
status: 1
}}
]
}
}

Stage 3: Calculate Product Metrics

{
$project: {
subscription: 1,
product: {
name: '$metadata.product_name',
nickname: '$metadata.price_name',
month_active: {
$ceil: {
$divide: [
{
$subtract: [
// Use canceled_at if exists, otherwise current time
{ $ifNull: [
{ $multiply: ['$subscription.canceled_at', 1000] },
{ $toLong: new Date().getTime() }
]},
{ $multiply: ['$subscription.start_date', 1000] }
]
},
2592000000 // 30 days in milliseconds
]
}
}
},
created_at: 1,

// Profit Calculation
profit: {
$cond: {
if: { $in: ['$subscription.status', ['active', 'trialing', 'past_due']] },
then: {
$subtract: [
{
$ifNull: [
{ $multiply: [
'$acc_price.monthly_cost',
'$subscription.plan.interval_count'
]},
'$subscription.plan.amount'
]
},
'$subscription.plan.amount'
]
},
else: 0 // Canceled subscriptions have 0 profit
}
},

// Retention Calculation
retentionMonths: {
$ceil: {
$divide: [
{
$subtract: [
{
$cond: [
{ $eq: ['$subscription.canceled_at', null] },
{ $toLong: new Date().getTime() },
{ $multiply: ['$subscription.canceled_at', 1000] }
]
},
{ $multiply: ['$subscription.created', 1000] }
]
},
2592000000 // 30 days in milliseconds
]
}
}
}
}

Profit Formula:

IF subscription is active/trialing/past_due:
profit = (acc_price.monthly_cost × interval_count || plan.amount) - plan.amount
ELSE:
profit = 0

Stage 4: Faceted Aggregation

{
$facet: {
// Overall metrics
data: [
{
$group: {
_id: null,
total_profit: { $sum: '$profit' },
monthly_profit: {
$sum: {
$cond: [
{
$and: [
{ $gte: [{ $toDate: '$created_at' }, startOfMonth] },
{ $lt: [{ $toDate: '$created_at' }, startOfNextMonth] }
]
},
'$profit',
0
]
}
},
averageRetentionMonths: { $avg: '$retentionMonths' }
}
},
{
$project: {
_id: 0,
total_profit: { $cond: { if: { $lt: ['$total_profit', 0] }, then: 0, else: '$total_profit' }},
this_month_profit: { $cond: { if: { $lt: ['$monthly_profit', 0] }, then: 0, else: '$monthly_profit' }},
averageRetentionMonths: {
$round: {
$cond: { if: { $lt: ['$averageRetentionMonths', 0] }, then: 0, else: '$averageRetentionMonths' }
}
}
}
}
],

// Product breakdown (all time)
products: [
{
$group: {
_id: { name: '$product.name', nickname: '$product.nickname' },
productCount: { $sum: 1 },
monthCount: { $sum: { $ifNull: ['$product.month_active', 0] }}
}
},
{
$project: {
_id: 0,
productName: '$_id.name',
nickname: '$_id.nickname',
productCount: 1,
monthCount: 1
}
}
],

// Product breakdown (current month)
this_month_products: [
{
$match: {
$expr: {
$and: [
// Subscription started before end of current month
{ $lt: [
'$subscription.start_date',
{ $divide: [{ $toLong: endOfMonth }, 1000] }
]},
{
$or: [
// Still active (not canceled)
{ $eq: ['$subscription.canceled_at', null] },
// Canceled but not in current month
{ $gte: [
'$subscription.canceled_at',
{ $divide: [{ $toLong: startOfMonth }, 1000] }
]}
]
}
]
}
}
},
{
$group: {
_id: { name: '$product.name', nickname: '$product.nickname' },
productCount: { $sum: 1 }
}
},
{
$project: {
_id: 0,
productName: '$_id.name',
nickname: '$_id.nickname',
productCount: 1
}
}
]
}
}

Stage 5: Calculate Time & Cost Savings

const totalTimeSaved = calculateHourSpent(analyticsResult.products);
const thisMonthtotalTimeSaved = calculateHourSpent(analyticsResult.this_month_products);
const totalCostsaving = calculateCost(analyticsResult.products) * 100;
const thisMonthCostsaving = calculateCost(analyticsResult.this_month_products) * 100;

return {
...analyticsResult.data[0],
total_time_saved: Math.max(0, Math.round(totalTimeSaved)),
this_month_time_saved: Math.max(0, Math.round(thisMonthtotalTimeSaved)),
total_cost_saving: Math.max(0, totalCostsaving),
this_month_cost_saving: Math.max(0, thisMonthCostsaving),
};

Utility Functions​

calculateHourSpent(products)​

Purpose: Calculates total hours spent based on product configurations and active months.

Parameters:

  • products (Array) - Product breakdown with counts and months

Returns: Total hours (Number)

Logic:

products.reduce((totalHours, { productName, nickname, productCount, monthCount }) => {
const productTierDetails = getProductTierDetails(productName, nickname);
if (!productTierDetails) return totalHours;

const { setupHours, monthlyHours } = productTierDetails;

// Monthly hours for all active months
const totalMonthlyHours = monthlyHours * (monthCount || 1);

// Setup hours for each product
const totalSetupHours = productCount * setupHours;

return totalHours + totalMonthlyHours + totalSetupHours;
}, 0);

Example:

5 Meta Ads Pro products:
- Setup: 5 products × 10 hours = 50 hours
- Monthly: 240 hours (varies by active months per product)
- Total: 290 hours

calculateCost(products)​

Purpose: Calculates total cost savings based on hourly rates and time spent.

Parameters:

  • products (Array) - Product breakdown with counts and months

Returns: Total cost (Number, in dollars)

Logic:

products.reduce((totalCost, { productName, nickname, productCount, monthCount }) => {
const productTierDetails = getProductTierDetails(productName, nickname);
if (!productTierDetails) return totalCost;

const { totalSetup, totalMonthly } = productTierDetails;

// Monthly cost for all active months
const totalMonthlyCost = totalMonthly * (monthCount || 1);

// Setup cost for each product
const totalSetupCost = productCount * totalSetup;

return totalCost + totalMonthlyCost + totalSetupCost;
}, 0);

Example:

5 Meta Ads Pro products:
- Setup: 5 × $400 = $2,000
- Monthly: $9,600 (varies by active months per product)
- Total: $11,600

getProductTierDetails(productName, tierName)​

Purpose: Retrieves hourly rates and costs for specific product/tier combination.

Parameters:

  • productName (String) - Product name (e.g., "Meta Ads")
  • tierName (String) - Tier name (e.g., "Pro", "Plus", "Platinum")

Returns: Tier details object or null

Product Configuration:

{
name: "Meta Ads",
tiers: {
"Pro": {
setupHours: 10,
monthlyHours: 15,
hourlyRate: 40,
totalSetup: 400,
totalMonthly: 600,
totalCombined: 1000
},
"Plus": { setupHours: 14, monthlyHours: 21, ... },
"Platinum": { setupHours: 18, monthlyHours: 27, ... }
}
}

Supported Products:

  • Meta Ads (Pro, Plus, Platinum)
  • Google Ads (Pro, Plus, Platinum)
  • TikTok Ads (Pro, Plus, Platinum)
  • SEO (Pro, Plus, Platinum)
  • Backlinks (Pro, Plus, Platinum)
  • GBP Ranker (Pro, Plus, Platinum)
  • Content (Pro, Plus, Platinum)
  • Social Posts (Pro, Plus, Platinum)
  • Websites (Information, E-Commerce Pro/Plus/Platinum)
  • Listings (Pro)

Controller Layer​

getAnalytics(req, res)​

Route: GET /api/projects/analytics

Authorization: Requires authentication

Response:

{
success: true,
message: 'SUCCESS',
data: {
total_profit: 150000,
this_month_profit: 12000,
averageRetentionMonths: 8,
total_time_saved: 1250,
this_month_time_saved: 105,
total_cost_saving: 5000000,
this_month_cost_saving: 420000
}
}

Data Flow Diagram​

flowchart TD
A[GET /analytics] --> B[Match Active Orders]
B --> C[Lookup Subscriptions]
C --> D[Calculate Product Metrics]
D --> E[Calculate Profit]
E --> F[Calculate Retention Months]
F --> G[Faceted Aggregation]
G --> H[Group Overall Metrics]
G --> I[Group All-Time Products]
G --> J[Group Current Month Products]
H --> K[Ensure Non-Negative Values]
I --> L[Calculate Time Saved - All Time]
J --> M[Calculate Time Saved - Current Month]
L --> N[Calculate Cost Savings - All Time]
M --> O[Calculate Cost Savings - Current Month]
K --> P[Merge All Results]
N --> P
O --> P
P --> Q[Return Analytics Data]

Integration Points​

Internal Dependencies​

  • MANAGED_SUBSCRIPTIONS - Service type list
  • calculateHourSpent utility - Time calculation
  • calculateCost utility - Cost calculation
  • getProductTierDetails utility - Product configuration lookup
  • catchAsync - Error handling

Product Configuration​

  • HOURLY_RATE_AND_COST - Product/tier configuration array
  • SUBSCRIPTION_TIERS - Tier name constants
  • PRODUCTS - Product name constants

Key Metrics Explained​

Profit Calculation​

For active/trialing/past_due subscriptions:
profit = revenue - cost
revenue = acc_price.monthly_cost × interval_count (or plan.amount as fallback)
cost = subscription.plan.amount

For canceled subscriptions:
profit = 0

Retention Months​

retentionMonths = ceil((end_date - created_date) / 30_days)

where end_date is:
- canceled_at (if subscription canceled)
- current date (if subscription active)

Month Active​

month_active = ceil((end_date - start_date) / 30_days)

where end_date is:
- canceled_at (if subscription canceled)
- current date (if subscription active)

Time Saved​

For each product:
setup_time = productCount × setupHours
monthly_time = monthCount × monthlyHours
total = setup_time + monthly_time

Cost Savings​

For each product:
setup_cost = productCount × totalSetup
monthly_cost = monthCount × totalMonthly
total = setup_cost + monthly_cost

Note: Returned in cents (× 100)

Important Notes​

  • 💰 Currency: All monetary values in cents (divide by 100 for dollars)
  • 📊 Active Only: Only counts orders with status: 'active'
  • ⏰ 30-Day Months: Uses 2592000000ms (30 days) for month calculations
  • 🔢 Ceiling Function: Months always rounded up to nearest integer
  • ✅ Non-Negative: All final values ensured to be ≥ 0
  • 📅 Current Month: Calculated using new Date().getFullYear() and getMonth()
  • 🔄 Faceted Aggregation: Parallel calculation of all metrics for performance
  • 🏷️ Product Tiers: Matches product_name + price_name to tier configuration

Last Updated: 2025-10-08
Service Files: services/analytics.service.js, controllers/analytics.controller.js, utils/analytics.js
Primary Functions: 1 service function, 3 utility functions, 1 controller endpoint

💬

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