feat: improve admin observability and translation-first summaries

This commit is contained in:
cesnimda
2026-03-22 21:37:30 +01:00
parent 8014c1e890
commit 4c49ffb0d6
8 changed files with 585 additions and 261 deletions
@@ -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
));
}