using Management.Data;
using Management.Security;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
namespace Management.Controllers;
///
/// Onboarding endpoints for new user/client registration.
/// Requires JWT authentication (user may not have session yet).
///
/// ENDPOINTS:
/// GET /api/onboarding/status - Check registration status
/// POST /api/onboarding/register - Register new organization
///
[ApiController]
[Route("api/onboarding")]
public sealed class OnboardingController : ControllerBase
{
private readonly SqlService _sql;
private readonly ClientContext _client;
private readonly ILogger _log;
public OnboardingController(SqlService sql, ClientContext client, ILogger log)
{
_sql = sql;
_client = client;
_log = log;
}
///
/// Check registration status for authenticated user.
///
[HttpGet("status")]
public async Task Status(CancellationToken ct)
{
if (!_client.IsAuthenticated)
return Unauthorized(new { ok = false, error = "Valid Entra authentication required" });
var rqst = JsonSerializer.Serialize(new
{
provider = "EntraExternalId",
subject = _client.ClientId,
email = _client.Email
});
try
{
var resp = await _sql.ExecProcAsync("dbo.spOnboarding", "status", rqst, ct: ct);
if (string.IsNullOrWhiteSpace(resp))
return StatusCode(500, new { ok = false, error = "Service unavailable" });
return Content(resp, "application/json");
}
catch (Exception ex)
{
_log.LogError(ex, "[Onboarding] Status error");
return StatusCode(500, new { ok = false, error = "Status check failed", detail = ex.Message });
}
}
///
/// Register a new organization.
///
[HttpPost("register")]
public async Task Register([FromBody] RegisterRequest request, CancellationToken ct)
{
if (!_client.IsAuthenticated)
return Unauthorized(new { ok = false, error = "Valid Entra authentication required" });
if (string.IsNullOrWhiteSpace(request?.ClientName))
return BadRequest(new { ok = false, error = "clientName is required" });
_log.LogWarning("[Onboarding] Register | Subject={Subject} ClientName={ClientName}",
_client.ClientId, request.ClientName);
var rqst = JsonSerializer.Serialize(new
{
provider = "EntraExternalId",
subject = _client.ClientId,
email = _client.Email,
displayName = _client.ClientName,
clientName = request.ClientName.Trim()
});
try
{
var resp = await _sql.ExecProcAsync("dbo.spOnboarding", "register", rqst, ct: ct);
if (string.IsNullOrWhiteSpace(resp))
return StatusCode(500, new { ok = false, error = "Registration service unavailable" });
using var doc = JsonDocument.Parse(resp);
var root = doc.RootElement;
if (root.TryGetProperty("ok", out var okProp) && okProp.GetBoolean())
return Content(resp, "application/json");
var error = root.TryGetProperty("error", out var errProp) ? errProp.GetString() : "Registration failed";
return BadRequest(new { ok = false, error });
}
catch (Exception ex)
{
_log.LogError(ex, "[Onboarding] Register error");
return StatusCode(500, new { ok = false, error = "Registration failed", detail = ex.Message });
}
}
}
public sealed class RegisterRequest
{
public string? ClientName { get; set; }
}