fix: MudBlazor v8 compatibility, static asset conflict, deploy host domain
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 5s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 9s
Deploy to Production / Build & Deploy to Production (push) Failing after 2m32s

- fix CS0542: rename Users/Assets private members to _users/_assets
- fix CS0246: MudDialogInstance -> IMudDialogInstance
- fix AppTheme: PaletteLight/PaletteDark, string[] FontFamily, string typography values
- fix DataCollectionMonitoring: @(ticker.DataPointCount)개 Korean char parsing
- fix SchedulerService: add missing Hangfire namespaces, fix GetJobStatus return type
- fix Program.cs: move PostgreSQL setup above Hangfire registration
- fix ConfirmDialog: BackdropClick, Canceled spelling for MudBlazor v8
- fix static asset conflict: remove wwwroot/_framework from git tracking
- chore: add wwwroot/_framework/ to .gitignore
- ci: change DEPLOY_HOST from IP to quant.taxbaik.com domain
This commit is contained in:
2026-07-05 17:43:36 +09:00
parent 7daedbff3c
commit 543b327d27
446 changed files with 237 additions and 1494 deletions
@@ -9,10 +9,10 @@
CloseButton = false,
MaxWidth = MaxWidth.Small,
FullWidth = true,
DisableBackdropClick = true
BackdropClick = false
};
var parameters = new DialogParameters<ConfirmDialogContent>
var parameters = new DialogParameters<ConfirmDialog>
{
{ x => x.Title, title },
{ x => x.Message, message },
@@ -20,10 +20,10 @@
{ x => x.CancelText, cancelText }
};
var dialog = await dialogService.ShowAsync<ConfirmDialogContent>(title, parameters, options);
var dialog = await dialogService.ShowAsync<ConfirmDialog>(title, parameters, options);
var result = await dialog.Result;
return !result.Cancelled && (bool?)result.Data == true;
return !result.Canceled && (bool?)result.Data == true;
}
}
@@ -42,7 +42,7 @@
@code {
[CascadingParameter]
private MudDialogInstance MudDialog { get; set; }
private IMudDialogInstance MudDialog { get; set; }
[Parameter]
public string Title { get; set; } = "확인";
@@ -5,7 +5,7 @@
</MudNavLink>
<!-- Admin Section -->
<MudNavGroup Title="관리" Icon="@Icons.Material.Filled.Admin4">
<MudNavGroup Title="관리" Icon="@Icons.Material.Filled.AdminPanelSettings">
<MudNavLink Href="/users" Icon="@Icons.Material.Filled.People">사용자 관리</MudNavLink>
<MudNavLink Href="/monitoring" Icon="@Icons.Material.Filled.Timeline">데이터 수집</MudNavLink>
<MudNavLink Href="/settings" Icon="@Icons.Material.Filled.Settings">설정</MudNavLink>
@@ -140,7 +140,7 @@
마지막 수집: @ticker.LastCollectionTime.ToString("yyyy-MM-dd HH:mm:ss")
</MudText>
<MudText Typo="Typo.caption" Class="text-muted">
데이터 포인트: @ticker.DataPointCount개
데이터 포인트: @(ticker.DataPointCount)
</MudText>
</div>
}
@@ -53,7 +53,7 @@
<MudPaper Class="pa-4" Elevation="1">
<MudText Typo="Typo.h6" Class="mb-4">자산 구성</MudText>
<MudTable Items="@Assets" Dense="true" Hover="true" Striped="true">
<MudTable Items="@_assets" Dense="true" Hover="true" Striped="true">
<HeaderContent>
<MudTh>종목/펀드명</MudTh>
<MudTh>수량</MudTh>
@@ -168,7 +168,7 @@
</MudPaper>
@code {
private List<AssetModel> Assets = new();
private List<AssetModel> _assets = new();
private List<CategoryModel> AssetCategories = new();
private List<TradeModel> TradingHistory = new();
@@ -179,14 +179,14 @@
private async Task LoadAssets()
{
Assets = new List<AssetModel>
_assets = new List<AssetModel>
{
new AssetModel { Name = "삼성전자", Ticker = "005930", Quantity = 50, CurrentPrice = 70000, Value = 3500000, ReturnRate = 5.2, Ratio = 28.0 },
new AssetModel { Name = "LG화학", Ticker = "051910", Quantity = 30, CurrentPrice = 820000, Value = 24600000, ReturnRate = -2.1, Ratio = 19.6 },
new AssetModel { Name = "현대차", Ticker = "005380", Quantity = 40, CurrentPrice = 245000, Value = 9800000, ReturnRate = 8.5, Ratio = 7.8 },
new AssetModel { Name = "SK하이닉스", Ticker = "000660", Quantity = 25, CurrentPrice = 105000, Value = 2625000, ReturnRate = 12.3, Ratio = 2.1 },
new AssetModel { Name = "삼성중공업", Ticker = "010140", Quantity = 60, CurrentPrice = 85000, Value = 5100000, ReturnRate = 3.7, Ratio = 4.1 },
new AssetModel { Name = "포스코", Ticker = "005490", Quantity = 20, CurrentPrice = 75000, Value = 1500000, ReturnRate = -5.2, Ratio = 1.2 },
new AssetModel { Name = "삼성전자", Ticker = "005930", Quantity = 50, CurrentPrice = 70000, Value = 3500000, ReturnRate = 5.2M, Ratio = 28.0M },
new AssetModel { Name = "LG화학", Ticker = "051910", Quantity = 30, CurrentPrice = 820000, Value = 24600000, ReturnRate = -2.1M, Ratio = 19.6M },
new AssetModel { Name = "현대차", Ticker = "005380", Quantity = 40, CurrentPrice = 245000, Value = 9800000, ReturnRate = 8.5M, Ratio = 7.8M },
new AssetModel { Name = "SK하이닉스", Ticker = "000660", Quantity = 25, CurrentPrice = 105000, Value = 2625000, ReturnRate = 12.3M, Ratio = 2.1M },
new AssetModel { Name = "삼성중공업", Ticker = "010140", Quantity = 60, CurrentPrice = 85000, Value = 5100000, ReturnRate = 3.7M, Ratio = 4.1M },
new AssetModel { Name = "포스코", Ticker = "005490", Quantity = 20, CurrentPrice = 75000, Value = 1500000, ReturnRate = -5.2M, Ratio = 1.2M },
};
AssetCategories = new List<CategoryModel>
@@ -23,7 +23,7 @@
<!-- Users Table -->
<MudPaper Class="pa-4" Elevation="1">
@if (Users.Count == 0)
@if (_users.Count == 0)
{
<MudAlert Severity="Severity.Info">사용자가 없습니다.</MudAlert>
}
@@ -75,14 +75,14 @@
</MudPaper>
@code {
private List<UserModel> Users = new();
private List<UserModel> _users = new();
private string SearchQuery = "";
private IEnumerable<UserModel> FilteredUsers
{
get => string.IsNullOrEmpty(SearchQuery)
? Users
: Users.Where(u => u.Name.Contains(SearchQuery, StringComparison.OrdinalIgnoreCase) ||
? _users
: _users.Where(u => u.Name.Contains(SearchQuery, StringComparison.OrdinalIgnoreCase) ||
u.Email.Contains(SearchQuery, StringComparison.OrdinalIgnoreCase));
}
@@ -95,7 +95,7 @@
{
try
{
Users = new List<UserModel>
_users = new List<UserModel>
{
new UserModel
{
@@ -6,7 +6,7 @@ public static class AppTheme
{
public static MudTheme LightTheme => new()
{
Palette = new PaletteLight
PaletteLight = new PaletteLight
{
Primary = "#3f51b5",
Secondary = "#f50057",
@@ -30,97 +30,87 @@ public static class AppTheme
DividerLight = "#f5f5f5",
TableLines = "#e0e0e0",
LinesDefault = "#e0e0e0",
LinesInputBorder = "#bdbdbd",
TextDisabled = "rgba(0,0,0,0.38)",
BorderRadius = "4px",
OverlayShadow = "0 5px 5px -3px rgba(0,0,0,0.2), 0 8px 10px 1px rgba(0,0,0,0.14), 0 3px 14px 2px rgba(0,0,0,0.12)",
Elevation = new Dictionary<int, string>
{
{ 0, "none" },
{ 1, "0 2px 1px -1px rgba(0,0,0,0.2),0 1px 1px 0 rgba(0,0,0,0.14),0 1px 3px 0 rgba(0,0,0,0.12)" },
{ 2, "0 3px 1px -2px rgba(0,0,0,0.2),0 2px 2px 0 rgba(0,0,0,0.14),0 1px 5px 0 rgba(0,0,0,0.12)" },
{ 3, "0 3px 3px -2px rgba(0,0,0,0.2),0 3px 4px 0 rgba(0,0,0,0.14),0 1px 8px 0 rgba(0,0,0,0.12)" },
{ 4, "0 2px 4px -1px rgba(0,0,0,0.2),0 4px 5px 0 rgba(0,0,0,0.14),0 1px 10px 0 rgba(0,0,0,0.12)" },
}
LinesInputs = "#bdbdbd",
TextDisabled = "rgba(0,0,0,0.38)"
},
Typography = new Typography
{
Default = new DefaultTypography
{
FontFamily = "Roboto, sans-serif",
FontFamily = new[] { "Roboto", "sans-serif" },
FontSize = "1rem",
FontWeight = 400,
LineHeight = 1.5,
FontWeight = "400",
LineHeight = "1.5",
LetterSpacing = "0.5px"
},
H1 = new H1Typography
{
FontSize = "6rem",
FontWeight = 300,
LineHeight = 1.167,
FontWeight = "300",
LineHeight = "1.167",
LetterSpacing = "-0.015625em"
},
H2 = new H2Typography
{
FontSize = "3.75rem",
FontWeight = 300,
LineHeight = 1.2,
FontWeight = "300",
LineHeight = "1.2",
LetterSpacing = "-0.0083333333em"
},
H3 = new H3Typography
{
FontSize = "3rem",
FontWeight = 400,
LineHeight = 1.167,
FontWeight = "400",
LineHeight = "1.167",
LetterSpacing = "0em"
},
H4 = new H4Typography
{
FontSize = "2.125rem",
FontWeight = 500,
LineHeight = 1.235,
FontWeight = "500",
LineHeight = "1.235",
LetterSpacing = "0.0125em"
},
H5 = new H5Typography
{
FontSize = "1.5rem",
FontWeight = 500,
LineHeight = 1.334,
FontWeight = "500",
LineHeight = "1.334",
LetterSpacing = "0em"
},
H6 = new H6Typography
{
FontSize = "1.25rem",
FontWeight = 600,
LineHeight = 1.6,
FontWeight = "600",
LineHeight = "1.6",
LetterSpacing = "0.0125em"
},
Body1 = new Body1Typography
{
FontSize = "1rem",
FontWeight = 500,
LineHeight = 1.5,
FontWeight = "500",
LineHeight = "1.5",
LetterSpacing = "0.03125em"
},
Body2 = new Body2Typography
{
FontSize = "0.875rem",
FontWeight = 400,
LineHeight = 1.43,
FontWeight = "400",
LineHeight = "1.43",
LetterSpacing = "0.0178571429em"
},
Button = new ButtonTypography
{
FontSize = "0.875rem",
FontWeight = 600,
LineHeight = 1.75,
FontWeight = "600",
LineHeight = "1.75",
LetterSpacing = "0.0892857143em"
},
Caption = new CaptionTypography
{
FontSize = "0.75rem",
FontWeight = 400,
LineHeight = 1.66,
FontWeight = "400",
LineHeight = "1.66",
LetterSpacing = "0.0333333333em"
}
},
@@ -135,7 +125,7 @@ public static class AppTheme
public static MudTheme DarkTheme => new()
{
Palette = new PaletteDark
PaletteDark = new PaletteDark
{
Primary = "#bb86fc",
Secondary = "#03dac6",
@@ -159,18 +149,8 @@ public static class AppTheme
DividerLight = "#2c3e50",
TableLines = "#37474f",
LinesDefault = "#37474f",
LinesInputBorder = "#555555",
TextDisabled = "rgba(255,255,255,0.38)",
BorderRadius = "4px",
OverlayShadow = "0 5px 5px -3px rgba(0,0,0,0.2), 0 8px 10px 1px rgba(0,0,0,0.14), 0 3px 14px 2px rgba(0,0,0,0.12)",
Elevation = new Dictionary<int, string>
{
{ 0, "none" },
{ 1, "0 2px 1px -1px rgba(0,0,0,0.2),0 1px 1px 0 rgba(0,0,0,0.14),0 1px 3px 0 rgba(0,0,0,0.12)" },
{ 2, "0 3px 1px -2px rgba(0,0,0,0.2),0 2px 2px 0 rgba(0,0,0,0.14),0 1px 5px 0 rgba(0,0,0,0.12)" },
{ 3, "0 3px 3px -2px rgba(0,0,0,0.2),0 3px 4px 0 rgba(0,0,0,0.14),0 1px 8px 0 rgba(0,0,0,0.12)" },
{ 4, "0 2px 4px -1px rgba(0,0,0,0.2),0 4px 5px 0 rgba(0,0,0,0.14),0 1px 10px 0 rgba(0,0,0,0.12)" },
}
LinesInputs = "#555555",
TextDisabled = "rgba(255,255,255,0.38)"
},
Typography = LightTheme.Typography,
LayoutProperties = LightTheme.LayoutProperties
+11 -11
View File
@@ -50,17 +50,6 @@ builder.Services.AddAuthorizationCore();
builder.Services.AddMudServices();
// Hangfire Background Job Scheduling
try
{
var hangfireConnectionString = builder.Configuration.GetConnectionString("HangfireConnection") ?? connectionString;
builder.Services.AddHangfireServices(hangfireConnectionString);
}
catch (Exception ex)
{
Log.Warning("Hangfire initialization failed: {Message}", ex.Message);
}
// PostgreSQL Dapper Setup
var configuredConnectionString = builder.Configuration.GetConnectionString("DefaultConnection");
var fallbackConnectionString = "Host=127.0.0.1;Database=quantenginedb;Username=quantengine_app;Password=CHANGE_ME;Search Path=quantengine;";
@@ -79,6 +68,17 @@ builder.Services.AddScoped<IPostgresqlHistoryStore, PostgresqlHistoryStore>();
builder.Services.AddScoped<IPostgresqlHistorySnapshotReader, PostgresqlHistorySnapshotReader>();
builder.Services.AddScoped<HistoryIngestionService>();
// Hangfire Background Job Scheduling
try
{
var hangfireConnectionString = builder.Configuration.GetConnectionString("HangfireConnection") ?? connectionString;
builder.Services.AddHangfireServices(hangfireConnectionString);
}
catch (Exception ex)
{
Log.Warning("Hangfire initialization failed: {Message}", ex.Message);
}
// Collection Pipeline Services (PostgreSQL-backed implementations)
builder.Services.AddScoped<ICollectionRepository, CollectionRepository>();
builder.Services.AddScoped<ITokenCache, PostgresTokenCache>();
@@ -1,4 +1,8 @@
using Hangfire;
using Hangfire.States;
using Hangfire.Dashboard;
using Hangfire.SqlServer;
using System.Linq.Expressions;
using QuantEngine.Application.Services;
using QuantEngine.Infrastructure.Data;
@@ -12,18 +16,15 @@ public class SchedulerService
private readonly ILogger<SchedulerService> _logger;
private readonly IBackgroundJobClient _jobClient;
private readonly IRecurringJobManager _recurringJobManager;
private readonly IKisApiPriceSource _kisApi;
public SchedulerService(
ILogger<SchedulerService> logger,
IBackgroundJobClient jobClient,
IRecurringJobManager recurringJobManager,
IKisApiPriceSource kisApi)
IRecurringJobManager recurringJobManager)
{
_logger = logger;
_jobClient = jobClient;
_recurringJobManager = recurringJobManager;
_kisApi = kisApi;
}
/// <summary>
@@ -195,7 +196,7 @@ public class SchedulerService
/// <summary>
/// Enqueue one-time job
/// </summary>
public string EnqueueJob(string jobName, Func<Task> job)
public string EnqueueJob(string jobName, Expression<Func<Task>> job)
{
var jobId = _jobClient.Enqueue(job);
_logger.LogInformation("Enqueued job {JobName} with ID {JobId}", jobName, jobId);
@@ -205,7 +206,7 @@ public class SchedulerService
/// <summary>
/// Get job status
/// </summary>
public JobState GetJobStatus(string jobId)
public string? GetJobStatus(string jobId)
{
return JobStorage.Current.GetConnection().GetJobData(jobId)?.State;
}
@@ -242,7 +243,6 @@ public static class HangfireServiceExtensions
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.FromSeconds(15),
UsePageLocks = true,
DisableGlobalLocks = true
}));

Some files were not shown because too many files have changed in this diff Show More