Initial import into Gitea
This commit is contained in:
67
IntelligenceApi/Controllers/SpendDistributionController.cs
Normal file
67
IntelligenceApi/Controllers/SpendDistributionController.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using IntelligenceApi.Engines;
|
||||
using IntelligenceApi.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IntelligenceApi.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Spend distribution endpoint — the single public surface of IntelligenceApi.
|
||||
///
|
||||
/// Called exclusively by the Gateway (never directly by the client portal).
|
||||
/// The Gateway injects clientCategory from ClientContext before forwarding.
|
||||
///
|
||||
/// POST /api/spend-distribution
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/spend-distribution")]
|
||||
public sealed class SpendDistributionController : ControllerBase
|
||||
{
|
||||
private readonly EngineRouter _router;
|
||||
private readonly ILogger<SpendDistributionController> _log;
|
||||
|
||||
public SpendDistributionController(EngineRouter router, ILogger<SpendDistributionController> log)
|
||||
{
|
||||
_router = router;
|
||||
_log = log;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a spend distribution recommendation.
|
||||
/// clientCategory in the request body determines which engine runs.
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Recommend(
|
||||
[FromBody] SpendDistributionRequest? request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
if (request == null)
|
||||
return BadRequest(new { ok = false, error = "Request body required" });
|
||||
|
||||
if (request.MonthlyBudget <= 0)
|
||||
return BadRequest(new { ok = false, error = "monthlyBudget must be greater than zero" });
|
||||
|
||||
if (request.Keywords.Count == 0)
|
||||
return BadRequest(new { ok = false, error = "At least one keyword is required" });
|
||||
|
||||
_log.LogInformation(
|
||||
"[SpendDistribution] Request | Category={Category} Budget={Budget} Objective={Obj}",
|
||||
request.ClientCategory, request.MonthlyBudget, request.Objective);
|
||||
|
||||
try
|
||||
{
|
||||
var engine = _router.Resolve(request.ClientCategory);
|
||||
var response = await engine.RecommendAsync(request, ct);
|
||||
|
||||
_log.LogInformation(
|
||||
"[SpendDistribution] OK | Engine={Engine} Channels={N}",
|
||||
response.Metadata.Engine, response.Channels.Count);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.LogError(ex, "[SpendDistribution] Unhandled error");
|
||||
return StatusCode(500, new { ok = false, error = "Intelligence service error" });
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user