feat: improve admin observability and translation-first summaries
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using JobTrackerApi.Data;
|
||||
using JobTrackerApi.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@@ -29,6 +30,9 @@ public sealed class AdminSystemController : ControllerBase
|
||||
|
||||
public sealed record StorageStatusDto(string DataRoot, string DbPath, bool DbExists, long? DbSizeBytes, int CompanyCount, int JobCount, int DeletedCount);
|
||||
public sealed record EmailStatusDto(bool Enabled, string? Host, int Port, bool EnableSsl, string? From, string? FromName);
|
||||
public sealed record DatabaseStatusDto(string Provider, bool LooksConfigured, bool CanConnect, string? Target, bool UsesFileStorage, string? Warning);
|
||||
public sealed record RuntimeStatusDto(string Framework, string OSDescription, string ProcessArchitecture, string? MachineName);
|
||||
public sealed record AuthStatusDto(bool Required, bool HasJwtKey, bool GoogleConfigured, bool GmailConfigured);
|
||||
public sealed record SystemStatusDto(
|
||||
string Environment,
|
||||
string ContentRoot,
|
||||
@@ -37,6 +41,9 @@ public sealed class AdminSystemController : ControllerBase
|
||||
string? BuildStamp,
|
||||
StorageStatusDto Storage,
|
||||
EmailStatusDto Email,
|
||||
DatabaseStatusDto Database,
|
||||
RuntimeStatusDto Runtime,
|
||||
AuthStatusDto Auth,
|
||||
SummarizerMetrics Summarizer
|
||||
);
|
||||
|
||||
@@ -65,6 +72,8 @@ public sealed class AdminSystemController : ControllerBase
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<SystemStatusDto>> Get(CancellationToken cancellationToken)
|
||||
{
|
||||
var provider = (_cfg["Database:Provider"] ?? "sqlite").Trim().ToLowerInvariant();
|
||||
var usesFileStorage = provider is not "mysql" and not "mariadb";
|
||||
var dbPath = _paths.GetDbPath();
|
||||
var dbFile = new FileInfo(dbPath);
|
||||
|
||||
@@ -80,6 +89,53 @@ public sealed class AdminSystemController : ControllerBase
|
||||
|
||||
var commitSha = NormalizeBuildMetadata(_cfg["App:CommitSha"]);
|
||||
var buildStamp = NormalizeBuildMetadata(_cfg["App:BuildStamp"]);
|
||||
var connectionString = _cfg.GetConnectionString("JobTracker") ?? string.Empty;
|
||||
var looksConfigured = !string.IsNullOrWhiteSpace(connectionString) || usesFileStorage;
|
||||
|
||||
string? dbTarget;
|
||||
if (usesFileStorage)
|
||||
{
|
||||
dbTarget = dbPath;
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(connectionString))
|
||||
{
|
||||
dbTarget = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
dbTarget = connectionString.Split(';', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(part => part.Trim())
|
||||
.FirstOrDefault(part => part.StartsWith("server=", StringComparison.OrdinalIgnoreCase)
|
||||
|| part.StartsWith("host=", StringComparison.OrdinalIgnoreCase)
|
||||
|| part.StartsWith("database=", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
bool canConnect;
|
||||
try
|
||||
{
|
||||
canConnect = await _db.Database.CanConnectAsync(cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
canConnect = false;
|
||||
}
|
||||
|
||||
string? dbWarning = null;
|
||||
if (!looksConfigured)
|
||||
{
|
||||
dbWarning = "Connection string is missing.";
|
||||
}
|
||||
else if (!canConnect)
|
||||
{
|
||||
dbWarning = "Database connection failed.";
|
||||
}
|
||||
else if (!usesFileStorage && jobs.Count == 0 && companies == 0)
|
||||
{
|
||||
dbWarning = "Connected, but no data is present yet. Check whether this is the intended production database.";
|
||||
}
|
||||
|
||||
var gmailConfigured = !string.IsNullOrWhiteSpace((_cfg["Google:GmailClientSecret"] ?? string.Empty).Trim())
|
||||
&& !string.IsNullOrWhiteSpace((_cfg["Google:GmailRedirectUri"] ?? string.Empty).Trim());
|
||||
|
||||
return Ok(new SystemStatusDto(
|
||||
Environment: _env.EnvironmentName,
|
||||
@@ -104,6 +160,26 @@ public sealed class AdminSystemController : ControllerBase
|
||||
From: (_cfg["Email:From"] ?? string.Empty).Trim(),
|
||||
FromName: (_cfg["Email:FromName"] ?? string.Empty).Trim()
|
||||
),
|
||||
Database: new DatabaseStatusDto(
|
||||
Provider: provider,
|
||||
LooksConfigured: looksConfigured,
|
||||
CanConnect: canConnect,
|
||||
Target: dbTarget,
|
||||
UsesFileStorage: usesFileStorage,
|
||||
Warning: dbWarning
|
||||
),
|
||||
Runtime: new RuntimeStatusDto(
|
||||
Framework: RuntimeInformation.FrameworkDescription,
|
||||
OSDescription: RuntimeInformation.OSDescription,
|
||||
ProcessArchitecture: RuntimeInformation.ProcessArchitecture.ToString(),
|
||||
MachineName: Environment.MachineName
|
||||
),
|
||||
Auth: new AuthStatusDto(
|
||||
Required: _cfg.GetValue("Auth:Require", false),
|
||||
HasJwtKey: !string.IsNullOrWhiteSpace((_cfg["Auth:JwtKey"] ?? string.Empty).Trim()),
|
||||
GoogleConfigured: !string.IsNullOrWhiteSpace((_cfg["Auth:GoogleClientId"] ?? string.Empty).Trim()),
|
||||
GmailConfigured: gmailConfigured
|
||||
),
|
||||
Summarizer: summarizer
|
||||
));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user