Volume 2: Organizational Intelligence Platforms

Pattern 18: Opportunity Mining

Intent

Systematically discover and quantify positive opportunities for expansion, deeper engagement, referrals, and revenue growth by identifying high-potential families, moments of receptivity, underutilized resources, and successful patterns that can be replicated at scale.

Also Known As

  • Opportunity Detection
  • Growth Mining
  • Revenue Discovery
  • Expansion Identification
  • Positive Signal Detection
  • Upsell Discovery

Problem

Organizations focus on problems, miss opportunities.

Sarah spends 80% of time on: - At-risk families (withdrawal prevention) - Payment issues (collections) - Low engagement (interventions)

But misses gold opportunities:

Opportunity 1: Hidden Champions - Chen family: 92% engagement, 3 referrals, volunteers 8 hours/month - Never asked to be mentor or board member - Missed opportunity: Could mentor 3-5 struggling families, recruit from network

Opportunity 2: Expansion Ready - Martinez family: Enrolled one child, has two more at home (ages eligible) - Financial capacity confirmed (always pay early) - Missed opportunity: $900/year additional revenue + deeper commitment

Opportunity 3: Receptivity Windows - Johnson family: Just volunteered for first time (after 8 months) - Engagement spiked 35 points in 2 weeks - Missed opportunity: Perfect moment to ask for referral or additional involvement

Opportunity 4: Underutilized Assets - Williams family: Professional photographer, never asked to help - Smith family: Owns community center, could host events - Missed opportunity: Free resources sitting idle

Without opportunity mining: - Reactive mindset (fix problems, not seize opportunities) - Miss revenue expansion - Underutilize champion families - Don't capitalize on receptivity windows - Resources wasted on low-potential activities

With opportunity mining: - Proactively identify high-value opportunities - Quantify potential impact ($, engagement, referrals) - Prioritize by ROI - Strike when receptivity is highest - Systematic approach to growth

Context

When this pattern applies:

  • Want growth (not just retention)
  • Have capacity for expansion activities
  • Population shows variation (some high-potential)
  • Data reveals signals of opportunity
  • Can act on opportunities discovered

