diff --git a/.claude/project-context.md b/.claude/project-context.md
index 97b464b..717f527 100644
--- a/.claude/project-context.md
+++ b/.claude/project-context.md
@@ -5,6 +5,15 @@
## RECENT CHANGES (This Session)
+**Seq Removal - Logging Cleanup (Dec 5, 2025):**
+- ✅ Removed Seq logging sink to eliminate commercial licensing concerns
+- ✅ Removed `Serilog.Sinks.Seq` NuGet package from DiunaBI.API.csproj
+- ✅ Removed Seq sink configuration from appsettings.Development.json
+- ✅ Kept Serilog (free, open-source) with Console + File sinks for production-ready logging
+- ✅ Build verified - no errors after Seq removal
+- Files modified: [DiunaBI.API.csproj](DiunaBI.API/DiunaBI.API.csproj), [appsettings.Development.json](DiunaBI.API/appsettings.Development.json)
+- Manual step required: Remove `seq` service from docker-compose.yml and add Docker log rotation config
+
**UI Reorganization (Dec 5, 2025):**
- ✅ Moved pages to feature-based folders: `Pages/Layers/`, `Pages/Jobs/`, `Pages/DataInbox/`
- ✅ Organized components: `Components/Layout/` (MainLayout, EmptyLayout, Routes), `Components/Auth/` (AuthGuard, LoginCard)
@@ -27,7 +36,7 @@
- UI: MudBlazor 8.0
- Real-time: SignalR (EntityChangeHub)
- Google: Sheets API, Drive API, OAuth
-- Logging: Serilog (Console, File, Seq)
+- Logging: Serilog (Console, File)
- Auth: JWT Bearer + Google OAuth
---
diff --git a/DiunaBI.API/DiunaBI.API.csproj b/DiunaBI.API/DiunaBI.API.csproj
index e464ea4..0e609e3 100644
--- a/DiunaBI.API/DiunaBI.API.csproj
+++ b/DiunaBI.API/DiunaBI.API.csproj
@@ -20,7 +20,6 @@
-
diff --git a/DiunaBI.API/Program.cs b/DiunaBI.API/Program.cs
index 0e08ff8..c530385 100644
--- a/DiunaBI.API/Program.cs
+++ b/DiunaBI.API/Program.cs
@@ -246,10 +246,6 @@ app.Use(async (context, next) =>
logger.LogError(ex, "❌ Failed to extract UserId from JWT token");
}
}
- else
- {
- logger.LogWarning("❌ No valid Bearer token found");
- }
await next(context);
});
diff --git a/DiunaBI.UI.Shared/Components/Auth/LoginCard.razor b/DiunaBI.UI.Shared/Components/Auth/LoginCard.razor
index 6f8b223..5f085f7 100644
--- a/DiunaBI.UI.Shared/Components/Auth/LoginCard.razor
+++ b/DiunaBI.UI.Shared/Components/Auth/LoginCard.razor
@@ -37,15 +37,36 @@
@_errorMessage
}
+
+ @if (_sessionExpired)
+ {
+
+ Your session has expired. Please sign in again.
+
+ }
@code {
private bool _isLoading = false;
private string _errorMessage = string.Empty;
+ private bool _sessionExpired = false;
private static LoginCard? _instance;
private bool _isInitialized = false;
+ protected override void OnInitialized()
+ {
+ // Check if sessionExpired query parameter is present
+ var uri = new Uri(NavigationManager.Uri);
+ var query = System.Web.HttpUtility.ParseQueryString(uri.Query);
+ _sessionExpired = query["sessionExpired"] == "true";
+
+ if (_sessionExpired)
+ {
+ Console.WriteLine("⚠️ Session expired - user redirected to login");
+ }
+ }
+
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
diff --git a/DiunaBI.UI.Shared/Extensions/ServiceCollectionExtensions.cs b/DiunaBI.UI.Shared/Extensions/ServiceCollectionExtensions.cs
index 9ecb8a1..6eb3624 100644
--- a/DiunaBI.UI.Shared/Extensions/ServiceCollectionExtensions.cs
+++ b/DiunaBI.UI.Shared/Extensions/ServiceCollectionExtensions.cs
@@ -17,14 +17,16 @@ public static class ServiceCollectionExtensions
Console.WriteLine($"🔧 Configuring HttpClient with BaseAddress: {baseUri}");
services.AddTransient();
+ services.AddTransient();
- // Configure named HttpClient with logging handler
+ // Configure named HttpClient with logging and 401 handling
// Note: Authentication is handled by AuthService setting DefaultRequestHeaders.Authorization
services.AddHttpClient("DiunaBI", client =>
{
client.BaseAddress = new Uri(baseUri);
Console.WriteLine($"✅ HttpClient BaseAddress set to: {client.BaseAddress}");
})
+ .AddHttpMessageHandler()
.AddHttpMessageHandler();
// Register a scoped HttpClient factory that services will use
diff --git a/DiunaBI.UI.Shared/Handlers/UnauthorizedResponseHandler.cs b/DiunaBI.UI.Shared/Handlers/UnauthorizedResponseHandler.cs
new file mode 100644
index 0000000..563586d
--- /dev/null
+++ b/DiunaBI.UI.Shared/Handlers/UnauthorizedResponseHandler.cs
@@ -0,0 +1,41 @@
+using Microsoft.AspNetCore.Components;
+using Microsoft.Extensions.DependencyInjection;
+using DiunaBI.UI.Shared.Services;
+
+namespace DiunaBI.UI.Shared.Handlers;
+
+public class UnauthorizedResponseHandler : DelegatingHandler
+{
+ private readonly IServiceProvider _serviceProvider;
+
+ public UnauthorizedResponseHandler(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ }
+
+ protected override async Task SendAsync(
+ HttpRequestMessage request,
+ CancellationToken cancellationToken)
+ {
+ var response = await base.SendAsync(request, cancellationToken);
+
+ // Check if response is 401 Unauthorized
+ if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
+ {
+ Console.WriteLine("⚠️ 401 Unauthorized response detected - clearing credentials and redirecting to login");
+
+ // Create a scope to get scoped services
+ using var scope = _serviceProvider.CreateScope();
+ var authService = scope.ServiceProvider.GetRequiredService();
+ var navigationManager = scope.ServiceProvider.GetRequiredService();
+
+ // Clear authentication
+ await authService.ClearAuthenticationAsync();
+
+ // Navigate to login page with session expired message
+ navigationManager.NavigateTo("/login?sessionExpired=true", forceLoad: true);
+ }
+
+ return response;
+ }
+}