diff --git a/src/dotnet/QuantEngine.Web/Client/Layout/AuthLayout.razor b/src/dotnet/QuantEngine.Web/Client/Layout/AuthLayout.razor
new file mode 100644
index 0000000..4f3f76d
--- /dev/null
+++ b/src/dotnet/QuantEngine.Web/Client/Layout/AuthLayout.razor
@@ -0,0 +1,3 @@
+@inherits LayoutComponentBase
+
+@Body
diff --git a/src/dotnet/QuantEngine.Web/Client/Layout/MainLayout.razor b/src/dotnet/QuantEngine.Web/Client/Layout/MainLayout.razor
index b4feea1..8ce1b45 100644
--- a/src/dotnet/QuantEngine.Web/Client/Layout/MainLayout.razor
+++ b/src/dotnet/QuantEngine.Web/Client/Layout/MainLayout.razor
@@ -2,74 +2,36 @@
@inject HttpClient Http
@inject AuthenticationStateProvider AuthStateProvider
@inject NavigationManager NavigationManager
-@using System.Net.Http.Json
-@using Microsoft.FluentUI.AspNetCore.Components
-@using QuantEngine.Web.Client.Infrastructure
-
-
-
-
-
- ☰
-
- QuantEngine v@appVersion
-
-
-
- 관리자 (@context.User.Identity?.Name)
-
- 로그아웃
-
-
-
-
-
-
+
+
+
+ QuantEngine v@appVersion
+
+
+
+ 관리자 (@context.User.Identity?.Name)
+ 로그아웃
+
+
+
-
-
-
- @if (navOpen)
- {
-
- }
+
+
+
+
+
+ QuantEngine v@appVersion
+ 배포: @buildTime
+
+
-
-
+
+
@Body
-
-
-
-
-
-
-
An unhandled error has occurred.
-
Reload
-
-
-
-
+
+
+
@code {
private bool navOpen = true;
@@ -89,7 +51,6 @@
}
catch
{
- // Fail-safe default fallback values
}
}
@@ -97,7 +58,7 @@
{
var customProvider = (CustomAuthenticationStateProvider)AuthStateProvider;
await customProvider.LogoutFromServerAsync();
- NavigationManager.NavigateTo("login");
+ NavigationManager.NavigateTo("/login");
}
private class VersionInfo
@@ -106,4 +67,3 @@
public string? Built { get; set; }
}
}
-
diff --git a/src/dotnet/QuantEngine.Web/Client/Layout/NavMenu.razor b/src/dotnet/QuantEngine.Web/Client/Layout/NavMenu.razor
index 974cb08..e6bee1c 100644
--- a/src/dotnet/QuantEngine.Web/Client/Layout/NavMenu.razor
+++ b/src/dotnet/QuantEngine.Web/Client/Layout/NavMenu.razor
@@ -1,10 +1,4 @@
-@using Microsoft.FluentUI.AspNetCore.Components
-
-
-
- Dashboard
-
-
- Operations
-
-
+
+ Dashboard
+ Operations
+
diff --git a/src/dotnet/QuantEngine.Web/Client/Pages/Collection.razor b/src/dotnet/QuantEngine.Web/Client/Pages/Collection.razor
index 1c70cfd..a7154e8 100644
--- a/src/dotnet/QuantEngine.Web/Client/Pages/Collection.razor
+++ b/src/dotnet/QuantEngine.Web/Client/Pages/Collection.razor
@@ -6,118 +6,88 @@
QuantEngine - Collection
-Data Collection
-
- KIS API data collection dashboard. Monitor runs, snapshots, and error trends.
-
+Data Collection
+KIS API data collection dashboard. API-first로만 동작합니다.
-
-
-
- @if (IsProcessing) { Running... } else { Start Collection }
-
-
- Refresh
-
-
+
+
+ @(IsProcessing ? "Running..." : "Start Collection")
+
+ Refresh
+
-
@if (IsLoading)
{
-
-
-
-
+
}
else if (DashboardState != null)
{
-
-
-
-
-
Last Run
-
@(DashboardState.LastRunStatus ?? "N/A")
-
@(DashboardState.LastFinishedAt ?? "Not finished")
-
-
-
-
-
Total Snapshots
-
@DashboardState.TotalSnapshots
-
-
-
-
-
Total Errors
-
@DashboardState.TotalErrors
-
-
-
+
+
+
+ Last Run
+ @(DashboardState.LastRunStatus ?? "N/A")
+ @(DashboardState.LastFinishedAt ?? "Not finished")
+
+
+
+
+ Total Snapshots
+ @DashboardState.TotalSnapshots
+
+
+
+
+ Total Errors
+ @DashboardState.TotalErrors
+
+
+
-
@if (DashboardState.RecentErrors.Count > 0)
{
-
-
-
Recent Errors
-
-
-
- | Source |
- Kind |
- Ticker |
- Message |
-
-
-
- @foreach (var error in DashboardState.RecentErrors)
- {
-
- | @error.SourceName |
- @error.ErrorKind |
- @error.Ticker |
- @error.ErrorMessage |
-
- }
-
-
-
-
+
+ Recent Errors
+
+
+ Source
+ Kind
+ Ticker
+ Message
+
+
+ @context.SourceName
+ @context.ErrorKind
+ @context.Ticker
+ @context.ErrorMessage
+
+
+
}
-
@if (RecentRuns != null && RecentRuns.Count > 0)
{
-
-
-
Recent Runs
-
-
-
- | Run ID |
- Status |
- Started |
- Finished |
- Snapshots |
- Errors |
-
-
-
- @foreach (var run in RecentRuns)
- {
-
- | @run.RunId |
- @run.Status |
- @run.StartedAt |
- @run.FinishedAt |
- @run.TotalSnapshots |
- @run.TotalErrors |
-
- }
-
-
-
-
+
+ Recent Runs
+
+
+ Run ID
+ Status
+ Started
+ Finished
+ Snapshots
+ Errors
+
+
+ @context.RunId
+ @context.Status
+ @context.StartedAt
+ @context.FinishedAt
+ @context.TotalSnapshots
+ @context.TotalErrors
+
+
+
}
}
@@ -138,7 +108,6 @@ else if (DashboardState != null)
try
{
DashboardState = await ApiClient.GetCollectionStateAsync();
-
var runsResponse = await ApiClient.GetCollectionRunsAsync(10);
RecentRuns = runsResponse?.Runs ?? new();
}
diff --git a/src/dotnet/QuantEngine.Web/Client/Pages/Dashboard.razor b/src/dotnet/QuantEngine.Web/Client/Pages/Dashboard.razor
index d22ffce..bc2def6 100644
--- a/src/dotnet/QuantEngine.Web/Client/Pages/Dashboard.razor
+++ b/src/dotnet/QuantEngine.Web/Client/Pages/Dashboard.razor
@@ -1,89 +1,84 @@
-@page "/"
+@page "/dashboard"
@attribute [Authorize]
@using QuantEngine.Core.Infrastructure
@inject HttpClient Http
Quant Engine - Dashboard
-Quant Engine
-
- 루트 화면은 운영 진입점입니다. 가짜 성과 수치 없이 현재 스냅샷 상태와 리포트 경로만 보여줍니다.
-
+Quant Engine
+운영 진입점입니다. 로그인 후 현재 스냅샷 상태와 리포트 경로만 표시합니다.
-
-
-
-
-
Operational Report
-
@ReportStateLabel
-
@ReportPath
-
-
-
-
-
Sections
-
@SectionCountLabel
-
Temp/operational_report.json
-
-
-
-
-
Primary Route
-
- Open Operations
-
-
-
-
+
+
+
+ Operational Report
+ @ReportStateLabel
+ @ReportPath
+
+
+
+
+ Sections
+ @SectionCountLabel
+ Temp/operational_report.json
+
+
+
+
+ Primary Route
+ Open Operations
+
+
+
-
-
-
-
-
Current State
-
- Status: @ReportChipLabel
- Generated: @GeneratedAtLabel
- Source: @SourceLabel
- Decision feed: @DecisionFeedLabel
- Factor feed: @FactorFeedLabel
- Raw feed: @RawFeedLabel
-
-
-
-
-
-
-
Routing Notes
-
+
+
+
+ Current State
+
+ Status: @ReportChipLabel
+ Generated: @GeneratedAtLabel
+ Source: @SourceLabel
+ Decision feed: @DecisionFeedLabel
+ Factor feed: @FactorFeedLabel
+ Raw feed: @RawFeedLabel
+
+
+
+
+
+ Routing Notes
+
- 운영 데이터는 snapshot 우선입니다.
- - Excel/GAS 의존 문구는 운영 경로에서 제거 대상입니다.
+ - Excel/GAS 의존 문구는 제거 대상입니다.
- 숫자는 provenance 없으면 표시하지 않습니다.
-
-
-
+
+
+
-
-
-
-
Coverage Summary
- @if (Sections.Count == 0)
- {
-
- DATA_MISSING: operational_report.json이 비어 있거나 아직 생성되지 않았습니다.
-
- }
- else
- {
-
-
-
-
-
- }
-
-
+
+ Coverage Summary
+ @if (Sections.Count == 0)
+ {
+ DATA_MISSING: operational_report.json이 비어 있거나 아직 생성되지 않았습니다.
+ }
+ else
+ {
+
+
+ Name
+ Title
+ Preview
+
+
+ @context.Name
+ @context.Title
+ @context.Preview
+
+
+ }
+
@code {
private readonly List Sections = new();
diff --git a/src/dotnet/QuantEngine.Web/Client/Pages/Login.razor b/src/dotnet/QuantEngine.Web/Client/Pages/Login.razor
index bc25fc1..02d72be 100644
--- a/src/dotnet/QuantEngine.Web/Client/Pages/Login.razor
+++ b/src/dotnet/QuantEngine.Web/Client/Pages/Login.razor
@@ -1,264 +1,54 @@
@page "/login"
@attribute [AllowAnonymous]
+@layout AuthLayout
@inject AuthenticationStateProvider AuthStateProvider
@inject NavigationManager NavigationManager
@inject HttpClient Http
로그인 - QuantEngine
-
-
-
-

-
QuantEngine
-
은퇴자산포트폴리오 투자 관리 시스템
-
+
+
+
+ Q
+ QuantEngine
+ 은퇴자산포트폴리오 투자 관리 시스템
+
-
-
-
+
+ @(IsSubmitting ? "인증 중..." : "로그인")
+
+
+
+
@@ -291,7 +81,6 @@
try
{
var response = await Http.PostAsJsonAsync("api/auth/login", new { Username, Password });
-
if (response.IsSuccessStatusCode)
{
var auth = await response.Content.ReadFromJsonAsync();
@@ -303,9 +92,7 @@
var customProvider = (CustomAuthenticationStateProvider)AuthStateProvider;
await customProvider.MarkUserAsAuthenticatedAsync(auth.Username ?? Username, auth.AccessToken, auth.Role ?? "Admin");
-
- // Redirect back to home dashboard
- NavigationManager.NavigateTo("");
+ NavigationManager.NavigateTo("/dashboard");
}
else
{
diff --git a/src/dotnet/QuantEngine.Web/Client/Pages/Operations.razor b/src/dotnet/QuantEngine.Web/Client/Pages/Operations.razor
index 9e44e3f..5c94800 100644
--- a/src/dotnet/QuantEngine.Web/Client/Pages/Operations.razor
+++ b/src/dotnet/QuantEngine.Web/Client/Pages/Operations.razor
@@ -3,87 +3,82 @@
@using QuantEngine.Core.Infrastructure
@inject HttpClient Http
-Quant Engine - Operations
+QuantEngine - Operations
-Operational Report
-
- 이 페이지는 `Temp/operational_report.json`만 읽습니다. DB 연결과 무관하게 동일한 결과를 보여주는 운영 고정 화면입니다.
-
+Operational Report
+Temp/operational_report.json만 읽는 운영 고정 화면입니다.
-
-
-
-
-
Schema
-
@SchemaVersion
-
-
-
-
-
Sections
-
@SectionCountLabel
-
-
-
-
-
-
-
-
Generated
-
@GeneratedAt
-
-
-
+
+
+
+ Schema
+ @SchemaVersion
+
+
+
+
+ Sections
+ @SectionCountLabel
+
+
+
+
+ Source
+ @SourceJson
+
+
+
+
+ Generated
+ @GeneratedAt
+
+
+
-
-
+
@foreach (var section in HighlightSections)
{
-
-
-
@(section.Name)
-
@(section.Title)
-
@(section.Preview)
-
-
+
+
+ @(section.Name)
+ @(section.Title)
+ @(section.Preview)
+
+
}
-
+
-
-
-
-
Report Health
-
- Status: @HealthLabel
- Path: @ReportPath
- Sections rendered: @RenderedSectionCountLabel
-
-
-
+
+ Report Health
+
+ Status: @HealthLabel
+ Path: @ReportPath
+ Sections rendered: @RenderedSectionCountLabel
+
+
-
-
-
-
Sections
- @if (Sections.Count == 0)
- {
-
- DATA_MISSING: operational_report.json에 표시할 섹션이 없습니다.
-
- }
- else
- {
-
-
-
-
-
- }
-
-
+
+ Sections
+ @if (Sections.Count == 0)
+ {
+ DATA_MISSING: operational_report.json에 표시할 섹션이 없습니다.
+ }
+ else
+ {
+
+
+ Name
+ Title
+ Preview
+
+
+ @context.Name
+ @context.Title
+ @context.Preview
+
+
+ }
+
@code {
private readonly List Sections = new();
@@ -106,7 +101,7 @@
SchemaVersion = report.SchemaVersion;
SourceJson = report.SourceJson;
GeneratedAt = report.GeneratedAt;
-
+
Sections.Clear();
Sections.AddRange(report.Sections);
diff --git a/src/dotnet/QuantEngine.Web/Client/Program.cs b/src/dotnet/QuantEngine.Web/Client/Program.cs
index 89b6b09..f7a2fc4 100644
--- a/src/dotnet/QuantEngine.Web/Client/Program.cs
+++ b/src/dotnet/QuantEngine.Web/Client/Program.cs
@@ -1,14 +1,10 @@
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
-using Microsoft.FluentUI.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using QuantEngine.Web.Client.Services;
using QuantEngine.Web.Client.Infrastructure;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
-// Register Fluent UI
-builder.Services.AddFluentUIComponents();
-
// Register LocalStorage for cross-platform session persistence
builder.Services.AddScoped();
diff --git a/src/dotnet/QuantEngine.Web/Client/QuantEngine.Web.Client.csproj b/src/dotnet/QuantEngine.Web/Client/QuantEngine.Web.Client.csproj
index ad69745..be0cf34 100644
--- a/src/dotnet/QuantEngine.Web/Client/QuantEngine.Web.Client.csproj
+++ b/src/dotnet/QuantEngine.Web/Client/QuantEngine.Web.Client.csproj
@@ -16,8 +16,7 @@
-
-
+
diff --git a/src/dotnet/QuantEngine.Web/Client/_Imports.razor b/src/dotnet/QuantEngine.Web/Client/_Imports.razor
index b98bd91..fe60c8a 100644
--- a/src/dotnet/QuantEngine.Web/Client/_Imports.razor
+++ b/src/dotnet/QuantEngine.Web/Client/_Imports.razor
@@ -6,8 +6,7 @@
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
-@using Microsoft.FluentUI.AspNetCore.Components
-@using Microsoft.FluentUI.AspNetCore.Components.Icons
+@using MudBlazor
@using QuantEngine.Web.Client
@using QuantEngine.Web.Client.Pages
@using QuantEngine.Web.Client.Layout
diff --git a/src/dotnet/QuantEngine.Web/Components/App.razor b/src/dotnet/QuantEngine.Web/Components/App.razor
index e12a7a9..39ac796 100644
--- a/src/dotnet/QuantEngine.Web/Components/App.razor
+++ b/src/dotnet/QuantEngine.Web/Components/App.razor
@@ -1,14 +1,13 @@
-
+
-
-
+
@@ -18,13 +17,14 @@
-
+
+
+
-
+
-
-
+
diff --git a/src/dotnet/QuantEngine.Web/Components/_Imports.razor b/src/dotnet/QuantEngine.Web/Components/_Imports.razor
index 9fae3a5..50a9bc5 100644
--- a/src/dotnet/QuantEngine.Web/Components/_Imports.razor
+++ b/src/dotnet/QuantEngine.Web/Components/_Imports.razor
@@ -6,8 +6,7 @@
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
-@using Microsoft.FluentUI.AspNetCore.Components
-@using Microsoft.FluentUI.AspNetCore.Components.Icons
+@using MudBlazor
@using QuantEngine.Web
@using QuantEngine.Web.Components
@using QuantEngine.Web.Components.Layout
diff --git a/src/dotnet/QuantEngine.Web/Program.cs b/src/dotnet/QuantEngine.Web/Program.cs
index d7179ba..78dc3c5 100644
--- a/src/dotnet/QuantEngine.Web/Program.cs
+++ b/src/dotnet/QuantEngine.Web/Program.cs
@@ -8,7 +8,6 @@ using QuantEngine.Core.Interfaces;
using QuantEngine.Application.Services;
using System.Text.Json;
using static QuantEngine.Application.Services.DataCollectionService;
-using Microsoft.FluentUI.AspNetCore.Components;
using Serilog;
using QuantEngine.Web.Client.Infrastructure;
using QuantEngine.Web.Client.Services;
@@ -19,6 +18,7 @@ using QuantEngine.Core.Models;
using Microsoft.AspNetCore.Authentication;
using System.Text.Encodings.Web;
using Microsoft.Extensions.Options;
+using MudBlazor.Services;
// Serilog Configuration with Telegram Sink
Log.Logger = new LoggerConfiguration()
@@ -43,8 +43,7 @@ builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddAuthorizationCore();
-// Fluent UI Services
-builder.Services.AddFluentUIComponents();
+builder.Services.AddMudServices();
// PostgreSQL Dapper Setup
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
@@ -112,6 +111,8 @@ app.UseAuthorization();
app.MapStaticAssets();
+app.MapGet("/", () => Results.Redirect("/login"));
+
// Collection API Endpoints (must be before MapRazorComponents)
app.MapCollectionEndpoints();
diff --git a/src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj b/src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj
index 38d8a2b..9ff8b4e 100644
--- a/src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj
+++ b/src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj
@@ -8,8 +8,7 @@
-
-
+