using Microsoft.EntityFrameworkCore; using Tau.Acuvim.Portal.Configuration; using Tau.Acuvim.Portal.Data; namespace Tau.Acuvim.Portal.Services; // Startup-time validation that prevents the obvious "pointed dev at prod DB" / // "Admin mode against a Client DB" mistakes. public static class RunModeGuards { public static void ValidateConfig(ApplicationOptions app, DatabaseOptions database, FleetIngestOptions fleet) { if (app.RunMode == RunMode.Admin) { if (string.IsNullOrWhiteSpace(database.ConnectionString)) { throw new InvalidOperationException( "RunMode=Admin requires Database:ConnectionString. " + "AutoProvisionLocalTimescaleDb is not honoured for Admin (no obvious local default for a fleet DB)."); } } if (app.RunMode == RunMode.Client && fleet.Enabled) { if (string.IsNullOrWhiteSpace(fleet.Url) || string.IsNullOrWhiteSpace(fleet.Token)) { throw new InvalidOperationException( "FleetIngest:Enabled=true requires both FleetIngest:Url and FleetIngest:Token. " + "Disable FleetIngest or provide both via env vars / secrets."); } } } // Refuse to run Client against an Admin DB (fleet.Customers exists) or vice versa. // Cheap query — only runs once at startup. public static async Task ValidateDatabaseShapeAsync( IServiceProvider services, RunMode runMode, CancellationToken ct = default) { using var scope = services.CreateScope(); if (runMode == RunMode.Client) { var db = scope.ServiceProvider.GetService(); if (db is null) return; try { var hasFleet = await db.Database .SqlQuery($@"SELECT 1 AS ""Value"" FROM information_schema.tables WHERE table_schema='fleet' AND table_name='Customers' LIMIT 1") .ToListAsync(ct); if (hasFleet.Count > 0) { throw new InvalidOperationException( "RunMode=Client is pointed at a database that contains fleet.Customers (an Admin DB). " + "Check Database:ConnectionString."); } } catch (Microsoft.EntityFrameworkCore.DbUpdateException) { /* db not ready, migration runs next */ } } else { var db = scope.ServiceProvider.GetService(); if (db is null) return; try { var hasMonitoring = await db.Database .SqlQuery($@"SELECT 1 AS ""Value"" FROM information_schema.tables WHERE table_schema='monitoring' AND table_name='PowerMeasurements' LIMIT 1") .ToListAsync(ct); if (hasMonitoring.Count > 0) { throw new InvalidOperationException( "RunMode=Admin is pointed at a database that contains monitoring.PowerMeasurements (a Client DB). " + "Check Database:ConnectionString."); } } catch (Microsoft.EntityFrameworkCore.DbUpdateException) { /* db not ready */ } } } }