Skip to content

Co-Sell Platform Implementation Notes

For Patent Application Support

Document Classification: Patent Sensitive - Implementation Documentation Version: 1.0 Date: December 2025


1. Technology Stack

1.1 Core Components

Component Technology Purpose
Backend API Node.js / TypeScript REST API for all platform operations
Database PostgreSQL Primary data store for partners, relationships, campaigns
Cache Redis Session management, rate limiting, temporary scoring cache
Message Queue Redis / Bull Async job processing for content generation, publishing
AI/LLM Claude 3 Sonnet API Content generation, analysis, predictions
Embeddings OpenAI Ada-002 or Claude Similarity detection for duplicate content
File Storage AWS S3 Generated assets, brand assets, campaign media
Search Elasticsearch Partner discovery, content search

1.2 External Integrations

Integration Purpose Authentication
LinkedIn API Social content publishing OAuth 2.0
SendGrid/Mailchimp Email campaign delivery API Key
Salesforce CRM sync, lead tracking OAuth 2.0
HubSpot Marketing automation sync OAuth 2.0
AWS Marketplace API Partner data enrichment AWS IAM
Segment Analytics event tracking API Key

2. Database Schema

2.1 Core Tables

-- Partners table
CREATE TABLE partners (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    company_name VARCHAR(255) NOT NULL,
    industry VARCHAR(100),
    company_size VARCHAR(50),
    aws_partner_tier VARCHAR(50),
    product_description TEXT,
    icp_definition JSONB,
    brand_voice JSONB,
    value_propositions JSONB,
    target_markets JSONB,
    product_categories JSONB,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW(),
    status VARCHAR(50) DEFAULT 'active'
);

-- Indexes for common queries
CREATE INDEX idx_partners_industry ON partners(industry);
CREATE INDEX idx_partners_tier ON partners(aws_partner_tier);
CREATE INDEX idx_partners_status ON partners(status);
CREATE INDEX idx_partners_icp ON partners USING GIN(icp_definition);

-- Co-sell relationships table
CREATE TABLE cosell_relationships (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    partner_a_id UUID REFERENCES partners(id),
    partner_b_id UUID REFERENCES partners(id),
    status VARCHAR(50) DEFAULT 'invited',
    initiated_by UUID REFERENCES partners(id),
    match_scores JSONB,
    success_prediction JSONB,
    created_at TIMESTAMP DEFAULT NOW(),
    accepted_at TIMESTAMP,
    ended_at TIMESTAMP,
    end_reason VARCHAR(255),

    CONSTRAINT unique_relationship UNIQUE (partner_a_id, partner_b_id)
);

CREATE INDEX idx_relationships_status ON cosell_relationships(status);
CREATE INDEX idx_relationships_partner_a ON cosell_relationships(partner_a_id);
CREATE INDEX idx_relationships_partner_b ON cosell_relationships(partner_b_id);

