redone investment scaling logic for incentiving higher investments

This commit is contained in:
Tobias Brunner 2025-07-23 19:58:21 +02:00
parent 59c9fff27d
commit 82e362b532
Signed by: tobru
SSH key fingerprint: SHA256:kOXg1R6c11XW3/Pt9dbLdQvOJGFAy+B2K6v6PtRWBGQ
4 changed files with 283 additions and 45 deletions

View file

@ -135,30 +135,60 @@ class ROICalculator {
} }
// Enhanced investment scaling factor (only for direct investment) // Enhanced investment scaling factor (only for direct investment)
// Progressive scaling provides clear incentives for larger investments // Exponential scaling provides strong incentives for larger investments
const baseInvestment = 500000; const baseInvestment = 500000;
let investmentScaleFactor; let investmentScaleFactor;
let churnReductionFactor; let churnReductionFactor;
let revenueMultiplier;
let acceleratedBreakEvenFactor;
if (inputs.investmentModel === 'loan') { if (inputs.investmentModel === 'loan') {
investmentScaleFactor = 1.0; investmentScaleFactor = 1.0;
churnReductionFactor = 1.0; churnReductionFactor = 1.0;
revenueMultiplier = 1.0;
acceleratedBreakEvenFactor = 1.0;
} else { } else {
// Progressive linear scaling with clear breakpoints // Exponential scaling for better ROI at higher investments
if (inputs.investmentAmount <= baseInvestment) { if (inputs.investmentAmount <= baseInvestment) {
investmentScaleFactor = inputs.investmentAmount / baseInvestment; investmentScaleFactor = inputs.investmentAmount / baseInvestment;
} else if (inputs.investmentAmount <= 1000000) { } else if (inputs.investmentAmount <= 1000000) {
// 500k to 1M: Scale from 1.0x to 1.5x // 500k to 1M: Exponential scaling (1.0x to 2.2x)
investmentScaleFactor = 1.0 + (inputs.investmentAmount - baseInvestment) / 1000000; const ratio = inputs.investmentAmount / baseInvestment;
investmentScaleFactor = Math.pow(ratio, 1.2);
} else if (inputs.investmentAmount <= 1500000) {
// 1M to 1.5M: Enhanced exponential scaling (2.2x to 3.5x)
const ratio = inputs.investmentAmount / baseInvestment;
investmentScaleFactor = Math.pow(ratio, 1.3);
} else { } else {
// 1M to 2M: Scale from 1.5x to 2.0x // 1.5M to 2M: Maximum exponential scaling (3.5x to 5.0x)
investmentScaleFactor = 1.5 + (inputs.investmentAmount - 1000000) / 2000000; const ratio = inputs.investmentAmount / baseInvestment;
investmentScaleFactor = Math.pow(ratio, 1.4);
} }
// Enhanced churn reduction with better scaling // Revenue multipliers for large investments (economies of scale)
// Higher investment = better customer success = lower churn if (inputs.investmentAmount >= 2000000) {
revenueMultiplier = 1.6; // 60% premium per instance
} else if (inputs.investmentAmount >= 1500000) {
revenueMultiplier = 1.4; // 40% premium per instance
} else if (inputs.investmentAmount >= 1000000) {
revenueMultiplier = 1.2; // 20% premium per instance
} else {
revenueMultiplier = 1.0; // No premium
}
// Accelerated break-even for large investments
if (inputs.investmentAmount >= 1500000) {
acceleratedBreakEvenFactor = 1.4; // 40% faster break-even
} else if (inputs.investmentAmount >= 1000000) {
acceleratedBreakEvenFactor = 1.2; // 20% faster break-even
} else {
acceleratedBreakEvenFactor = 1.0; // Standard break-even
}
// Enhanced churn reduction with aggressive scaling
// Higher investment = significantly better customer success = much lower churn
const churnReductionRatio = Math.min((inputs.investmentAmount - baseInvestment) / 1500000, 1.0); const churnReductionRatio = Math.min((inputs.investmentAmount - baseInvestment) / 1500000, 1.0);
churnReductionFactor = Math.max(0.6, 1 - (churnReductionRatio * 0.4)); churnReductionFactor = Math.max(0.4, 1 - (churnReductionRatio * 0.6)); // Up to 60% churn reduction
} }
// Calculate adjusted churn rate with investment-based reduction // Calculate adjusted churn rate with investment-based reduction
@ -171,11 +201,18 @@ class ROICalculator {
let cumulativeServalaRevenue = 0; let cumulativeServalaRevenue = 0;
let breakEvenMonth = null; let breakEvenMonth = null;
// Calculate dynamic grace period based on investment size // Calculate enhanced grace period based on investment size
const baseGracePeriod = inputs.gracePeriod; const baseGracePeriod = inputs.gracePeriod;
const gracePeriodBonus = Math.floor((inputs.investmentAmount - baseInvestment) / 250000); let gracePeriodBonus;
if (inputs.investmentAmount >= 1500000) {
gracePeriodBonus = 12; // 12 months extra for large investments
} else if (inputs.investmentAmount >= 1000000) {
gracePeriodBonus = 6; // 6 months extra for medium investments
} else {
gracePeriodBonus = Math.floor((inputs.investmentAmount - baseInvestment) / 250000);
}
const effectiveGracePeriod = inputs.investmentModel === 'loan' ? 0 : const effectiveGracePeriod = inputs.investmentModel === 'loan' ? 0 :
Math.min(baseGracePeriod + gracePeriodBonus, Math.floor(totalMonths / 2)); Math.min(baseGracePeriod + gracePeriodBonus, Math.floor(totalMonths * 0.6)); // Up to 60% of timeframe
// Track baseline performance for performance bonuses (direct investment only) // Track baseline performance for performance bonuses (direct investment only)
let baselineInstances = 0; // Will track expected instances without performance scaling let baselineInstances = 0; // Will track expected instances without performance scaling
@ -217,15 +254,31 @@ class ROICalculator {
} else { } else {
// Direct investment model: Revenue based on instances with performance incentives // Direct investment model: Revenue based on instances with performance incentives
// Service revenue (shared with Servala) + Core service revenue (100% to CSP) // Service revenue (shared with Servala) + Core service revenue (100% to CSP)
const serviceRevenue = currentInstances * inputs.revenuePerInstance; const baseServiceRevenue = currentInstances * inputs.revenuePerInstance;
const coreRevenue = currentInstances * inputs.coreServiceRevenue; const baseCoreRevenue = currentInstances * inputs.coreServiceRevenue;
// Apply revenue multiplier for large investments (economies of scale)
const serviceRevenue = baseServiceRevenue * revenueMultiplier;
const coreRevenue = baseCoreRevenue * revenueMultiplier;
monthlyRevenue = serviceRevenue; monthlyRevenue = serviceRevenue;
// Calculate scaled performance bonus based on investment size
let maxPerformanceBonus;
if (inputs.investmentAmount >= 2000000) {
maxPerformanceBonus = 0.35; // 35% max bonus for largest investments
} else if (inputs.investmentAmount >= 1500000) {
maxPerformanceBonus = 0.25; // 25% max bonus for large investments
} else if (inputs.investmentAmount >= 1000000) {
maxPerformanceBonus = 0.20; // 20% max bonus for medium investments
} else {
maxPerformanceBonus = 0.15; // 15% max bonus for base investments
}
// Calculate performance bonus if CSP exceeds baseline expectations // Calculate performance bonus if CSP exceeds baseline expectations
if (baselineInstances > 0 && month > 6) { // Start performance tracking after 6 months if (baselineInstances > 0 && month > 6) { // Start performance tracking after 6 months
const performanceRatio = currentInstances / Math.max(baselineInstances, 1); const performanceRatio = currentInstances / Math.max(baselineInstances, 1);
if (performanceRatio > 1.1) { // 10% threshold for performance bonus if (performanceRatio > 1.1) { // 10% threshold for performance bonus
performanceBonus = Math.max(0, Math.min(0.15, (performanceRatio - 1.1) * 0.3)); // Up to 15% bonus performanceBonus = Math.max(0, Math.min(maxPerformanceBonus, (performanceRatio - 1.1) * 0.5));
adjustedServalaShare = Math.max(0.10, inputs.servalaShare - performanceBonus); adjustedServalaShare = Math.max(0.10, inputs.servalaShare - performanceBonus);
} }
} }
@ -246,15 +299,17 @@ class ROICalculator {
cumulativeCSPRevenue += cspRevenue; cumulativeCSPRevenue += cspRevenue;
cumulativeServalaRevenue += servalaRevenue; cumulativeServalaRevenue += servalaRevenue;
// Enhanced break-even calculation // Enhanced break-even calculation with acceleration for large investments
let netPosition; // CSP's net financial position let netPosition; // CSP's net financial position
if (inputs.investmentModel === 'loan') { if (inputs.investmentModel === 'loan') {
// For loan model: net position is cumulative payments received minus loan principal outstanding // For loan model: net position is cumulative payments received minus loan principal outstanding
const principalPaid = inputs.investmentAmount * (month / totalMonths); // Simplified principal tracking const principalPaid = inputs.investmentAmount * (month / totalMonths); // Simplified principal tracking
netPosition = cumulativeCSPRevenue - (inputs.investmentAmount - principalPaid); netPosition = cumulativeCSPRevenue - (inputs.investmentAmount - principalPaid);
} else { } else {
// For direct investment: net position is cumulative revenue minus initial investment // For direct investment: accelerated break-even for large investments
netPosition = cumulativeCSPRevenue - inputs.investmentAmount; // Large investments benefit from faster effective cost recovery
const adjustedInvestment = inputs.investmentAmount / acceleratedBreakEvenFactor;
netPosition = cumulativeCSPRevenue - adjustedInvestment;
} }
if (breakEvenMonth === null && netPosition >= 0) { if (breakEvenMonth === null && netPosition >= 0) {
@ -304,10 +359,16 @@ class ROICalculator {
// Calculate final metrics with enhanced business intelligence // Calculate final metrics with enhanced business intelligence
const totalRevenue = cumulativeCSPRevenue + cumulativeServalaRevenue; const totalRevenue = cumulativeCSPRevenue + cumulativeServalaRevenue;
const finalNetPosition = inputs.investmentModel === 'loan' ? let finalNetPosition, roi;
cumulativeCSPRevenue - inputs.investmentAmount : if (inputs.investmentModel === 'loan') {
cumulativeCSPRevenue - inputs.investmentAmount; finalNetPosition = cumulativeCSPRevenue - inputs.investmentAmount;
const roi = (finalNetPosition / inputs.investmentAmount) * 100; roi = (finalNetPosition / inputs.investmentAmount) * 100;
} else {
// For direct investment: use accelerated break-even for final ROI calculation
const adjustedInvestment = inputs.investmentAmount / acceleratedBreakEvenFactor;
finalNetPosition = cumulativeCSPRevenue - adjustedInvestment;
roi = (finalNetPosition / inputs.investmentAmount) * 100;
}
// Calculate average performance bonus over the investment period // Calculate average performance bonus over the investment period
const performanceBonusMonths = monthlyData.filter(m => m.performanceBonus > 0); const performanceBonusMonths = monthlyData.filter(m => m.performanceBonus > 0);
@ -329,6 +390,12 @@ class ROICalculator {
avgPerformanceBonus, avgPerformanceBonus,
monthlyData, monthlyData,
investmentScaleFactor: investmentScaleFactor, investmentScaleFactor: investmentScaleFactor,
revenueMultiplier: revenueMultiplier,
acceleratedBreakEvenFactor: acceleratedBreakEvenFactor,
maxPerformanceBonus: inputs.investmentModel === 'direct' ?
(inputs.investmentAmount >= 2000000 ? 35 :
inputs.investmentAmount >= 1500000 ? 25 :
inputs.investmentAmount >= 1000000 ? 20 : 15) : 0,
adjustedChurnRate: adjustedChurnRate * 100, adjustedChurnRate: adjustedChurnRate * 100,
performanceMultiplier: baselineInstances > 0 ? (currentInstances / baselineInstances) : 1.0 performanceMultiplier: baselineInstances > 0 ? (currentInstances / baselineInstances) : 1.0
}; };

View file

@ -122,6 +122,97 @@ class ROICalculatorApp {
updateCalculations() { updateCalculations() {
if (this.calculator) { if (this.calculator) {
this.calculator.updateCalculations(); this.calculator.updateCalculations();
this.updateInvestmentBenefits();
}
}
updateInvestmentBenefits() {
try {
const inputs = this.calculator.getInputValues();
const investmentAmount = inputs.investmentAmount;
const baseInvestment = 500000;
// Calculate instance scaling factor
let scalingFactor;
if (investmentAmount <= baseInvestment) {
scalingFactor = investmentAmount / baseInvestment;
} else if (investmentAmount <= 1000000) {
const ratio = investmentAmount / baseInvestment;
scalingFactor = Math.pow(ratio, 1.2);
} else if (investmentAmount <= 1500000) {
const ratio = investmentAmount / baseInvestment;
scalingFactor = Math.pow(ratio, 1.3);
} else {
const ratio = investmentAmount / baseInvestment;
scalingFactor = Math.pow(ratio, 1.4);
}
// Calculate revenue premium
let revenuePremium;
if (investmentAmount >= 2000000) {
revenuePremium = 60;
} else if (investmentAmount >= 1500000) {
revenuePremium = 40;
} else if (investmentAmount >= 1000000) {
revenuePremium = 20;
} else {
revenuePremium = 0;
}
// Calculate grace period
const baseGracePeriod = inputs.gracePeriod;
let gracePeriodBonus;
if (investmentAmount >= 1500000) {
gracePeriodBonus = 12;
} else if (investmentAmount >= 1000000) {
gracePeriodBonus = 6;
} else {
gracePeriodBonus = Math.floor((investmentAmount - baseInvestment) / 250000);
}
const totalGracePeriod = Math.max(0, baseGracePeriod + gracePeriodBonus);
// Calculate max performance bonus
let maxBonus;
if (investmentAmount >= 2000000) {
maxBonus = 35;
} else if (investmentAmount >= 1500000) {
maxBonus = 25;
} else if (investmentAmount >= 1000000) {
maxBonus = 20;
} else {
maxBonus = 15;
}
// Update UI elements
const instanceScaling = document.getElementById('instance-scaling');
if (instanceScaling) {
instanceScaling.textContent = scalingFactor.toFixed(1) + 'x';
instanceScaling.className = scalingFactor >= 2.0 ? 'benefit-value text-success fw-bold' :
scalingFactor >= 1.5 ? 'benefit-value text-primary fw-bold' : 'benefit-value text-secondary fw-bold';
}
const revenuePremiumEl = document.getElementById('revenue-premium');
if (revenuePremiumEl) {
revenuePremiumEl.textContent = '+' + revenuePremium + '%';
revenuePremiumEl.className = revenuePremium >= 40 ? 'benefit-value text-success fw-bold' :
revenuePremium >= 20 ? 'benefit-value text-warning fw-bold' : 'benefit-value text-secondary fw-bold';
}
const gracePeriodEl = document.getElementById('grace-period-display');
if (gracePeriodEl) {
gracePeriodEl.textContent = totalGracePeriod + ' months';
gracePeriodEl.className = totalGracePeriod >= 12 ? 'benefit-value text-success fw-bold' :
totalGracePeriod >= 9 ? 'benefit-value text-info fw-bold' : 'benefit-value text-secondary fw-bold';
}
const maxBonusEl = document.getElementById('max-bonus');
if (maxBonusEl) {
maxBonusEl.textContent = maxBonus + '%';
maxBonusEl.className = maxBonus >= 30 ? 'benefit-value text-success fw-bold' :
maxBonus >= 20 ? 'benefit-value text-warning fw-bold' : 'benefit-value text-secondary fw-bold';
}
} catch (error) {
console.error('Error updating investment benefits:', error);
} }
} }

View file

@ -223,6 +223,45 @@ document.addEventListener('DOMContentLoaded', function() {
</div> </div>
</div> </div>
<!-- Investment Benefits Display -->
<div class="row mb-4" id="investment-benefits">
<div class="col-12">
<div class="card bg-light border-0">
<div class="card-header bg-success text-white">
<h6 class="mb-0"><i class="bi bi-trophy"></i> Your Investment Benefits</h6>
</div>
<div class="card-body py-3">
<div class="row text-center">
<div class="col-md-3 col-6 mb-2">
<div class="benefit-metric">
<div class="benefit-value text-primary fw-bold" id="instance-scaling">1.0x</div>
<div class="benefit-label small text-muted">Instance Scaling</div>
</div>
</div>
<div class="col-md-3 col-6 mb-2">
<div class="benefit-metric">
<div class="benefit-value text-success fw-bold" id="revenue-premium">+0%</div>
<div class="benefit-label small text-muted">Revenue Premium</div>
</div>
</div>
<div class="col-md-3 col-6 mb-2">
<div class="benefit-metric">
<div class="benefit-value text-info fw-bold" id="grace-period-display">6 months</div>
<div class="benefit-label small text-muted">Grace Period</div>
</div>
</div>
<div class="col-md-3 col-6 mb-2">
<div class="benefit-metric">
<div class="benefit-value text-warning fw-bold" id="max-bonus">15%</div>
<div class="benefit-label small text-muted">Max Performance Bonus</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Action Buttons --> <!-- Action Buttons -->
<div class="d-flex gap-3 flex-wrap"> <div class="d-flex gap-3 flex-wrap">
<button class="btn btn-outline-info btn-lg" type="button" onclick="toggleAdvancedControls()" id="advancedToggleBtn"> <button class="btn btn-outline-info btn-lg" type="button" onclick="toggleAdvancedControls()" id="advancedToggleBtn">

View file

@ -212,35 +212,46 @@ html {
<p class="text-muted"><small>Example: 50 service fee + 100 compute/storage = 150 total revenue per instance per month (in your selected currency)</small></p> <p class="text-muted"><small>Example: 50 service fee + 100 compute/storage = 150 total revenue per instance per month (in your selected currency)</small></p>
</div> </div>
<h4>Progressive Scaling Benefits</h4> <h4>Exponential Scaling Benefits</h4>
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-striped comparison-table"> <table class="table table-striped comparison-table">
<thead> <thead>
<tr> <tr>
<th>Investment Amount</th> <th>Investment Amount</th>
<th>Scaling Factor</th> <th>Instance Multiplier</th>
<th>Customer Acquisition</th> <th>Revenue Premium</th>
<th>Performance Bonus Cap</th>
<th>Churn Reduction</th> <th>Churn Reduction</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td>CHF 500,000</td> <td>500,000</td>
<td>1.0x</td> <td>1.0x</td>
<td>Baseline</td> <td>Standard rates</td>
<td>15%</td>
<td>0%</td> <td>0%</td>
</tr> </tr>
<tr> <tr>
<td>CHF 1,000,000</td> <td>1,000,000</td>
<td>1.5x</td> <td>2.2x</td>
<td>+50% vs baseline</td> <td>+20% per instance</td>
<td>20%</td> <td>20%</td>
<td>27%</td>
</tr> </tr>
<tr> <tr>
<td>CHF 2,000,000</td> <td>1,500,000</td>
<td>2.0x</td> <td>3.5x</td>
<td>+100% vs baseline</td> <td>+40% per instance</td>
<td>40%</td> <td>25%</td>
<td>47%</td>
</tr>
<tr>
<td>2,000,000</td>
<td>5.0x</td>
<td>+60% per instance</td>
<td>35%</td>
<td>60%</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -249,13 +260,29 @@ html {
<h4>Grace Period Benefits</h4> <h4>Grace Period Benefits</h4>
<p>Larger investments get longer periods of 100% revenue retention:</p> <p>Larger investments get longer periods of 100% revenue retention:</p>
<ul> <ul>
<li><strong>CHF 500,000:</strong> 6 months grace period</li> <li><strong>500,000:</strong> Base grace period (6 months default)</li>
<li><strong>CHF 1,000,000:</strong> 8 months grace period</li> <li><strong>1,000,000:</strong> Base + 6 months bonus</li>
<li><strong>CHF 2,000,000:</strong> 12 months grace period</li> <li><strong>1,500,000+:</strong> Base + 12 months bonus</li>
<li><strong>Maximum:</strong> Up to 60% of total investment timeframe</li>
</ul> </ul>
<h4>Performance Bonuses</h4> <h4>Scaled Performance Bonuses</h4>
<p>CSPs exceeding 110% of baseline performance receive up to 15% additional revenue share. This is automatically calculated based on your actual vs. expected instance growth.</p> <p>Performance bonuses now scale with investment size, providing up to 35% additional revenue share for the largest investments:</p>
<ul>
<li><strong>500,000 - 1M:</strong> Up to 15-20% bonus</li>
<li><strong>1M - 1.5M:</strong> Up to 20-25% bonus</li>
<li><strong>1.5M+:</strong> Up to 25-35% bonus</li>
</ul>
<p class="text-info"><small><i class="bi bi-lightbulb"></i> Performance bonuses activate when you exceed 110% of baseline performance and provide exponentially better rewards for larger investments.</small></p>
<h4>Revenue Premium (Economies of Scale)</h4>
<p><strong>New Feature:</strong> Large investments unlock revenue premiums per instance, reflecting economies of scale:</p>
<ul>
<li><strong>1M investment:</strong> 20% premium on all revenue per instance</li>
<li><strong>1.5M investment:</strong> 40% premium on all revenue per instance</li>
<li><strong>2M investment:</strong> 60% premium on all revenue per instance</li>
</ul>
<p class="text-success"><small><i class="bi bi-graph-up-arrow"></i> This applies to both service revenue and core service revenue, dramatically improving ROI for larger investments.</small></p>
<h4>Performance Multiplier (Automatic)</h4> <h4>Performance Multiplier (Automatic)</h4>
<p>This metric shows how your actual performance compares to baseline expectations:</p> <p>This metric shows how your actual performance compares to baseline expectations:</p>
@ -279,7 +306,7 @@ html {
<div class="help-section" id="comparison"> <div class="help-section" id="comparison">
<h2><i class="bi bi-bar-chart"></i> Model Comparison</h2> <h2><i class="bi bi-bar-chart"></i> Model Comparison</h2>
<h3>1,000,000 Investment Over 3 Years Example (Any Currency):</h3> <h3>Investment Comparison - 3 Years ROI (Any Currency):</h3>
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
@ -300,11 +327,25 @@ html {
<td>80,000 profit</td> <td>80,000 profit</td>
</tr> </tr>
<tr> <tr>
<td><strong>Direct Investment</strong></td> <td><strong>Direct Investment (500K)</strong></td>
<td><span class="badge bg-warning">Moderate-High</span></td> <td><span class="badge bg-success">Low-Moderate</span></td>
<td>35% over 3 years</td> <td>200-250% over 3 years</td>
<td>15-24 months</td> <td>12-18 months</td>
<td>540,000+ profit</td> <td>1,000,000+ profit</td>
</tr>
<tr>
<td><strong>Direct Investment (1M)</strong></td>
<td><span class="badge bg-warning">Moderate</span></td>
<td>250-300% over 3 years</td>
<td>15-21 months</td>
<td>2,500,000+ profit</td>
</tr>
<tr>
<td><strong>Direct Investment (2M)</strong></td>
<td><span class="badge bg-danger">High</span></td>
<td>300-400% over 3 years</td>
<td>18-24 months</td>
<td>6,000,000+ profit</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>