pounce/backend/app/schemas/yield_domain.py
Yves Gugger bb7ce97330
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
Deploy: referral rewards antifraud + legal contact updates
2025-12-15 13:56:43 +01:00

287 lines
7.1 KiB
Python

"""
Pydantic schemas for Yield/Intent Routing feature.
"""
from datetime import datetime
from decimal import Decimal
from typing import Optional
from pydantic import BaseModel, Field
# ============================================================================
# Intent Detection
# ============================================================================
class IntentAnalysis(BaseModel):
"""Intent detection result for a domain."""
category: str
subcategory: Optional[str] = None
confidence: float = Field(ge=0.0, le=1.0)
keywords_matched: list[str] = []
suggested_partners: list[str] = []
monetization_potential: str # "high", "medium", "low"
class YieldValueEstimate(BaseModel):
"""Estimated yield value for a domain."""
estimated_monthly_min: int
estimated_monthly_max: int
currency: str = "CHF"
potential: str
confidence: float
geo: Optional[str] = None
class DomainYieldAnalysis(BaseModel):
"""Complete yield analysis for a domain."""
domain: str
intent: IntentAnalysis
value: YieldValueEstimate
partners: list[str] = []
monetization_potential: str
# ============================================================================
# Yield Domain CRUD
# ============================================================================
class YieldDomainCreate(BaseModel):
"""Create a new yield domain."""
domain: str = Field(..., min_length=3, max_length=255)
class YieldDomainUpdate(BaseModel):
"""Update yield domain settings."""
active_route: Optional[str] = None
landing_page_url: Optional[str] = None
status: Optional[str] = None
class YieldDomainResponse(BaseModel):
"""Yield domain response."""
id: int
domain: str
status: str
# Intent
detected_intent: Optional[str] = None
intent_confidence: float = 0.0
# Routing
active_route: Optional[str] = None
partner_name: Optional[str] = None
# DNS
dns_verified: bool = False
dns_verified_at: Optional[datetime] = None
connected_at: Optional[datetime] = None
# Stats
total_clicks: int = 0
total_conversions: int = 0
total_revenue: Decimal = Decimal("0")
currency: str = "CHF"
# Timestamps
activated_at: Optional[datetime] = None
created_at: datetime
class Config:
from_attributes = True
class YieldDomainListResponse(BaseModel):
"""List of yield domains with summary stats."""
domains: list[YieldDomainResponse]
total: int
# Aggregates
total_active: int = 0
total_revenue: Decimal = Decimal("0")
total_clicks: int = 0
# ============================================================================
# Transactions
# ============================================================================
class YieldTransactionResponse(BaseModel):
"""Single transaction record."""
id: int
event_type: str
partner_slug: str
click_id: Optional[str] = None
gross_amount: Decimal
net_amount: Decimal
currency: str
status: str
geo_country: Optional[str] = None
created_at: datetime
confirmed_at: Optional[datetime] = None
class Config:
from_attributes = True
class YieldTransactionListResponse(BaseModel):
"""List of transactions."""
transactions: list[YieldTransactionResponse]
total: int
# Aggregates
total_gross: Decimal = Decimal("0")
total_net: Decimal = Decimal("0")
# ============================================================================
# Payouts
# ============================================================================
class YieldPayoutResponse(BaseModel):
"""Payout record."""
id: int
amount: Decimal
currency: str
period_start: datetime
period_end: datetime
transaction_count: int
status: str
payment_method: Optional[str] = None
payment_reference: Optional[str] = None
created_at: datetime
completed_at: Optional[datetime] = None
class Config:
from_attributes = True
class YieldPayoutListResponse(BaseModel):
"""List of payouts."""
payouts: list[YieldPayoutResponse]
total: int
total_paid: Decimal = Decimal("0")
total_pending: Decimal = Decimal("0")
# ============================================================================
# Dashboard
# ============================================================================
class YieldDashboardStats(BaseModel):
"""Yield dashboard statistics."""
# Domain counts
total_domains: int = 0
active_domains: int = 0
pending_domains: int = 0
# Revenue (current month)
monthly_revenue: Decimal = Decimal("0")
monthly_clicks: int = 0
monthly_conversions: int = 0
# Lifetime
lifetime_revenue: Decimal = Decimal("0")
lifetime_clicks: int = 0
lifetime_conversions: int = 0
# Pending payout
pending_payout: Decimal = Decimal("0")
next_payout_date: Optional[datetime] = None
currency: str = "CHF"
class YieldDashboardResponse(BaseModel):
"""Complete yield dashboard data."""
stats: YieldDashboardStats
domains: list[YieldDomainResponse]
recent_transactions: list[YieldTransactionResponse]
top_domains: list[YieldDomainResponse]
# ============================================================================
# Partners
# ============================================================================
class AffiliatePartnerResponse(BaseModel):
"""Affiliate partner info (public view)."""
slug: str
name: str
network: str
intent_categories: list[str]
geo_countries: list[str]
payout_type: str
description: Optional[str] = None
logo_url: Optional[str] = None
class Config:
from_attributes = True
# ============================================================================
# DNS Verification
# ============================================================================
class DNSVerificationResult(BaseModel):
"""Result of DNS verification check."""
domain: str
verified: bool
expected_ns: list[str]
actual_ns: list[str]
cname_ok: bool = False
error: Optional[str] = None
checked_at: datetime
class DNSSetupInstructions(BaseModel):
"""DNS setup instructions for a domain."""
domain: str
# Option 1: Nameserver delegation
nameservers: list[str]
# Option 2: CNAME
cname_host: str
cname_target: str
# Verification
verification_url: str
# ============================================================================
# Activation Flow
# ============================================================================
class ActivateYieldRequest(BaseModel):
"""Request to activate a domain for yield."""
domain: str = Field(..., min_length=3, max_length=255)
accept_terms: bool = False
class ActivateYieldResponse(BaseModel):
"""Response after initiating yield activation."""
domain_id: int
domain: str
status: str
# Analysis
intent: IntentAnalysis
value_estimate: YieldValueEstimate
# Setup
dns_instructions: DNSSetupInstructions
message: str