-- Campaign plans table
CREATE TABLE cosell_plans (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    relationship_id UUID REFERENCES cosell_relationships(id),
    name VARCHAR(255),
    type VARCHAR(50),
    status VARCHAR(50) DEFAULT 'draft',
    merged_brand_voice JSONB,
    objectives JSONB,
    content_calendar JSONB,
    metrics JSONB,
    start_date DATE,
    end_date DATE,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_plans_relationship ON cosell_plans(relationship_id);
CREATE INDEX idx_plans_status ON cosell_plans(status);

-- Shared assets table
CREATE TABLE shared_assets (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    plan_id UUID REFERENCES cosell_plans(id),
    asset_type VARCHAR(50),
    title VARCHAR(500),
    content JSONB,
    partner_a_approval VARCHAR(50) DEFAULT 'pending',
    partner_b_approval VARCHAR(50) DEFAULT 'pending',
    scheduled_publish_date TIMESTAMP,
    published_at TIMESTAMP,
    distribution_channels JSONB,
    tracking_parameters JSONB,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_assets_plan ON shared_assets(plan_id);
CREATE INDEX idx_assets_status ON shared_assets(partner_a_approval, partner_b_approval);
CREATE INDEX idx_assets_scheduled ON shared_assets(scheduled_publish_date);

2.2 Audit and History Tables

-- Audit log for all changes
CREATE TABLE audit_log (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    entity_type VARCHAR(50),
    entity_id UUID,
    action VARCHAR(50),
    actor_id UUID,
    actor_type VARCHAR(50),
    old_values JSONB,
    new_values JSONB,
    metadata JSONB,
    created_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_audit_entity ON audit_log(entity_type, entity_id);
CREATE INDEX idx_audit_actor ON audit_log(actor_id);
CREATE INDEX idx_audit_created ON audit_log(created_at);

-- Asset approval history
CREATE TABLE asset_approval_history (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    asset_id UUID REFERENCES shared_assets(id),
    partner_id UUID REFERENCES partners(id),
    action VARCHAR(50),
    comment TEXT,
    created_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_approval_history_asset ON asset_approval_history(asset_id);

3. API Endpoints

3.1 Partner Matching API

POST /api/v1/partners/{partner_id}/match-requests
    Request matching candidates for a partner
    Body: { filters: { industry?, tier?, min_score? } }
    Response: { matches: [{ partner, scores, prediction }] }

GET /api/v1/partners/{partner_id}/matches
    Get all qualified matches for a partner
    Query: ?status=qualified&min_score=50&limit=20
    Response: { matches: [...], total: number }

GET /api/v1/matches/{match_id}/scores
    Get detailed scoring breakdown
    Response: { icp_overlap: {...}, product_fit: {...}, market: {...} }

3.2 Relationship API

POST /api/v1/relationships
    Create new co-sell relationship (send invitation)
    Body: { partner_a_id, partner_b_id }
    Response: { relationship_id, status: 'invited' }

PATCH /api/v1/relationships/{id}
    Update relationship status (accept/decline/pause/end)
    Body: { status: 'active' | 'declined' | 'paused' | 'ended', reason? }
    Response: { relationship }

GET /api/v1/relationships/{id}
    Get relationship details
    Response: { relationship, match_scores, prediction, plans: [...] }

3.3 Campaign API

POST /api/v1/relationships/{relationship_id}/plans
    Create new campaign plan
    Body: { type, duration_weeks, objectives? }
    Response: { plan_id, calendar, assets: [...] }

GET /api/v1/plans/{plan_id}
    Get plan with all assets
    Response: { plan, calendar, assets, merged_voice }

POST /api/v1/plans/{plan_id}/regenerate
    Regenerate campaign with new parameters
    Body: { focus?, tone_adjustment?, exclude_assets? }
    Response: { plan, assets }

3.4 Asset Approval API

PATCH /api/v1/assets/{asset_id}/approval
    Submit approval decision
    Body: { partner_id, decision: 'approved' | 'changes_requested' | 'rejected', comment? }
    Response: { asset, ready_for_publishing: boolean }

POST /api/v1/assets/{asset_id}/revisions
    Submit revision to asset
    Body: { content: {...}, revision_notes }
    Response: { asset, version: number }

GET /api/v1/assets/{asset_id}/history
    Get approval and revision history
    Response: { history: [...] }

3.5 Publishing API

POST /api/v1/assets/{asset_id}/schedule
    Schedule asset for publishing
    Body: { publish_time, channels: [...] }
    Response: { scheduled_jobs: [...] }

POST /api/v1/assets/{asset_id}/publish
    Immediately publish asset
    Body: { channels: [...] }
    Response: { results: [{ channel, status, url? }] }

GET /api/v1/plans/{plan_id}/publishing-status
    Get publishing status for all plan assets
    Response: { assets: [{ id, status, published_urls }] }

4. Algorithm Implementation Details

4.1 ICP Overlap Scoring

interface ICPDefinition {
  company_size_range: [number, number];
  industries: string[];
  geographic_regions: string[];
  technologies: string[];
}

interface ICPOverlapResult {
  score: number;
  breakdown: {
    company_size: number;
    industry: number;
    geography: number;
    technology: number;
  };
}

function calculateICPOverlap(icpA: ICPDefinition, icpB: ICPDefinition): ICPOverlapResult {
  const weights = {
    company_size: 0.25,
    industry: 0.30,
    geography: 0.25,
    technology: 0.20
  };

  // Company size overlap (range intersection)
  const sizeOverlap = calculateRangeOverlap(
    icpA.company_size_range,
    icpB.company_size_range
  );
  const sizeScore = sizeOverlap * weights.company_size * 100;

  // Industry overlap (Jaccard index)
  const industryJaccard = calculateJaccardIndex(icpA.industries, icpB.industries);
  const industryScore = industryJaccard * weights.industry * 100;

  // Geography overlap (Jaccard index)
  const geoJaccard = calculateJaccardIndex(icpA.geographic_regions, icpB.geographic_regions);
  const geoScore = geoJaccard * weights.geography * 100;

  // Technology overlap (Jaccard index)
  const techJaccard = calculateJaccardIndex(icpA.technologies, icpB.technologies);
  const techScore = techJaccard * weights.technology * 100;

  const totalScore = Math.round(sizeScore + industryScore + geoScore + techScore);

  return {
    score: totalScore,
    breakdown: {
      company_size: Math.round(sizeScore),
      industry: Math.round(industryScore),
      geography: Math.round(geoScore),
      technology: Math.round(techScore)
    }
  };
}

function calculateJaccardIndex(setA: string[], setB: string[]): number {
  const intersection = setA.filter(x => setB.includes(x));
  const union = [...new Set([...setA, ...setB])];

  if (union.length === 0) return 0;
  return intersection.length / union.length;
}

function calculateRangeOverlap(rangeA: [number, number], rangeB: [number, number]): number {
  const overlapStart = Math.max(rangeA[0], rangeB[0]);
  const overlapEnd = Math.min(rangeA[1], rangeB[1]);

  if (overlapStart > overlapEnd) return 0;

  const overlapLength = overlapEnd - overlapStart;
  const unionLength = Math.max(rangeA[1], rangeB[1]) - Math.min(rangeA[0], rangeB[0]);

  return overlapLength / unionLength;
}

4.2 Product Complementarity Analysis

interface ComplementarityResult {
  score: number;
  competitive_overlap: number;
  ai_analysis: {
    complementarity_score: number;
    integration_potential: number;
    customer_use_case_fit: number;
    reasoning: string;
  };
}

async function calculateProductComplementarity(
  partnerA: Partner,
  partnerB: Partner
): Promise<ComplementarityResult> {
  // Step 1: Check category overlap (competition detection)
  const competitiveOverlap = calculateCategoryOverlap(
    partnerA.product_categories,
    partnerB.product_categories
  );

  if (competitiveOverlap > 0.7) {
    return {
      score: 0,
      competitive_overlap: competitiveOverlap,
      ai_analysis: null // Disqualified
    };
  }

  // Step 2: AI analysis
  const prompt = constructComplementarityPrompt(partnerA, partnerB);

  const aiAnalysis = await claude.invoke({
    model: 'claude-3-sonnet',
    prompt: prompt,
    response_format: {
      type: 'json_schema',
      schema: {
        complementarity_score: 'integer',
        integration_potential: 'integer',
        customer_use_case_fit: 'integer',
        reasoning: 'string'
      }
    }
  });

  // Step 3: Calculate weighted score
  const rawScore =
    aiAnalysis.complementarity_score * 0.40 +
    aiAnalysis.integration_potential * 0.30 +
    aiAnalysis.customer_use_case_fit * 0.30;

  // Step 4: Apply competition penalty
  const finalScore = Math.round(rawScore * (1 - competitiveOverlap));

  return {
    score: finalScore,
    competitive_overlap: competitiveOverlap,
    ai_analysis: aiAnalysis
  };
}

function constructComplementarityPrompt(partnerA: Partner, partnerB: Partner): string {
  return `
    Analyze the business complementarity between these two software companies:

    Company A: ${partnerA.company_name}
    Product: ${partnerA.product_description}
    Value Props: ${partnerA.value_propositions.join(', ')}

    Company B: ${partnerB.company_name}
    Product: ${partnerB.product_description}
    Value Props: ${partnerB.value_propositions.join(', ')}

    Rate the following on a scale of 0-100:
    1. complementarity_score: How well do these products complement each other?
    2. integration_potential: How feasible is technical or workflow integration?
    3. customer_use_case_fit: Would shared customers benefit from using both?

    Provide brief reasoning for your scores.
  `;
}

4.3 Brand Voice Merging

interface MergedBrandVoice {
  harmonized_tone: string[];
  shared_pain_points: string[];
  combined_goals: string[];
  messaging_guidelines: {
    do: string[];
    avoid: string[];
    conflicts_resolved: ConflictResolution[];
  };
  joint_value_propositions: string[];
  co_branding_guidelines: CoBrandingGuidelines;
}

const TONE_SPECTRUM: Record<string, number> = {
  'formal': 0.9,
  'professional': 0.7,
  'business-casual': 0.5,
  'approachable': 0.4,
  'casual': 0.2,
  'playful': 0.1
};

function harmonizeTones(toneA: string[], toneB: string[]): string[] {
  // Calculate average position on spectrum
  const avgA = toneA.reduce((sum, t) => sum + (TONE_SPECTRUM[t] || 0.5), 0) / toneA.length;
  const avgB = toneB.reduce((sum, t) => sum + (TONE_SPECTRUM[t] || 0.5), 0) / toneB.length;
  const mergedPosition = (avgA + avgB) / 2;

  // Find tones within 0.2 of merged position
  const harmonized: string[] = [];
  for (const [tone, value] of Object.entries(TONE_SPECTRUM)) {
    if (Math.abs(value - mergedPosition) < 0.2) {
      harmonized.push(tone);
    }
  }

  // Add shared tones
  const shared = toneA.filter(t => toneB.includes(t));
  const result = [...new Set([...harmonized, ...shared])];

  return result.slice(0, 3); // Return top 3
}

async function mergeBrandVoices(
  brandA: BrandVoice,
  brandB: BrandVoice,
  campaignContext: CampaignContext
): Promise<MergedBrandVoice> {
  // Step 1: Tone harmonization
  const harmonizedTone = harmonizeTones(brandA.tone, brandB.tone);

  // Step 2: Audience intersection
  const sharedPainPoints = brandA.target_audience.pain_points.filter(
    p => brandB.target_audience.pain_points.some(bp => semanticallySimilar(p, bp))
  );
  const combinedGoals = [...new Set([
    ...brandA.target_audience.goals,
    ...brandB.target_audience.goals
  ])];

  // Step 3: Messaging merge with conflict detection
  const conflicts = identifyMessagingConflicts(brandA, brandB);
  const conflictsResolved = await resolveConflictsWithAI(conflicts);

  const messagingDo = [...new Set([...brandA.messaging_guidelines.do, ...brandB.messaging_guidelines.do])];
  const messagingAvoid = [...new Set([...brandA.messaging_guidelines.avoid, ...brandB.messaging_guidelines.avoid])];

  // Step 4: AI-generated joint value propositions
  const jointValueProps = await generateJointValuePropositions(brandA, brandB, campaignContext);

  // Step 5: Co-branding guidelines
  const coBrandingGuidelines = {
    company_mention_order: [brandA.company_name, brandB.company_name].sort().join(' and '),
    logo_placement: 'equal',
    voice_balance: { [brandA.company_name]: 0.5, [brandB.company_name]: 0.5 },
    attribution_format: `${brandA.company_name} and ${brandB.company_name}`
  };

  return {
    harmonized_tone: harmonizedTone,
    shared_pain_points: sharedPainPoints,
    combined_goals: combinedGoals,
    messaging_guidelines: {
      do: messagingDo,
      avoid: messagingAvoid,
      conflicts_resolved: conflictsResolved
    },
    joint_value_propositions: jointValueProps,
    co_branding_guidelines: coBrandingGuidelines
  };
}

5. Job Queue Architecture

5.1 Queue Definitions

// Queue names and their purposes
const QUEUES = {
  CONTENT_GENERATION: 'content-generation',  // AI content generation jobs
  PUBLISHING: 'publishing',                   // Social/email publishing
  NOTIFICATIONS: 'notifications',             // Partner notifications
  ANALYTICS: 'analytics',                     // Event processing
  MATCHING: 'matching'                        // Partner matching calculations
};

// Job processors
const jobProcessors = {
  [QUEUES.CONTENT_GENERATION]: async (job) => {
    const { assetId, assetType, mergedVoice, objectives } = job.data;

    const content = await generateCobrandedContent(assetType, mergedVoice, objectives);

    await updateAsset(assetId, { content, status: 'pending_approval' });
    await notifyPartners(assetId, 'content_ready_for_review');
  },

  [QUEUES.PUBLISHING]: async (job) => {
    const { assetId, channel, scheduledTime } = job.data;

    // Wait until scheduled time
    if (Date.now() < scheduledTime) {
      throw new Error('Not yet scheduled'); // Will be retried
    }

    const asset = await getAsset(assetId);
    const result = await publishToChannel(channel, asset.content);

    await updateAsset(assetId, {
      published_at: new Date(),
      [`${channel}_result`]: result
    });
  }
};

5.2 Retry Configuration

const queueOptions = {
  [QUEUES.CONTENT_GENERATION]: {
    attempts: 3,
    backoff: {
      type: 'exponential',
      delay: 5000 // 5s, 10s, 20s
    }
  },
  [QUEUES.PUBLISHING]: {
    attempts: 5,
    backoff: {
      type: 'exponential',
      delay: 60000 // 1m, 2m, 4m, 8m, 16m
    }
  }
};

6. Caching Strategy

6.1 Cache Keys and TTLs

const CACHE_CONFIG = {
  // Partner matching scores - cache for 1 hour
  MATCH_SCORES: {
    pattern: 'match:scores:{partnerA}:{partnerB}',
    ttl: 3600
  },

  // Brand voice merge results - cache for 24 hours
  MERGED_VOICE: {
    pattern: 'merged:voice:{relationshipId}:{campaignType}',
    ttl: 86400
  },

  // Success predictions - cache for 6 hours
  PREDICTIONS: {
    pattern: 'prediction:{relationshipId}',
    ttl: 21600
  },

  // Partner profile summary - cache for 15 minutes
  PARTNER_SUMMARY: {
    pattern: 'partner:summary:{partnerId}',
    ttl: 900
  }
};

6.2 Cache Invalidation

// Events that trigger cache invalidation
const INVALIDATION_TRIGGERS = {
  'partner.profile.updated': ['PARTNER_SUMMARY', 'MATCH_SCORES'],
  'partner.icp.updated': ['MATCH_SCORES', 'PREDICTIONS'],
  'partner.brand_voice.updated': ['MERGED_VOICE'],
  'relationship.created': ['PREDICTIONS'],
  'relationship.status.changed': ['PREDICTIONS']
};

7. Monitoring and Metrics

7.1 Key Metrics to Track

const METRICS = {
  // Matching metrics
  'matching.requests': 'counter',
  'matching.duration_ms': 'histogram',
  'matching.qualified_count': 'histogram',
  'matching.disqualified_count': 'histogram',

  // Content generation metrics
  'content.generation.requests': 'counter',
  'content.generation.duration_ms': 'histogram',
  'content.generation.failures': 'counter',
  'content.generation.token_usage': 'counter',

  // Approval metrics
  'approval.time_to_decision_hours': 'histogram',
  'approval.revisions_per_asset': 'histogram',
  'approval.rejection_rate': 'gauge',

  // Publishing metrics
  'publishing.success_rate': 'gauge',
  'publishing.failures_by_channel': 'counter',
  'publishing.retry_count': 'histogram',

  // Business metrics
  'relationships.active': 'gauge',
  'campaigns.active': 'gauge',
  'assets.published_total': 'counter'
};

7.2 Alerting Thresholds

const ALERTS = {
  'content.generation.failures': {
    threshold: 5,
    window: '5m',
    severity: 'warning'
  },
  'publishing.success_rate': {
    threshold: 0.95,
    operator: 'lt',
    severity: 'critical'
  },
  'approval.time_to_decision_hours': {
    threshold: 168, // 7 days
    percentile: 'p95',
    severity: 'warning'
  }
};

8. Security Implementation

8.1 Authentication

// JWT token structure
interface JWTPayload {
  sub: string;           // User ID
  partner_id: string;    // Partner organization
  roles: string[];       // ['admin', 'editor', 'viewer']
  permissions: string[]; // ['campaigns.create', 'assets.approve']
  exp: number;           // Expiration timestamp
}

// Middleware for route protection
function requirePermission(permission: string) {
  return (req, res, next) => {
    if (!req.user.permissions.includes(permission)) {
      return res.status(403).json({ error: 'Insufficient permissions' });
    }
    next();
  };
}

8.2 Data Access Control

// Row-level security for partner data
function enforcePartnerAccess(query: Query, partnerId: string): Query {
  return query.where(builder => {
    builder
      .where('partner_a_id', partnerId)
      .orWhere('partner_b_id', partnerId);
  });
}

// Sensitive field redaction
function redactSensitiveFields(partner: Partner, viewerPartnerId: string): Partner {
  if (partner.id === viewerPartnerId) {
    return partner; // Full access to own data
  }

  // Redact sensitive fields for other partners
  return {
    ...partner,
    icp_definition: {
      ...partner.icp_definition,
      budget_range: undefined // Don't expose budget info
    }
  };
}

Document Version: 1.0 For Patent Application Support Confidential - Implementation Documentation