Initial import into Gitea
This commit is contained in:
137
Gateway/Models/ForecastModels.cs
Normal file
137
Gateway/Models/ForecastModels.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
namespace Gateway.Models;
|
||||
|
||||
// ════════════════════════════════════════════════
|
||||
// Request: Client → Gateway
|
||||
// ════════════════════════════════════════════════
|
||||
|
||||
public sealed class ChannelForecastRequest
|
||||
{
|
||||
/// <summary>Advertising objective: awareness, traffic, leads, sales</summary>
|
||||
public string Objective { get; set; } = "traffic";
|
||||
|
||||
/// <summary>Business category from wizard Step 1</summary>
|
||||
public string? BusinessCategory { get; set; }
|
||||
|
||||
/// <summary>Keywords from URL analysis (Step 1)</summary>
|
||||
public List<string> Keywords { get; set; } = new();
|
||||
|
||||
/// <summary>Geo targeting from audience step</summary>
|
||||
public ForecastGeoTargeting? GeoTargeting { get; set; }
|
||||
|
||||
/// <summary>Audience parameters from Step 2</summary>
|
||||
public ForecastAudience? Audience { get; set; }
|
||||
|
||||
/// <summary>Monthly budget in whole dollars</summary>
|
||||
public decimal MonthlyBudget { get; set; }
|
||||
|
||||
/// <summary>Channels to estimate (defaults to all selected)</summary>
|
||||
public List<string>? Channels { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ForecastGeoTargeting
|
||||
{
|
||||
public List<string>? ZipCodes { get; set; }
|
||||
public double? RadiusMiles { get; set; }
|
||||
public List<long>? GeoTargetIds { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ForecastAudience
|
||||
{
|
||||
public int? AgeMin { get; set; }
|
||||
public int? AgeMax { get; set; }
|
||||
public List<string>? Genders { get; set; }
|
||||
public List<string>? Interests { get; set; }
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════
|
||||
// Response: Gateway → Client (normalized)
|
||||
// ════════════════════════════════════════════════
|
||||
|
||||
public sealed class ChannelForecastResponse
|
||||
{
|
||||
public bool Ok { get; set; } = true;
|
||||
public string Objective { get; set; } = string.Empty;
|
||||
public decimal TotalBudget { get; set; }
|
||||
public List<ChannelEstimate> Channels { get; set; } = new();
|
||||
public ForecastRecommendation? Recommendation { get; set; }
|
||||
public ForecastMeta Metadata { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class ChannelEstimate
|
||||
{
|
||||
public string Provider { get; set; } = string.Empty;
|
||||
public int AllocationPercent { get; set; }
|
||||
public decimal AllocatedBudget { get; set; }
|
||||
public ChannelEstimateMetrics Estimates { get; set; } = new();
|
||||
public double EfficiencyScore { get; set; }
|
||||
public string StrengthLabel { get; set; } = string.Empty;
|
||||
public string Confidence { get; set; } = "none";
|
||||
public string DataSource { get; set; } = "none";
|
||||
}
|
||||
|
||||
public sealed class ChannelEstimateMetrics
|
||||
{
|
||||
public double Impressions { get; set; }
|
||||
public double? Reach { get; set; }
|
||||
public double Clicks { get; set; }
|
||||
public double Conversions { get; set; }
|
||||
public decimal AvgCpc { get; set; }
|
||||
public decimal AvgCpm { get; set; }
|
||||
public decimal? EstimatedCpa { get; set; }
|
||||
public double Ctr { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ForecastRecommendation
|
||||
{
|
||||
public string Summary { get; set; } = string.Empty;
|
||||
public List<string> Highlights { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class ForecastMeta
|
||||
{
|
||||
public DateTimeOffset GeneratedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
public string ForecastPeriod { get; set; } = "30 days";
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════
|
||||
// Objective-weighted scoring
|
||||
// ════════════════════════════════════════════════
|
||||
|
||||
public sealed class MetricWeights
|
||||
{
|
||||
public double Reach { get; }
|
||||
public double Impressions { get; }
|
||||
public double Cpm { get; }
|
||||
public double Clicks { get; }
|
||||
public double Cpc { get; }
|
||||
public double Ctr { get; }
|
||||
public double Conversions { get; }
|
||||
public double Cpa { get; }
|
||||
|
||||
public MetricWeights(double reach, double impressions, double cpm,
|
||||
double clicks, double cpc, double ctr, double conversions, double cpa)
|
||||
{
|
||||
Reach = reach; Impressions = impressions; Cpm = cpm;
|
||||
Clicks = clicks; Cpc = cpc; Ctr = ctr;
|
||||
Conversions = conversions; Cpa = cpa;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ObjectiveWeights
|
||||
{
|
||||
public static readonly Dictionary<string, MetricWeights> Weights = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
// reach imp cpm clicks cpc ctr conv cpa
|
||||
["awareness"] = new MetricWeights(0.35, 0.25, 0.20, 0.05, 0.05, 0.05, 0.00, 0.00),
|
||||
["traffic"] = new MetricWeights(0.05, 0.10, 0.10, 0.30, 0.30, 0.15, 0.00, 0.00),
|
||||
["leads"] = new MetricWeights(0.05, 0.05, 0.05, 0.15, 0.15, 0.10, 0.25, 0.20),
|
||||
["sales"] = new MetricWeights(0.05, 0.05, 0.05, 0.10, 0.10, 0.10, 0.30, 0.25),
|
||||
};
|
||||
|
||||
/// <summary>Fallback: balanced weights if objective not recognized</summary>
|
||||
public static readonly MetricWeights Default =
|
||||
new(0.10, 0.10, 0.10, 0.20, 0.20, 0.10, 0.10, 0.10);
|
||||
|
||||
public static MetricWeights For(string objective)
|
||||
=> Weights.TryGetValue(objective, out var w) ? w : Default;
|
||||
}
|
||||
109
Gateway/Models/MultiChannelConfig.cs
Normal file
109
Gateway/Models/MultiChannelConfig.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Gateway.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration for a single advertising channel provider.
|
||||
/// Populated from database (tbChannelConfig) via ChannelConfigService.
|
||||
/// Drives Gateway routing, wizard behavior, and validation.
|
||||
/// </summary>
|
||||
public sealed class ProviderConfig
|
||||
{
|
||||
/// <summary>Channel type key (e.g., "google_ads", "meta", "tiktok").</summary>
|
||||
public string ChannelType { get; set; } = "";
|
||||
|
||||
/// <summary>Display name for UI.</summary>
|
||||
public string DisplayName { get; set; } = "";
|
||||
|
||||
/// <summary>Short description shown in channel selection.</summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>Whether this channel is currently available for new campaigns.</summary>
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
/// <summary>Provider service endpoint URL (null = stub/disabled).</summary>
|
||||
public string? Endpoint { get; set; }
|
||||
|
||||
/// <summary>Internal API key for provider service authentication.</summary>
|
||||
public string? InternalKey { get; set; }
|
||||
|
||||
/// <summary>Whether this is a stub container (test mode).</summary>
|
||||
public bool IsStub { get; set; }
|
||||
|
||||
/// <summary>Minimum daily budget in USD for this channel.</summary>
|
||||
public decimal MinDailyBudget { get; set; }
|
||||
|
||||
/// <summary>Minimum monthly budget in USD for this channel.</summary>
|
||||
public decimal MinMonthlyBudget { get; set; }
|
||||
|
||||
/// <summary>Supported unified objectives (awareness, traffic, conversions, leads, sales).</summary>
|
||||
public List<string> SupportedObjectives { get; set; } = new();
|
||||
|
||||
/// <summary>Supported creative formats (text, image, video, carousel, etc.).</summary>
|
||||
public List<string> SupportedCreativeFormats { get; set; } = new();
|
||||
|
||||
/// <summary>Estimated approval time in hours.</summary>
|
||||
public int ApprovalEstimateHours { get; set; }
|
||||
|
||||
/// <summary>How often to refresh metrics from this provider (minutes).</summary>
|
||||
public int MetricsRefreshIntervalMinutes { get; set; } = 60;
|
||||
|
||||
/// <summary>Icon identifier for UI (e.g., "google", "meta", "tiktok").</summary>
|
||||
public string? Icon { get; set; }
|
||||
|
||||
/// <summary>Brand color hex for UI (e.g., "#4285F4").</summary>
|
||||
public string? Color { get; set; }
|
||||
|
||||
/// <summary>Auth method used by provider (oauth2, api_key, mcc).</summary>
|
||||
public string? AuthMethod { get; set; }
|
||||
|
||||
/// <summary>Key Vault secret name for provider credentials.</summary>
|
||||
public string? KeyVaultSecretName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maps provider-specific status strings to platform statuses.
|
||||
/// Keys are raw provider values (case-insensitive), values are platform statuses
|
||||
/// (draft, staged, pending, active, paused, completed, cancelled, error).
|
||||
/// </summary>
|
||||
public Dictionary<string, string> StatusMappings { get; set; } = new(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Global allocation and multi-channel settings.
|
||||
/// Loaded from appsettings.json "MultiChannel:Allocation" section (simple scalars only).
|
||||
/// </summary>
|
||||
public sealed class AllocationSettings
|
||||
{
|
||||
public decimal MinMultiChannelMonthlyBudget { get; set; } = 500.00m;
|
||||
public int MaxChannelsPerInitiative { get; set; } = 5;
|
||||
public string DefaultAllocationStrategy { get; set; } = "template";
|
||||
public int PerformanceEvalIntervalDays { get; set; } = 7;
|
||||
public int PerformanceLookbackDays { get; set; } = 14;
|
||||
public int PerformanceLearningPeriodDays { get; set; } = 14;
|
||||
public decimal MaxAllocationShiftPct { get; set; } = 15.00m;
|
||||
public decimal MinChannelAllocationPct { get; set; } = 10.00m;
|
||||
public decimal MaxChannelAllocationPct { get; set; } = 80.00m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Root multi-channel configuration.
|
||||
/// Channels are populated from DB via ChannelConfigService at startup.
|
||||
/// Allocation settings loaded from appsettings.json (simple scalars).
|
||||
/// </summary>
|
||||
public sealed class MultiChannelConfig
|
||||
{
|
||||
/// <summary>Per-provider configurations, keyed by channel type.</summary>
|
||||
public Dictionary<string, ProviderConfig> Channels { get; set; } = new();
|
||||
|
||||
/// <summary>Global allocation settings.</summary>
|
||||
public AllocationSettings Allocation { get; set; } = new();
|
||||
|
||||
/// <summary>Get only enabled providers.</summary>
|
||||
[JsonIgnore]
|
||||
public IEnumerable<ProviderConfig> EnabledChannels =>
|
||||
Channels.Values.Where(c => c.Enabled);
|
||||
|
||||
/// <summary>Look up a provider config by channel type.</summary>
|
||||
public ProviderConfig? GetChannel(string channelType) =>
|
||||
Channels.TryGetValue(channelType, out var config) ? config : null;
|
||||
}
|
||||
Reference in New Issue
Block a user