League-Sportsbook Matchmaking Platform
The League-Sportsbook Matchmaking Platform serves as an intelligent "dating service" between sports leagues and betting platforms, facilitating compliant, mutually beneficial partnerships. By combining self-service onboarding, AI-powered compatibility matching, real-time compliance monitoring, and tiered service levels, the system empowers league owners to achieve sportsbook integration while enabling sportsbooks to discover and connect with leagues meeting their specific technical and business requirements.
This platform extends the existing AltSportsLeagues.ai infrastructure, leveraging the schema-driven data layer, Google Cloud deployment, N8N webhook processing, and NextJS frontend architecture to provide a seamless, scalable matchmaking experience.
Executive Summary
The matchmaking platform addresses the core challenge of connecting sports leagues with sportsbooks in a compliant, efficient manner. Traditionally, this process involves manual outreach, inconsistent requirements, and lengthy compliance validation. The platform automates and streamlines this workflow, achieving >70% faster onboarding and >85% compliance accuracy.
Key Features:
- Self-Service Onboarding: League owners register, select sport domains, and configure preferences independently
- Intelligent Matching: AI-driven compatibility scoring across technical, business, and compliance dimensions
- Real-Time Compliance: Continuous monitoring of API and data quality against sportsbook requirements
- Tiered Services: Scalable pricing from starter (3 sportsbooks) to enterprise (unlimited)
- League NotebookLLM: AI-powered guidance for compliance remediation and league management
- Bidirectional Integration: Seamless sync with existing CRM, database, and webhook infrastructure
Architecture
High-Level Architecture
Schema-Driven Data Architecture
Building on the existing data_layer/output_styles/schemas/generated/adapters system:
New Domain Schemas (v1)
-
Matchmaking Schemas
matchmaking_profile_schema.json- League and sportsbook profilescompatibility_matrix_schema.json- Matching criteria and scorespartnership_request_schema.json- Connection requests and responses
-
Compliance Schemas
compliance_requirements_schema.json- Sportsbook-specific requirementscompliance_status_schema.json- Real-time compliance trackingremediation_steps_schema.json- Step-by-step guidance
-
Service Level Schemas
service_tier_schema.json- Pricing and feature tierssubscription_schema.json- User subscriptions and billing
Detailed Requirements
REQ-LSM-001: User Registration and Sport Domain Selection
User Story: As a league owner, I want to register and select my sport domain and target sportsbooks, so that I can begin the matchmaking process with relevant betting platforms.
Acceptance Criteria
- WHEN a new user registers, THE Self_Service_Portal SHALL present role selection options (owner, trader, admin)
- WHERE the user selects "owner", THE Self_Service_Portal SHALL display sport domain categories (combat, racing, action sports, competitive turn-taking sports, team player actions)
- WHEN a user selects a sport domain, THE Self_Service_Portal SHALL show subcategories (e.g., boxing, UFC for combat)
- THE Self_Service_Portal SHALL display available sportsbooks with priority ranking capability
- THE Self_Service_Portal SHALL allow users to select multiple sportsbooks in numbered priority order
Implementation Example (Frontend - NextJS)
// pages/register-league.tsx
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { SportDomainSchema } from 'data_layer/schemas/generated/adapters/typescript/v1/sport_domain_schema';
import { UserRegistrationSchema } from 'data_layer/schemas/generated/adapters/typescript/v1/user_registration_schema';
const RegistrationSchema = UserRegistrationSchema.extend({
sportDomain: SportDomainSchema,
targetSportsbooks: z.array(z.object({
id: z.string(),
priority: z.number().min(1)
})).min(1)
});
type RegistrationForm = z.infer<typeof RegistrationSchema>;
export default function LeagueRegistration() {
const [role, setRole] = useState<'owner' | 'trader' | 'admin'>();
const [sportDomain, setSportDomain] = useState<string>();
const [selectedSportsbooks, setSelectedSportsbooks] = useState<{id: string, priority: number}[]>([]);
const { register, handleSubmit, formState: { errors } } = useForm<RegistrationForm>({
resolver: zodResolver(RegistrationSchema)
});
const onSubmit = async (data: RegistrationForm) => {
// Submit to backend
const response = await fetch('/api/league/register', {
method: 'POST',
body: JSON.stringify(data)
});
if (response.ok) {
router.push('/dashboard');
}
};
if (!role) {
return (
<div className="space-y-4">
<h2>Select Your Role</h2>
<button onClick={() => setRole('owner')} className="btn-primary">League Owner</button>
<button onClick={() => setRole('trader')} className="btn-secondary">Trader</button>
<button onClick={() => setRole('admin')} className="btn-secondary">Admin</button>
</div>
);
}
if (role === 'owner' && !sportDomain) {
return (
<div className="space-y-4">
<h2>Select Sport Domain</h2>
<div className="grid grid-cols-2 gap-4">
<button onClick={() => setSportDomain('combat')} className="card">Combat Sports</button>
<button onClick={() => setSportDomain('racing')} className="card">Racing</button>
<button onClick={() => setSportDomain('action_sports')} className="card">Action Sports</button>
<button onClick={() => setSportDomain('team_player_actions')} className="card">Team Player Actions</button>
<button onClick={() => setSportDomain('competitive_turn_taking')} className="card">Competitive Turn-Taking</button>
</div>
</div>
);
}
// Sport domain selection and sportsbook priority
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email')} placeholder="Email" />
<input {...register('leagueName')} placeholder="League Name" />
<select {...register('sportDomain')} value={sportDomain}>
<option value="combat">Combat Sports</option>
{/* ... other options */}
</select>
<div>
<h3>Select Target Sportsbooks (Priority Order)</h3>
<DragDropList
items={availableSportsbooks}
onReorder={setSelectedSportsbooks}
/>
</div>
<button type="submit">Complete Registration</button>
</form>
);
}REQ-LSM-002: League NotebookLLM Section
User Story: As a league owner, I want access to a League NotebookLLM section, so that I can create leagues, manage resources, and track compliance status independently.
Acceptance Criteria
- THE Self_Service_Portal SHALL provide a League_NotebookLLM sidebar section for league owners
- WHEN accessing League_NotebookLLM, THE Self_Service_Portal SHALL allow creation of new leagues
- THE League_NotebookLLM SHALL enable adding data extraction resources and API testing capabilities
- THE League_NotebookLLM SHALL display real-time compliance status for each sportsbook requirement
- WHERE compliance gaps exist, THE League_NotebookLLM SHALL provide clear step-by-step remediation guidance
Implementation Example (Backend - Python/FastAPI)
# services/league_notebook_service.py
from fastapi import APIRouter, Depends
from pydantic import BaseModel
from typing import List, Optional
from data_layer.schemas.generated.adapters.python.v1.league_schema import LeagueSchema
from data_layer.schemas.generated.adapters.python.v1.compliance_status_schema import ComplianceStatusSchema
router = APIRouter(prefix="/api/league-notebook", tags=["League Notebook"])
class CreateLeagueRequest(BaseModel):
name: str
sport_domain: str
primary_contact: str
website: Optional[str] = None
api_endpoints: List[str] = []
@router.post("/leagues", response_model=LeagueSchema)
async def create_league(request: CreateLeagueRequest, user=Depends(get_current_user)):
"""Create a new league in the notebook"""
# Validate sport domain
sport_domain = await validate_sport_domain(request.sport_domain)
# Create league record
league = await league_repository.create({
"owner_id": user.id,
"name": request.name,
"sport_domain": sport_domain,
"primary_contact": request.primary_contact,
"website": request.website,
"api_endpoints": request.api_endpoints,
"compliance_status": "incomplete",
"created_at": datetime.utcnow()
})
# Initialize compliance tracking
await compliance_service.initialize_tracking(league.id)
return league
@router.get("/compliance/{league_id}", response_model=ComplianceStatusSchema)
async def get_compliance_status(league_id: str, user=Depends(get_current_user)):
"""Get real-time compliance status for league"""
# Verify ownership
league = await league_repository.get(league_id)
if league.owner_id != user.id:
raise HTTPException(403, "Not authorized")
# Get compliance status from all sportsbooks
compliance_data = await compliance_service.get_status(league_id)
# Generate remediation steps
remediation_steps = await ai_service.generate_remediation_steps(
league_id,
compliance_data.incomplete_requirements
)
return ComplianceStatusSchema(
league_id=league_id,
overall_score=compliance_data.overall_score,
complete_requirements=compliance_data.complete_requirements,
incomplete_requirements=compliance_data.incomplete_requirements,
remediation_steps=remediation_steps
)
@router.post("/api-test/{league_id}")
async def test_api_endpoint(
league_id: str,
endpoint: str,
test_data: dict,
user=Depends(get_current_user)
):
"""Test API endpoint compliance"""
# Verify ownership
league = await league_repository.get(league_id)
if league.owner_id != user.id:
raise HTTPException(403, "Not authorized")
try:
# Call external API
response = await httpx.AsyncClient().post(endpoint, json=test_data)
# Validate response
validation_result = await compliance_service.validate_api_response(
league_id,
endpoint,
response
)
return {
"endpoint": endpoint,
"status_code": response.status_code,
"response_time": response.elapsed.total_seconds(),
"validation": validation_result,
"passed": validation_result.passed
}
except Exception as e:
return {
"endpoint": endpoint,
"error": str(e),
"passed": False
}REQ-LSM-003: Real-Time Compliance Status
User Story: As a league owner, I want to see real-time compliance status across all my target sportsbooks, so that I can understand what requirements I need to meet for each partnership.
Acceptance Criteria
- THE Compliance_Status SHALL display real-time synchronization status with each selected sportsbook
- WHEN viewing compliance, THE Self_Service_Portal SHALL show specific requirements for each sportsbook (e.g., DraftKings combat requirements, Underdog racing requirements)
- THE Compliance_Status SHALL indicate completion percentage for each sportsbook's requirements
- WHERE requirements are incomplete, THE Self_Service_Portal SHALL provide actionable next steps
- THE Compliance_Status SHALL update automatically when league data or APIs change
Implementation Example (Frontend - React Component)
// components/ComplianceDashboard.tsx
import { useQuery } from '@tanstack/react-query';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Progress } from '@/components/ui/progress';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { ComplianceStatusSchema } from 'data_layer/schemas/generated/adapters/typescript/v1/compliance_status_schema';
import { useLeagueContext } from '@/contexts/LeagueContext';
export function ComplianceDashboard() {
const { leagueId } = useLeagueContext();
const { data: complianceStatus, isLoading } = useQuery<ComplianceStatusSchema>({
queryKey: ['compliance', leagueId],
queryFn: () => fetch(`/api/compliance/status/${leagueId}`).then(res => res.json()),
refetchInterval: 30000, // 30 seconds real-time updates
});
if (isLoading) return <div>Loading compliance status...</div>;
return (
<div className="space-y-6">
<Card>
<CardHeader>
<CardTitle>Overall Compliance Status</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="flex items-center justify-between">
<span>Compliance Score</span>
<span className="text-2xl font-bold">{complianceStatus?.overall_score ?? 0}%</span>
</div>
<Progress value={complianceStatus?.overall_score ?? 0} className="w-full" />
</div>
</CardContent>
</Card>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{complianceStatus?.sportsbook_compliance?.map((sportsbook) => (
<Card key={sportsbook.id}>
<CardHeader>
<CardTitle className="text-lg">{sportsbook.name}</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between">
<span>Completion</span>
<span>{sportsbook.completion_percentage}%</span>
</div>
<Progress value={sportsbook.completion_percentage} />
{sportsbook.incomplete_requirements.length > 0 && (
<Alert variant="destructive">
<AlertDescription>
<h4 className="font-medium">Incomplete Requirements ({sportsbook.incomplete_requirements.length})</h4>
<ul className="mt-2 space-y-1 list-disc list-inside">
{sportsbook.incomplete_requirements.slice(0, 3).map((req) => (
<li key={req.id} className="text-sm">
{req.name} - <span className="text-destructive">{req.status}</span>
</li>
))}
{sportsbook.incomplete_requirements.length > 3 && (
<li className="text-sm">... and {sportsbook.incomplete_requirements.length - 3} more</li>
)}
</ul>
</AlertDescription>
</Alert>
)}
</CardContent>
</Card>
))}
</div>
</div>
);
}REQ-LSM-004: Sportsbook Requirements Definition
User Story: As a sportsbook, I want to specify my league requirements and preferences, so that the system can match me with compatible leagues.
Acceptance Criteria
- THE Matchmaking_Engine SHALL allow sportsbooks to define their league requirements by sport domain
- THE Matchmaking_Engine SHALL enable sportsbooks to specify technical API requirements
- THE Matchmaking_Engine SHALL allow sportsbooks to set data quality and compliance standards
- WHEN requirements are updated, THE Matchmaking_Engine SHALL automatically re-evaluate existing league matches
- THE Matchmaking_Engine SHALL notify sportsbooks of new leagues meeting their criteria
Implementation Example (Backend - API Endpoints)
# api/sportsbook_requirements.py
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from typing import List, Dict
from data_layer.schemas.generated.adapters.python.v1.sportsbook_requirements_schema import SportsbookRequirementsSchema
router = APIRouter(prefix="/api/sportsbook", tags=["Sportsbook"])
class UpdateRequirementsRequest(BaseModel):
sport_domains: List[str]
technical_requirements: Dict[str, Any]
business_requirements: Dict[str, Any]
compliance_standards: List[str]
@router.post("/requirements/{sportsbook_id}")
async def update_requirements(
sportsbook_id: str,
request: UpdateRequirementsRequest,
user=Depends(get_current_sportsbook_user)
):
"""Update sportsbook league requirements"""
if user.sportsbook_id != sportsbook_id:
raise HTTPException(403, "Not authorized")
# Validate requirements
requirements = SportsbookRequirementsSchema(
sportsbook_id=sportsbook_id,
sport_domains=request.sport_domains,
technical_requirements=request.technical_requirements,
business_requirements=request.business_requirements,
compliance_standards=request.compliance_standards,
updated_at=datetime.utcnow()
)
# Store in database
await requirements_repository.update(sportsbook_id, requirements)
# Trigger re-evaluation of existing matches
await matchmaking_engine.reevaluate_matches_for_sportsbook(sportsbook_id)
# Notify of new potential matches
new_matches = await matchmaking_engine.find_new_matches(sportsbook_id)
if new_matches:
await notification_service.notify_new_matches(sportsbook_id, new_matches)
return {"status": "updated", "new_matches_found": len(new_matches)}
@router.get("/requirements/{sportsbook_id}", response_model=SportsbookRequirementsSchema)
async def get_requirements(sportsbook_id: str, user=Depends(get_current_sportsbook_user)):
"""Get current sportsbook requirements"""
if user.sportsbook_id != sportsbook_id:
raise HTTPException(403, "Not authorized")
return await requirements_repository.get(sportsbook_id)REQ-LSM-005: Tiered Service Levels
User Story: As a league owner, I want tiered service levels based on the number of sportsbook partnerships, so that I can choose a pricing plan that matches my business needs.
Acceptance Criteria
- THE Self_Service_Portal SHALL offer multiple Service_Level tiers based on sportsbook partnership quantity
- WHEN selecting a service level, THE Self_Service_Portal SHALL display clear pricing for each tier
- THE Service_Level SHALL determine the maximum number of sportsbook partnerships available
- THE Self_Service_Portal SHALL allow upgrading service levels as league needs grow
- WHERE payment is processed, THE Self_Service_Portal SHALL activate the selected service level immediately
Implementation Example (Service Tier Management)
# services/service_tier_service.py
from enum import Enum
from dataclasses import dataclass
from typing import Dict, List
from data_layer.schemas.generated.adapters.python.v1.service_tier_schema import ServiceTierSchema
class ServiceTier(Enum):
STARTER = "starter"
PROFESSIONAL = "professional"
ENTERPRISE = "enterprise"
@dataclass
class TierDefinition:
max_sportsbooks: int
price_monthly: float
features: List[str]
description: str
TIER_DEFINITIONS: Dict[ServiceTier, TierDefinition] = {
ServiceTier.STARTER: TierDefinition(
max_sportsbooks=3,
price_monthly=99.0,
features=[
"Basic compliance tracking",
"API endpoint testing",
"Up to 3 sportsbook matches"
],
description="Perfect for emerging leagues getting started with sportsbook partnerships"
),
ServiceTier.PROFESSIONAL: TierDefinition(
max_sportsbooks=10,
price_monthly=299.0,
features=[
"Advanced compliance monitoring",
"Priority matchmaking",
"Dedicated support",
"Up to 10 sportsbook matches",
"Custom integration assistance"
],
description="Ideal for established leagues seeking multiple partnerships"
),
ServiceTier.ENTERPRISE: TierDefinition(
max_sportsbooks=999,
price_monthly=999.0,
features=[
"White-label portal",
"Custom API development",
"Dedicated account manager",
"Unlimited sportsbook matches",
"Advanced analytics and reporting"
],
description="Complete solution for major leagues and sports organizations"
)
}
class ServiceTierService:
async def upgrade_tier(self, user_id: str, new_tier: ServiceTier) -> Subscription:
"""Upgrade user to new service tier"""
# Validate tier availability
if new_tier not in TIER_DEFINITIONS:
raise ValueError(f"Invalid tier: {new_tier}")
# Process payment
payment_result = await self.payment_processor.charge(
user_id=user_id,
amount=TIER_DEFINITIONS[new_tier].price_monthly,
description=f"Service tier upgrade to {new_tier.value}"
)
if not payment_result.success:
raise PaymentError("Payment failed")
# Update subscription
subscription = await subscription_repository.update(
user_id=user_id,
tier=new_tier,
active=True,
activated_at=datetime.utcnow(),
expires_at=datetime.utcnow() + timedelta(days=30)
)
# Update available sportsbooks limit
await user_repository.update_sportsbook_limit(
user_id=user_id,
limit=TIER_DEFINITIONS[new_tier].max_sportsbooks
)
# Notify user
await notification_service.send_tier_upgrade_notification(
user_id=user_id,
tier=new_tier,
features=TIER_DEFINITIONS[new_tier].features
)
return subscription
async def get_available_tiers(self, user_id: str) -> List[ServiceTierSchema]:
"""Get available service tiers for user"""
current_subscription = await subscription_repository.get(user_id)
tiers = []
for tier, definition in TIER_DEFINITIONS.items():
tier_schema = ServiceTierSchema(
tier=tier.value,
max_sportsbooks=definition.max_sportsbooks,
price_monthly=definition.price_monthly,
features=definition.features,
description=definition.description,
available=(current_subscription is None or current_subscription.tier != tier)
)
tiers.append(tier_schema)
return tiersREQ-LSM-006: Backend Infrastructure Integration
User Story: As a system administrator, I want the matchmaking system to integrate with our existing backend infrastructure, so that it leverages our current Google Cloud, database, and N8N webhook capabilities.
Acceptance Criteria
- THE Matchmaking_Engine SHALL integrate with the existing Google Cloud dockerized backend
- THE Self_Service_Portal SHALL support direct database mutations for real-time updates
- THE Matchmaking_Engine SHALL utilize existing N8N services for webhook processing and JSON payload handling
- THE Self_Service_Portal SHALL maintain compatibility with the current NextJS frontend architecture
- WHERE data synchronization occurs, THE Matchmaking_Engine SHALL ensure consistency across all integrated systems
Implementation Example (N8N Webhook Integration)
# services/n8n_integration_service.py
import httpx
from typing import Dict, Any
class N8NIntegrationService:
def __init__(self, n8n_base_url: str, api_key: str):
self.base_url = n8n_base_url
self.api_key = api_key
self.client = httpx.AsyncClient(
base_url=n8n_base_url,
headers={"Authorization": f"Bearer {api_key}"}
)
async def trigger_compliance_webhook(self, league_id: str, event: str, data: Dict[str, Any]):
"""Trigger N8N workflow for compliance updates"""
payload = {
"league_id": league_id,
"event": event,
"data": data,
"timestamp": datetime.utcnow().isoformat()
}
# Trigger N8N workflow
response = await self.client.post("/webhook/compliance-update", json=payload)
if response.status_code != 200:
logger.error("N8N webhook failed", status=response.status_code, payload=payload)
raise N8NIntegrationError(f"Webhook failed: {response.status_code}")
return response.json()
async def process_sportsbook_webhook(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Process incoming webhook from sportsbook about requirements change"""
try:
sportsbook_id = payload.get("sportsbook_id")
requirements = payload.get("requirements")
# Update requirements in database
await requirements_repository.update_from_webhook(
sportsbook_id=sportsbook_id,
requirements=requirements
)
# Trigger re-matching for affected leagues
affected_leagues = await matchmaking_engine.find_affected_leagues(sportsbook_id)
for league_id in affected_leagues:
await self.recalculate_matches(league_id, sportsbook_id)
return {"status": "processed", "affected_leagues": len(affected_leagues)}
except Exception as e:
logger.error("Webhook processing failed", error=str(e), payload=payload)
return {"status": "error", "message": str(e)}REQ-LSM-007: API Compliance Testing
User Story: As a league owner, I want to test my API compliance and data quality, so that I can ensure my league meets sportsbook technical requirements before going live.
Acceptance Criteria
- THE League_NotebookLLM SHALL provide API testing tools for each sportsbook integration
- WHEN testing APIs, THE League_NotebookLLM SHALL validate data format, completeness, and update frequency
- THE API_Compliance SHALL show real-time test results and error reporting
- WHERE API tests fail, THE League_NotebookLLM SHALL provide specific error messages and remediation steps
- THE League_NotebookLLM SHALL allow retesting after fixes are implemented
Implementation Example (API Testing Service)
# services/api_compliance_tester.py
import httpx
import json
from typing import Dict, Any, List
from pydantic import ValidationError
from data_layer.schemas.generated.adapters.python.v1.api_test_results_schema import ApiTestResultsSchema
class ApiComplianceTester:
async def test_api_endpoint(
self,
league_id: str,
endpoint_url: str,
test_cases: List[Dict[str, Any]],
expected_schema: str
) -> ApiTestResultsSchema:
"""Test API endpoint against sportsbook requirements"""
results = []
overall_passed = True
for test_case in test_cases:
try:
# Make API call
response = await httpx.AsyncClient(
timeout=10.0,
headers={"Authorization": f"Bearer {test_case.get('token')}"}
).post(endpoint_url, json=test_case["payload"])
# Validate response
response_json = response.json()
# Schema validation
try:
validated_response = ApiTestResultsSchema(**response_json)
schema_passed = True
except ValidationError as e:
schema_passed = False
validation_errors = e.errors()
# Performance validation
response_time = response.elapsed.total_seconds()
performance_passed = response_time < test_case.get("max_response_time", 2.0)
# Status code validation
status_passed = response.status_code == test_case.get("expected_status", 200)
test_result = {
"test_case_id": test_case["id"],
"endpoint": endpoint_url,
"status_code": response.status_code,
"response_time": response_time,
"schema_passed": schema_passed,
"performance_passed": performance_passed,
"status_passed": status_passed,
"response_sample": response_json if len(str(response_json)) < 1000 else "Truncated",
"validation_errors": validation_errors if not schema_passed else None
}
results.append(test_result)
overall_passed = overall_passed and (
schema_passed and performance_passed and status_passed
)
except Exception as e:
test_result = {
"test_case_id": test_case["id"],
"endpoint": endpoint_url,
"error": str(e),
"schema_passed": False,
"performance_passed": False,
"status_passed": False
}
results.append(test_result)
overall_passed = False
# Generate remediation steps
remediation_steps = await self.generate_remediation_guidance(results, expected_schema)
return ApiTestResultsSchema(
league_id=league_id,
endpoint=endpoint_url,
test_results=results,
overall_passed=overall_passed,
remediation_steps=remediation_steps,
tested_at=datetime.utcnow()
)
async def generate_remediation_guidance(
self,
test_results: List[Dict],
expected_schema: str
) -> List[str]:
"""Generate AI-powered remediation guidance"""
failed_tests = [r for r in test_results if not r["overall_passed"]]
if not failed_tests:
return ["All tests passed! Your API is ready for integration."]
prompt = f"""
Based on these failed API tests, provide specific, actionable remediation steps:
Failed Tests: {json.dumps(failed_tests, indent=2)}
Expected Schema: {expected_schema}
For each failure, provide:
1. What went wrong
2. Why it matters for sportsbook integration
3. Specific steps to fix
4. Code examples where applicable
Format as numbered list of remediation steps.
"""
response = await self.ai_service.generate_text(prompt)
return response.split('\n') if response else []REQ-LSM-008: Real-Time Connections Dashboard
User Story: As a league owner, I want to view all my connections and services in real-time, so that I can monitor the health and status of my sportsbook partnerships.
Acceptance Criteria
- THE Self_Service_Portal SHALL display a real-time dashboard of all active sportsbook connections
- THE Self_Service_Portal SHALL show connection health, data sync status, and partnership performance metrics
- WHEN connection issues occur, THE Self_Service_Portal SHALL provide immediate alerts and diagnostic information
- THE Self_Service_Portal SHALL allow manual refresh of connection status for troubleshooting
- WHERE partnerships are inactive, THE Self_Service_Portal SHALL indicate reasons and suggested actions
Implementation Example (Real-Time Dashboard - React with WebSockets)
// components/ConnectionsDashboard.tsx
import { useState, useEffect } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { io } from 'socket.io-client';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { AlertCircle, CheckCircle, Clock, RefreshCw } from 'lucide-react';
import { ConnectionStatusSchema } from 'data_layer/schemas/generated/adapters/typescript/v1/connection_status_schema';
export function ConnectionsDashboard() {
const [connections, setConnections] = useState<ConnectionStatusSchema[]>([]);
const [isRefreshing, setIsRefreshing] = useState(false);
const queryClient = useQueryClient();
useEffect(() => {
// Initialize WebSocket for real-time updates
const socket = io('/api/ws/connections');
socket.on('connection_update', (updatedConnection: ConnectionStatusSchema) => {
setConnections(prev =>
prev.map(conn => conn.sportsbook_id === updatedConnection.sportsbook_id
? updatedConnection
: conn
)
);
});
socket.on('connection_alert', (alert: any) => {
// Show toast notification
toast.error(`Connection issue: ${alert.message}`);
});
// Load initial data
loadConnections();
return () => socket.disconnect();
}, []);
const loadConnections = async () => {
const data = await queryClient.fetchQuery({
queryKey: ['connections'],
queryFn: () => fetch('/api/connections/status').then(res => res.json())
});
setConnections(data);
};
const handleManualRefresh = async () => {
setIsRefreshing(true);
await loadConnections();
setIsRefreshing(false);
};
const getStatusVariant = (status: string) => {
switch (status) {
case 'active': return 'default' as const;
case 'degraded': return 'secondary' as const;
case 'disconnected': return 'destructive' as const;
case 'pending': return 'outline' as const;
default: return 'ghost' as const;
}
};
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<h2 className="text-2xl font-bold">Sportsbook Connections</h2>
<button
onClick={handleManualRefresh}
disabled={isRefreshing}
className="flex items-center gap-2 btn-secondary"
>
{isRefreshing ? <RefreshCw className="h-4 w-4 animate-spin" /> : <RefreshCw className="h-4 w-4" />}
Refresh
</button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{connections.map((connection) => (
<Card key={connection.sportsbook_id}>
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle className="text-lg">{connection.sportsbook_name}</CardTitle>
<Badge variant={getStatusVariant(connection.status)}>
{connection.status}
</Badge>
</div>
<p className="text-sm text-muted-foreground">
Connected since {new Date(connection.connected_at).toLocaleDateString()}
</p>
</CardHeader>
<CardContent className="space-y-4">
{/* Health Metrics */}
<div className="grid grid-cols-2 gap-4 text-sm">
<div>
<span className="text-muted-foreground">Data Sync</span>
<div className="flex items-center gap-2 mt-1">
{connection.data_sync_status === 'healthy' ? (
<CheckCircle className="h-4 w-4 text-green-500" />
) : (
<AlertCircle className="h-4 w-4 text-destructive" />
)}
<span>{connection.data_sync_status}</span>
</div>
</div>
<div>
<span className="text-muted-foreground">Last Update</span>
<div className="flex items-center gap-2 mt-1">
<Clock className="h-4 w-4" />
<span>{connection.last_update_ago}</span>
</div>
</div>
<div>
<span className="text-muted-foreground">Compliance</span>
<Progress value={connection.compliance_score} className="mt-1" />
<span className="text-xs text-muted-foreground">{connection.compliance_score}%</span>
</div>
<div>
<span className="text-muted-foreground">Performance</span>
<div className="flex items-center gap-2 mt-1">
<span className="text-sm font-medium">{connection.avg_response_time}ms</span>
</div>
</div>
</div>
{/* Alerts */}
{connection.has_issues && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>
{connection.issue_description}
<div className="mt-2">
<button className="text-xs underline">View Diagnostics</button>
</div>
</AlertDescription>
</Alert>
)}
</CardContent>
</Card>
))}
</div>
{connections.length === 0 && (
<Card>
<CardContent className="text-center py-12">
<p className="text-muted-foreground">No active connections. Complete your profile to start matching with sportsbooks.</p>
</CardContent>
</Card>
)}
</div>
);
}Non-Functional Requirements
Performance Requirements
- Real-Time Updates: Compliance status refreshes every 30 seconds without blocking UI
- API Response Time: <200ms for matchmaking queries and compliance checks
- Concurrent Users: Support 500+ simultaneous league owners browsing matches
- Data Sync Latency: <5 seconds for webhook-processed updates
- Dashboard Load: <2 seconds initial load with 50+ connection cards
Reliability Requirements
- System Availability: 99.9% uptime for matchmaking and compliance services
- Data Consistency: Eventual consistency within 10 seconds across distributed systems
- Error Recovery: Automatic retry for transient API failures with exponential backoff
- Graceful Degradation: Continue matchmaking with cached data during outages
- Backup Strategy: Daily database snapshots with 7-day retention
Security Requirements
- Authentication: JWT-based auth with role-based access control
- Data Privacy: PII encrypted at rest and in transit, GDPR compliant
- API Security: Rate limiting, input validation, and OAuth2 for external integrations
- Audit Logging: Complete audit trail for all matchmaking actions and compliance changes
- Access Control: Sportsbook requirements only visible to authorized personnel
Maintainability Requirements
- Modular Design: Independent deployment of matchmaking engine and compliance tracker
- Schema Versioning: Backward-compatible schema evolution with migration tools
- Monitoring: Comprehensive metrics for all services (Prometheus/Grafana integration)
- Documentation: Auto-generated API docs and schema documentation
- Testing Coverage: >90% unit test coverage, >80% integration test coverage
Success Metrics
User Adoption
- Registration Completion: >70% of started registrations complete onboarding
- Service Tier Upgrade: 25% of starter users upgrade to professional within 90 days
- Active Usage: >60% monthly active users in League NotebookLLM
- Compliance Improvement: Average compliance score increases 20% within 30 days
Matchmaking Effectiveness
- Match Quality: >80% of recommended matches result in partnership discussions
- Conversion Rate: >40% of matches lead to active integrations
- User Satisfaction: NPS > 70 for matchmaking experience
- False Positives: <5% of matches fail due to undisclosed requirements
Technical Performance
- System Reliability: 99.9% uptime, <1% error rate on critical paths
- Response Times: P95 < 300ms for API calls, P95 < 2s for dashboard loads
- Scalability: Handle 10x user growth without performance degradation
- Data Accuracy: >95% accuracy in compliance assessments and matchmaking scores
Business Impact
- Revenue Growth: $500K ARR from service tier subscriptions within first year
- Partnership Velocity: 3x faster league-to-sportsbook connection time vs. manual processes
- Market Penetration: 20% of target leagues in top 5 sport domains onboarded
- Compliance Efficiency: 80% reduction in manual compliance validation time
Error Handling
Compliance Validation Errors
- API Endpoint Failures: Detailed error messages with remediation steps
- Data Quality Issues: Specific field-level validation errors
- Authentication Problems: Clear guidance on credential setup
- Rate Limiting: Automatic retry logic with exponential backoff
Matchmaking Errors
- No Compatible Sportsbooks: Suggestions for improving league profile
- Tier Limitations: Clear upgrade path messaging
- Incomplete Profiles: Step-by-step completion guidance
Testing Strategy
Unit Testing
- Schema Validation: Test all Pydantic models against edge cases
- Matchmaking Algorithm: Comprehensive compatibility scoring tests
- Compliance Logic: Validation of all compliance rules and thresholds
Integration Testing
- API Endpoints: Full CRUD operations for all entities
- Database Operations: Test schema migrations and data consistency
- External Services: Mock sportsbook APIs and webhook processing
End-to-End Testing
- User Flows: Complete onboarding and matchmaking journeys
- Compliance Workflows: Full compliance assessment and remediation cycles
- Payment Processing: Service tier upgrades and billing integration
Performance Testing
- Real-time Updates: Compliance status refresh under load
- Matchmaking Speed: Algorithm performance with large datasets
- Database Queries: Neo4j relationship queries optimization
Integration Points
Existing Infrastructure Leverage
Schema Generation Pipeline
# Extend existing adapter generation for new schemas
python data_layer/schemas/scripts/generate_adapters.py --version v1 --target all --include matchmaking,compliance,service_tiersDatabase Integration
- PostgreSQL: Transactional data using existing Drizzle adapters
- Redshift: Analytics and reporting using existing SQL adapters
- Neo4j: Relationship mapping using existing Cypher adapters
N8N Webhook Integration
{
"webhook_endpoints": {
"compliance_update": "/webhooks/compliance/update",
"sportsbook_requirements_change": "/webhooks/sportsbook/requirements",
"partnership_status_change": "/webhooks/partnership/status"
}
}Frontend Integration
- Existing NextJS Architecture: Extend current frontend with new routes
- Component Library: Reuse existing UI components for consistency
- Authentication: Leverage existing user management system
New Service Endpoints
Matchmaking API
// GET /api/matchmaking/compatible-sportsbooks/:league_id
// POST /api/matchmaking/request-partnership
// PUT /api/matchmaking/update-preferences/:league_idCompliance API
// GET /api/compliance/status/:league_id/:sportsbook_id
// POST /api/compliance/test-api/:league_id
// GET /api/compliance/remediation-steps/:league_id/:requirement_idService Tier API
// GET /api/service-tiers/available
// POST /api/service-tiers/subscribe
// PUT /api/service-tiers/upgrade/:user_idThis guide provides a complete overview of the League-Sportsbook Matchmaking Platform, detailing each requirement, implementation examples, and integration points to ensure successful deployment and operation of this critical business system.