When this pattern may not be needed:

  • Pure survival mode (retention is everything)
  • No capacity for growth initiatives
  • Population is homogeneous (no variation)
  • Already at capacity (can't grow)

Forces

Competing concerns:

1. Problem Focus vs Opportunity Focus - Problems demand attention (urgent) - Opportunities require proactive effort (important) - Balance: 70% problem, 30% opportunity

2. Sure Bets vs Long Shots - Sure bets: Low impact, high probability - Long shots: High impact, low probability - Balance: Portfolio approach (mix of both)

3. Revenue vs Relationship - Revenue opportunities = transactional - Relationship opportunities = long-term - Balance: Both, but relationship-first

4. Individual vs Systematic - Individual: One-off opportunities - Systematic: Patterns that scale - Balance: Start individual, find patterns

5. Quantity vs Quality - Many small opportunities - Few large opportunities - Balance: Pareto principle (80/20)

Solution

Build systematic opportunity discovery across multiple dimensions:

Dimension 1: Expansion Opportunities - Additional services/products - Additional family members - Upgrade to premium tiers - Long-term commitments

Dimension 2: Referral Opportunities - High engagement + social connections - Recent positive experiences - Natural evangelists

Dimension 3: Champion Development - High performers willing to mentor - Board/leadership potential - Ambassador opportunities

Dimension 4: Engagement Deepening - Receptivity windows (recent positive events) - Underutilized family talents/resources - Volunteer potential

Dimension 5: Partnership Opportunities - Professional services - Physical assets (space, equipment) - Network access

Opportunity Scoring Formula:

Opportunity Score = 
  Potential_Value × 
  Success_Probability × 
  Receptivity_Level × 
  Effort_Efficiency

Where:
  Potential_Value = $ or engagement impact
  Success_Probability = 0-1 (based on signals)
  Receptivity_Level = 0-1 (timing factor)
  Effort_Efficiency = 1/effort_required

Structure

Opportunity Mining Tables

-- Store discovered opportunities
CREATE TABLE opportunities (
  opportunity_id INT PRIMARY KEY IDENTITY(1,1),
  family_id INT NOT NULL,

  -- Opportunity details
  opportunity_type VARCHAR(100),  -- 'expansion', 'referral', 'champion', 'engagement', 'partnership'
  opportunity_category VARCHAR(100),  -- 'additional_enrollment', 'mentor', 'board_member', 'ambassador'

  opportunity_description NVARCHAR(1000),

  -- Scoring
  potential_value DECIMAL(10,2),  -- $ or engagement points
  success_probability DECIMAL(3,2),  -- 0-1
  receptivity_score DECIMAL(3,2),  -- 0-1
  effort_required INT,  -- Minutes
  opportunity_score DECIMAL(10,2),  -- Composite score

  -- Signals that triggered discovery
  trigger_signals NVARCHAR(MAX),  -- JSON

  -- Timing
  discovered_date DATETIME2 DEFAULT GETDATE(),
  optimal_contact_window_start DATE,
  optimal_contact_window_end DATE,

  -- Execution
  status VARCHAR(50) DEFAULT 'new',  -- 'new', 'in_progress', 'pursued', 'converted', 'declined', 'expired'
  assigned_to VARCHAR(100),
  contacted_date DATETIME2,

  -- Outcome
  outcome VARCHAR(50),  -- 'converted', 'declined', 'not_pursued', 'expired'
  actual_value DECIMAL(10,2),
  outcome_date DATETIME2,
  outcome_notes NVARCHAR(MAX),

  CONSTRAINT FK_opp_family FOREIGN KEY (family_id)
    REFERENCES families(family_id)
);

-- Index for active opportunities
CREATE INDEX IX_opportunities_active ON opportunities(status, opportunity_score DESC)
  WHERE status IN ('new', 'in_progress');

-- Track opportunity patterns
CREATE TABLE opportunity_patterns (
  pattern_id INT PRIMARY KEY IDENTITY(1,1),

  -- Pattern definition
  pattern_name VARCHAR(200),
  pattern_description NVARCHAR(1000),
  opportunity_type VARCHAR(100),

  -- Signals that indicate this opportunity
  required_signals NVARCHAR(MAX),  -- JSON

  -- Historical performance
  times_identified INT DEFAULT 0,
  times_pursued INT DEFAULT 0,
  times_converted INT DEFAULT 0,
  conversion_rate DECIMAL(5,2),
  avg_value DECIMAL(10,2),

  active BIT DEFAULT 1,
  created_date DATETIME2 DEFAULT GETDATE()
);

-- Track ROI of opportunity mining
CREATE TABLE opportunity_roi_tracking (
  tracking_id INT PRIMARY KEY IDENTITY(1,1),

  period_start DATE,
  period_end DATE,

  -- Opportunities
  total_opportunities_identified INT,
  opportunities_pursued INT,
  opportunities_converted INT,

  -- Value
  total_potential_value DECIMAL(10,2),
  total_actual_value DECIMAL(10,2),

  -- Effort
  total_effort_hours DECIMAL(8,2),

  -- ROI
  roi_percentage DECIMAL(8,2),  -- (actual_value / effort_cost) * 100

  created_date DATETIME2 DEFAULT GETDATE()
);

Implementation

Opportunity Mining Engine

class OpportunityMiningEngine {
  constructor(db) {
    this.db = db;
  }

  async mineOpportunities() {
    const opportunities = [];

    // Mine each opportunity type
    const expansion = await this.mineExpansionOpportunities();
    const referral = await this.mineReferralOpportunities();
    const champion = await this.mineChampionOpportunities();
    const engagement = await this.mineEngagementOpportunities();
    const partnership = await this.minePartnershipOpportunities();

    opportunities.push(...expansion, ...referral, ...champion, ...engagement, ...partnership);

    // Score and rank
    const scored = opportunities.map(opp => ({
      ...opp,
      opportunity_score: this.calculateOpportunityScore(opp)
    }));

    scored.sort((a, b) => b.opportunity_score - a.opportunity_score);

    // Save to database
    for (const opp of scored) {
      await this.saveOpportunity(opp);
    }

    return scored;
  }

  async mineExpansionOpportunities() {
    const opportunities = [];

    // Opportunity: Additional family members
    const additionalMembers = await this.db.query(`
      SELECT 
        f.family_id,
        f.family_name,
        f.enrolled_student_count,
        f.total_eligible_children,
        fem.engagement_score,
        fem.financial_health_score,
        p.avg_payment_amount
      FROM families f
      JOIN family_engagement_metrics fem ON f.family_id = fem.family_id
      LEFT JOIN (
        SELECT family_id, AVG(amount) as avg_payment_amount
        FROM payments
        GROUP BY family_id
      ) p ON f.family_id = p.family_id
      WHERE f.enrolled_student_count < f.total_eligible_children
        AND fem.engagement_score > 70
        AND fem.financial_health_score > 70
    `);

    for (const family of additionalMembers) {
      const additionalKids = family.total_eligible_children - family.enrolled_student_count;
      const potentialRevenue = additionalKids * 450;  // $450 per student per semester

      opportunities.push({
        family_id: family.family_id,
        opportunity_type: 'expansion',
        opportunity_category: 'additional_enrollment',
        opportunity_description: `${family.family_name} has ${additionalKids} more eligible child(ren). High engagement and financial health.`,
        potential_value: potentialRevenue,
        success_probability: this.estimateExpansionProbability(family),
        receptivity_score: family.engagement_score / 100,
        effort_required: 30,  // 30 minute conversation
        trigger_signals: {
          eligible_children: additionalKids,
          engagement_score: family.engagement_score,
          financial_health: family.financial_health_score
        }
      });
    }

    // Opportunity: Upgrade to year commitment (discount + stability)
    const upgradeOpportunities = await this.db.query(`
      SELECT 
        f.family_id,
        f.family_name,
        f.enrollment_type,
        fem.engagement_score,
        fem.tenure_score,
        DATEDIFF(NOW(), f.enrollment_date) as days_enrolled
      FROM families f
      JOIN family_engagement_metrics fem ON f.family_id = fem.family_id
      WHERE f.enrollment_type = 'semester'
        AND fem.engagement_score > 75
        AND DATEDIFF(NOW(), f.enrollment_date) > 180
    `);

    for (const family of upgradeOpportunities) {
      opportunities.push({
        family_id: family.family_id,
        opportunity_type: 'expansion',
        opportunity_category: 'annual_commitment',
        opportunity_description: `${family.family_name} highly engaged and established. Offer annual enrollment with 10% discount.`,
        potential_value: 810,  // Annual: $900, discount: $90, net: $810 vs $450 semester
        success_probability: 0.65,
        receptivity_score: Math.min(1.0, family.days_enrolled / 365),
        effort_required: 20,
        trigger_signals: {
          engagement_score: family.engagement_score,
          tenure_days: family.days_enrolled,
          enrollment_type: family.enrollment_type
        }
      });
    }

    return opportunities;
  }

  async mineReferralOpportunities() {
    const opportunities = [];

    // High engagement + social connections + recent positive experience
    const referralCandidates = await this.db.query(`
      SELECT 
        f.family_id,
        f.family_name,
        fem.engagement_score,
        COUNT(DISTINCT re.edge_id) as connection_count,
        MAX(il.interaction_timestamp) as last_positive_interaction
      FROM families f
      JOIN family_engagement_metrics fem ON f.family_id = fem.family_id
      LEFT JOIN relationship_edges re ON f.family_id = re.source_entity_id
      LEFT JOIN interaction_log il ON f.family_id = il.family_id
        AND il.outcome_category = 'success'
        AND il.interaction_timestamp >= DATE_SUB(NOW(), INTERVAL 30 DAY)
      WHERE fem.engagement_score > 80
        AND f.enrolled_current_semester = 1
      GROUP BY f.family_id, f.family_name, fem.engagement_score
      HAVING connection_count > 3
        AND last_positive_interaction IS NOT NULL
    `);

    for (const family of referralCandidates) {
      const daysSincePositive = Math.floor(
        (Date.now() - new Date(family.last_positive_interaction)) / (1000 * 60 * 60 * 24)
      );

      // Receptivity highest within 7 days of positive experience
      const receptivity = Math.max(0.3, 1.0 - (daysSincePositive / 30));

      opportunities.push({
        family_id: family.family_id,
        opportunity_type: 'referral',
        opportunity_category: 'peer_referral',
        opportunity_description: `${family.family_name} is highly engaged with ${family.connection_count} connections. Recent positive experience ${daysSincePositive} days ago.`,
        potential_value: 450,  // Value of new enrollment
        success_probability: 0.40,  // 40% of asked champions refer someone
        receptivity_score: receptivity,
        effort_required: 15,  // Quick ask
        trigger_signals: {
          engagement_score: family.engagement_score,
          connection_count: family.connection_count,
          days_since_positive: daysSincePositive
        },
        optimal_contact_window_start: new Date(),
        optimal_contact_window_end: this.addDays(new Date(), 7)
      });
    }

    return opportunities;
  }

  async mineChampionOpportunities() {
    const opportunities = [];

    // Mentor opportunities
    const mentorCandidates = await this.db.query(`
      SELECT 
        f.family_id,
        f.family_name,
        fem.engagement_score,
        fem.participation_score,
        COALESCE(vol.volunteer_hours, 0) as volunteer_hours,
        COALESCE(ref.referral_count, 0) as referral_count
      FROM families f
      JOIN family_engagement_metrics fem ON f.family_id = fem.family_id
      LEFT JOIN (
        SELECT family_id, SUM(CAST(JSON_VALUE(metadata, '$.hours') AS DECIMAL)) as volunteer_hours
        FROM interaction_log
        WHERE interaction_type = 'volunteer_hours_logged'
        GROUP BY family_id
      ) vol ON f.family_id = vol.family_id
      LEFT JOIN (
        SELECT family_id, COUNT(*) as referral_count
        FROM interaction_log
        WHERE interaction_type = 'referral_made'
        GROUP BY family_id
      ) ref ON f.family_id = ref.family_id
      WHERE fem.engagement_score > 85
        AND (vol.volunteer_hours > 5 OR ref.referral_count > 1)
        AND f.enrolled_current_semester = 1
    `);

    for (const family of mentorCandidates) {
      // Find families they could mentor (new + struggling)
      const menteeCount = await this.db.query(`
        SELECT COUNT(*) as count
        FROM families f2
        JOIN family_engagement_metrics fem2 ON f2.family_id = fem2.family_id
        WHERE fem2.engagement_score < 50
          AND DATEDIFF(NOW(), f2.enrollment_date) < 180
      `);

      const potentialMentees = menteeCount[0].count;

      if (potentialMentees > 0) {
        opportunities.push({
          family_id: family.family_id,
          opportunity_type: 'champion',
          opportunity_category: 'mentor',
          opportunity_description: `${family.family_name} is high performer (${family.engagement_score} engagement, ${family.volunteer_hours} volunteer hours). Could mentor ${potentialMentees} struggling new families.`,
          potential_value: potentialMentees * 200,  // Value of retention improvement
          success_probability: 0.70,  // High performers usually say yes
          receptivity_score: 0.80,
          effort_required: 45,  // Recruit + train + match
          trigger_signals: {
            engagement_score: family.engagement_score,
            volunteer_hours: family.volunteer_hours,
            referral_count: family.referral_count,
            potential_mentees: potentialMentees
          }
        });
      }
    }

    // Board member opportunities
    const boardCandidates = await this.db.query(`
      SELECT 
        f.family_id,
        f.family_name,
        fem.engagement_score,
        DATEDIFF(NOW(), f.enrollment_date) / 365 as years_enrolled,
        COALESCE(vol.volunteer_hours, 0) as volunteer_hours
      FROM families f
      JOIN family_engagement_metrics fem ON f.family_id = fem.family_id
      LEFT JOIN (
        SELECT family_id, SUM(CAST(JSON_VALUE(metadata, '$.hours') AS DECIMAL)) as volunteer_hours
        FROM interaction_log
        WHERE interaction_type = 'volunteer_hours_logged'
        GROUP BY family_id
      ) vol ON f.family_id = vol.family_id
      WHERE fem.engagement_score > 90
        AND DATEDIFF(NOW(), f.enrollment_date) > 365
        AND vol.volunteer_hours > 10
    `);

    for (const family of boardCandidates) {
      opportunities.push({
        family_id: family.family_id,
        opportunity_type: 'champion',
        opportunity_category: 'board_member',
        opportunity_description: `${family.family_name} exceptional engagement (${family.engagement_score}), ${family.years_enrolled.toFixed(1)} years tenure, ${family.volunteer_hours} volunteer hours. Board candidate.`,
        potential_value: 1000,  // Leadership value
        success_probability: 0.50,
        receptivity_score: 0.75,
        effort_required: 60,
        trigger_signals: {
          engagement_score: family.engagement_score,
          years_enrolled: family.years_enrolled,
          volunteer_hours: family.volunteer_hours
        }
      });
    }

    return opportunities;
  }

  async mineEngagementOpportunities() {
    const opportunities = [];

    // Receptivity window (recent positive spike)
    const receptivityWindows = await this.db.query(`
      SELECT 
        f.family_id,
        f.family_name,
        femh1.engagement_score as current_score,
        femh2.engagement_score as previous_score,
        (femh1.engagement_score - femh2.engagement_score) as score_change,
        femh1.calculation_date as recent_date
      FROM families f
      JOIN family_engagement_metrics_history femh1 ON f.family_id = femh1.family_id
      JOIN family_engagement_metrics_history femh2 ON f.family_id = femh2.family_id
        AND femh2.calculation_date = DATE_SUB(femh1.calculation_date, INTERVAL 1 MONTH)
      WHERE femh1.calculation_date = (
        SELECT MAX(calculation_date) FROM family_engagement_metrics_history WHERE family_id = f.family_id
      )
        AND (femh1.engagement_score - femh2.engagement_score) > 15
        AND femh1.engagement_score > 65
    `);

    for (const family of receptivityWindows) {
      opportunities.push({
        family_id: family.family_id,
        opportunity_type: 'engagement',
        opportunity_category: 'receptivity_window',
        opportunity_description: `${family.family_name} engagement spiked ${family.score_change.toFixed(1)} points recently. High receptivity for deeper involvement.`,
        potential_value: 300,  // Increased retention probability
        success_probability: 0.75,
        receptivity_score: Math.min(1.0, family.score_change / 30),
        effort_required: 20,
        trigger_signals: {
          score_change: family.score_change,
          current_score: family.current_score,
          previous_score: family.previous_score
        },
        optimal_contact_window_start: new Date(),
        optimal_contact_window_end: this.addDays(new Date(), 14)
      });
    }

    return opportunities;
  }

  async minePartnershipOpportunities() {
    const opportunities = [];

    // Families with professional services or assets
    const assetFamilies = await this.db.query(`
      SELECT 
        f.family_id,
        f.family_name,
        f.parent_profession,
        f.special_resources,
        fem.engagement_score
      FROM families f
      JOIN family_engagement_metrics fem ON f.family_id = fem.family_id
      WHERE (
        f.parent_profession IN ('photographer', 'graphic_designer', 'web_developer', 'teacher', 'lawyer', 'accountant')
        OR f.special_resources LIKE '%community_center%'
        OR f.special_resources LIKE '%meeting_space%'
      )
        AND fem.engagement_score > 60
    `);

    for (const family of assetFamilies) {
      let category, description, value;

      if (family.parent_profession === 'photographer') {
        category = 'professional_service';
        description = `${family.family_name} is professional photographer. Could provide event photography (valued at $500-1000 per event).`;
        value = 750;
      } else if (family.parent_profession === 'graphic_designer') {
        category = 'professional_service';
        description = `${family.family_name} is graphic designer. Could create marketing materials ($300-500 value).`;
        value = 400;
      } else if (family.special_resources && family.special_resources.includes('community_center')) {
        category = 'physical_asset';
        description = `${family.family_name} has access to community center. Could host events (valued at $200 per event).`;
        value = 600;  // 3 events per semester
      }

      if (category) {
        opportunities.push({
          family_id: family.family_id,
          opportunity_type: 'partnership',
          opportunity_category: category,
          opportunity_description: description,
          potential_value: value,
          success_probability: 0.60,
          receptivity_score: family.engagement_score / 100,
          effort_required: 30,
          trigger_signals: {
            profession: family.parent_profession,
            resources: family.special_resources,
            engagement_score: family.engagement_score
          }
        });
      }
    }

    return opportunities;
  }

  calculateOpportunityScore(opportunity) {
    // Composite score formula
    const score = 
      opportunity.potential_value *
      opportunity.success_probability *
      opportunity.receptivity_score *
      (60 / opportunity.effort_required);  // Efficiency factor (60 minutes baseline)

    return Math.round(score * 100) / 100;
  }

  estimateExpansionProbability(family) {
    // Factors that predict expansion success
    let probability = 0.50;  // Base rate

    if (family.engagement_score > 85) probability += 0.20;
    else if (family.engagement_score > 75) probability += 0.10;

    if (family.financial_health_score > 85) probability += 0.15;
    else if (family.financial_health_score > 75) probability += 0.08;

    return Math.min(0.95, probability);
  }

  addDays(date, days) {
    const result = new Date(date);
    result.setDate(result.getDate() + days);
    return result;
  }

  async saveOpportunity(opportunity) {
    // Check if similar opportunity already exists
    const existing = await this.db.query(`
      SELECT opportunity_id
      FROM opportunities
      WHERE family_id = ?
        AND opportunity_category = ?
        AND status IN ('new', 'in_progress')
    `, [opportunity.family_id, opportunity.opportunity_category]);

    if (existing.length === 0) {
      await this.db.query(`
        INSERT INTO opportunities (
          family_id, opportunity_type, opportunity_category, opportunity_description,
          potential_value, success_probability, receptivity_score, effort_required,
          opportunity_score, trigger_signals,
          optimal_contact_window_start, optimal_contact_window_end
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
      `, [
        opportunity.family_id,
        opportunity.opportunity_type,
        opportunity.opportunity_category,
        opportunity.opportunity_description,
        opportunity.potential_value,
        opportunity.success_probability,
        opportunity.receptivity_score,
        opportunity.effort_required,
        opportunity.opportunity_score,
        JSON.stringify(opportunity.trigger_signals),
        opportunity.optimal_contact_window_start,
        opportunity.optimal_contact_window_end
      ]);
    }
  }

  async getOpportunityDashboard(topN = 20) {
    return await this.db.query(`
      SELECT 
        o.opportunity_id,
        o.family_id,
        f.family_name,
        o.opportunity_type,
        o.opportunity_category,
        o.opportunity_description,
        o.potential_value,
        o.success_probability,
        o.receptivity_score,
        o.effort_required,
        o.opportunity_score,
        o.optimal_contact_window_end,
        CASE 
          WHEN o.optimal_contact_window_end < CURRENT_DATE THEN 'expired'
          WHEN o.optimal_contact_window_end <= DATE_ADD(CURRENT_DATE, INTERVAL 3 DAY) THEN 'urgent'
          ELSE 'active'
        END as urgency
      FROM opportunities o
      JOIN families f ON o.family_id = f.family_id
      WHERE o.status = 'new'
      ORDER BY o.opportunity_score DESC
      LIMIT ?
    `, [topN]);
  }
}

module.exports = OpportunityMiningEngine;

Usage Example

const miner = new OpportunityMiningEngine(db);

// Mine all opportunities
const opportunities = await miner.mineOpportunities();

console.log(`\n=== DISCOVERED ${opportunities.length} OPPORTUNITIES ===\n`);

// Get top opportunities
const dashboard = await miner.getOpportunityDashboard(10);

dashboard.forEach((opp, i) => {
  console.log(`${i+1}. ${opp.family_name} - ${opp.opportunity_category.toUpperCase()}`);
  console.log(`   Type: ${opp.opportunity_type}`);
  console.log(`   Description: ${opp.opportunity_description}`);
  console.log(`   Potential Value: $${opp.potential_value.toFixed(0)}`);
  console.log(`   Success Probability: ${(opp.success_probability * 100).toFixed(0)}%`);
  console.log(`   Opportunity Score: ${opp.opportunity_score.toFixed(2)}`);
  console.log(`   Urgency: ${opp.urgency}`);
  console.log(``);
});

// Example output:
// === DISCOVERED 47 OPPORTUNITIES ===
//
// 1. Chen Family - MENTOR
//    Type: champion
//    Description: Chen Family is high performer (92 engagement, 12 volunteer hours). Could mentor 8 struggling new families.
//    Potential Value: $1600
//    Success Probability: 70%
//    Opportunity Score: 672.00
//    Urgency: active
//
// 2. Martinez Family - ADDITIONAL_ENROLLMENT
//    Type: expansion
//    Description: Martinez Family has 2 more eligible child(ren). High engagement and financial health.
//    Potential Value: $900
//    Success Probability: 75%
//    Opportunity Score: 540.00
//    Urgency: active
//
// 3. Johnson Family - PEER_REFERRAL
//    Type: referral
//    Description: Johnson Family is highly engaged with 7 connections. Recent positive experience 3 days ago.
//    Potential Value: $450
//    Success Probability: 40%
//    Opportunity Score: 432.00
//    Urgency: urgent

Variations

By Opportunity Type

Revenue-Focused: - Expansion (additional services/members) - Upsell (premium tiers) - Referral (new customers)

Relationship-Focused: - Champion development - Mentor recruitment - Community building

Resource-Focused: - Volunteer recruitment - Asset utilization - Partnership development

By Discovery Method

Rule-Based: - Explicit criteria (engagement > 80 + connections > 3) - Fast, interpretable - Requires domain knowledge

ML-Based: - Propensity models (likelihood to accept offer) - Lookalike modeling (similar to converters) - More accurate, less interpretable

Hybrid: - ML scores + rule filters - Best of both worlds

By Timing

Immediate: - Act within days - Receptivity windows - Time-sensitive

Near-Term (Weeks): - Standard opportunities - Planned outreach - Most opportunities

Long-Term (Months): - Strategic partnerships - Major commitments - Patient cultivation

Consequences

Benefits

1. Proactive growth Don't wait for opportunities to find you - discover them systematically.

2. Quantified priorities $1600 mentor opportunity > $450 referral opportunity (when success rates similar).

3. Optimal timing Strike during receptivity windows (within 7 days of positive experience).

4. Underutilized resources Discover photographer family, event space, professional services sitting idle.

5. Champion leverage High performers mentor 3-5 struggling families (multiplier effect).

6. ROI tracking Measure effort invested vs value realized.

Costs

1. Opportunity cost Time mining opportunities = less time solving problems.

2. Relationship risk Aggressive pursuit can feel transactional.

3. False positives Not every "opportunity" converts.

4. Complexity Many opportunity types to track and manage.

5. Timing pressure Receptivity windows create urgency.

6. Expectations Discovered opportunities create pressure to pursue.

Sample Code

Track opportunity conversion:

async function recordOpportunityOutcome(opportunityId, outcome, actualValue, notes) {
  await db.query(`
    UPDATE opportunities
    SET 
      status = 'pursued',
      outcome = ?,
      actual_value = ?,
      outcome_date = NOW(),
      outcome_notes = ?
    WHERE opportunity_id = ?
  `, [outcome, actualValue, notes, opportunityId]);

  // Update pattern statistics
  const opp = await db.query(`
    SELECT opportunity_category
    FROM opportunities
    WHERE opportunity_id = ?
  `, [opportunityId]);

  await db.query(`
    UPDATE opportunity_patterns
    SET 
      times_pursued = times_pursued + 1,
      times_converted = times_converted + (CASE WHEN ? = 'converted' THEN 1 ELSE 0 END),
      conversion_rate = (times_converted * 100.0) / times_pursued
    WHERE opportunity_type = ?
  `, [outcome, opp[0].opportunity_category]);
}

Known Uses

Homeschool Co-op Intelligence Platform - Mines 40-50 opportunities monthly - Pursues top 15-20 (resource constrained) - 65% conversion rate on pursued opportunities - Generated $12,000 additional revenue in one semester - Recruited 8 mentors (retained 18 struggling families)

E-Commerce: - Product recommendation engines - Upsell/cross-sell opportunities - Cart abandonment recovery

SaaS: - Expansion opportunities (add seats, features) - Upgrade propensity models - Champion/advocate programs

Financial Services: - Cross-sell opportunities (existing customers) - Wealth management upsell - Referral mining

Requires: - Pattern 1: Universal Event Log - behavioral signals - Pattern 16: Cohort Discovery - high-value cohorts - Pattern 17: Anomaly Detection - positive anomalies = opportunities

Enables: - Pattern 15: Intervention Recommendation - opportunity-specific recommendations - Pattern 22: Progressive Escalation - opportunity cultivation sequences - Pattern 24: Template-Based Communication - outreach templates

Enhanced by: - Pattern 2: Behavioral Graph - connection-based opportunities - Pattern 12: Risk Stratification Models - propensity modeling

References

Academic Foundations

  • Davenport, Thomas H., and Jeanne G. Harris (2007). Competing on Analytics. Harvard Business Press. ISBN: 978-1422103326
  • Kumar, V., and Werner Reinartz (2018). Customer Relationship Management: Concept, Strategy, and Tools (3rd ed.). Springer. ISBN: 978-3662553817
  • Gupta, Sunil, and Donald R. Lehmann (2005). Managing Customers as Investments. Wharton School Publishing. ISBN: 978-0132281638 - Customer lifetime value
  • Fader, Peter S. (2012). Customer Centricity. Wharton Digital Press. ISBN: 978-1613630211

Cohort Analysis Methods

Propensity Modeling

  • Logistic Regression for Propensity: Hosmer, D.W., Lemeshow, S., & Sturdivant, R.X. (2013). Applied Logistic Regression (3rd ed.). Wiley. ISBN: 978-0470582473
  • Uplift Modeling: Rzepakowski, P., & Jaroszewicz, S. (2012). "Decision trees for uplift modeling with single and multiple treatments." Knowledge and Information Systems 32(2): 303-327.
  • Propensity Score Matching: Rosenbaum, P.R., & Rubin, D.B. (1983). "The central role of the propensity score in observational studies for causal effects." Biometrika 70(1): 41-55.

Practical Implementation

  • Pattern 8: Tier-Based Segmentation - Cohorts inform segmentation
  • Pattern 11: Historical Pattern Matching - Match current cohort to historical cohorts
  • Pattern 15: Intervention Recommendation Engine - Cohort-specific recommendations
  • Volume 3, Pattern 6: Domain-Aware Validation - Domain-specific cohort definitions

Tools & Services