Fix admin login prerender and static assets
TaxBaik CI/CD / build-and-deploy (push) Failing after 2m6s

This commit is contained in:
2026-07-02 16:55:56 +09:00
parent d780fecf8c
commit 500d163ebc
8 changed files with 82 additions and 67 deletions
+1 -1
View File
@@ -37,7 +37,7 @@
</div>
</div>
<MudThemeProvider @bind-IsDarkMode="isDarkMode" Theme="mudTheme" />
<Routes @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" />
<Routes @rendermode="new InteractiveWebAssemblyRenderMode(prerender: true)" />
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
<script src="js/admin-session.js"></script>
<script src="_framework/blazor.web.js"></script>
@@ -1,5 +1,3 @@
@inherits LayoutComponentBase
<AdminTelemetryContext />
@Body
@@ -1,6 +1,6 @@
@page "/admin/login"
@layout TaxBaik.Web.Components.Admin.Layout.BlankLayout
@attribute [AllowAnonymous]
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
@rendermode @(new InteractiveServerRenderMode(prerender: true))
<PageTitle>로그인</PageTitle>
<AdminLoginForm />
@@ -56,8 +56,15 @@
{
if (firstRender)
{
await Js.InvokeVoidAsync("taxbaikAdminSession.syncRouteClass");
await Js.InvokeVoidAsync("taxbaikAdminSession.bindLoginForm");
try
{
await Js.InvokeVoidAsync("taxbaikAdminSession.syncRouteClass");
await Js.InvokeVoidAsync("taxbaikAdminSession.bindLoginForm");
}
catch
{
// Login UI must remain visible even if JS binding fails.
}
}
}
}
@@ -15,16 +15,23 @@
{
if (firstRender)
{
var route = GetRoute();
var context = ResolveContext(route);
await Js.InvokeVoidAsync("taxbaikAdminSession.setContext",
string.IsNullOrWhiteSpace(Screen) ? context.Screen : Screen,
string.IsNullOrWhiteSpace(Feature) ? context.Feature : Feature,
string.IsNullOrWhiteSpace(Action) ? context.Action : Action,
string.IsNullOrWhiteSpace(Step) ? context.Step : Step,
string.IsNullOrWhiteSpace(Entity) ? context.Entity : Entity,
string.IsNullOrWhiteSpace(EntityId) ? context.EntityId : EntityId,
string.IsNullOrWhiteSpace(DataKey) ? context.DataKey : DataKey);
try
{
var route = GetRoute();
var context = ResolveContext(route);
await Js.InvokeVoidAsync("taxbaikAdminSession.setContext",
string.IsNullOrWhiteSpace(Screen) ? context.Screen : Screen,
string.IsNullOrWhiteSpace(Feature) ? context.Feature : Feature,
string.IsNullOrWhiteSpace(Action) ? context.Action : Action,
string.IsNullOrWhiteSpace(Step) ? context.Step : Step,
string.IsNullOrWhiteSpace(Entity) ? context.Entity : Entity,
string.IsNullOrWhiteSpace(EntityId) ? context.EntityId : EntityId,
string.IsNullOrWhiteSpace(DataKey) ? context.DataKey : DataKey);
}
catch
{
// telemetry must never block rendering
}
}
}
@@ -2,44 +2,55 @@ namespace TaxBaik.Web.Components.Admin.Shared;
public static class BusinessDayCalculator
{
private sealed record HolidayWindow(DateOnly Start, DateOnly End)
private static readonly HashSet<DateOnly> HolidayDates = new()
{
public IEnumerable<DateOnly> Dates()
{
for (var date = Start; date <= End; date = date.AddDays(1))
{
yield return date;
}
}
}
// 2026
new DateOnly(2026, 1, 1),
new DateOnly(2026, 2, 16),
new DateOnly(2026, 2, 17),
new DateOnly(2026, 2, 18),
new DateOnly(2026, 3, 1),
new DateOnly(2026, 3, 2),
new DateOnly(2026, 5, 5),
new DateOnly(2026, 5, 25),
new DateOnly(2026, 6, 6),
new DateOnly(2026, 8, 15),
new DateOnly(2026, 8, 16),
new DateOnly(2026, 8, 17),
new DateOnly(2026, 9, 24),
new DateOnly(2026, 9, 25),
new DateOnly(2026, 9, 26),
new DateOnly(2026, 10, 3),
new DateOnly(2026, 10, 4),
new DateOnly(2026, 10, 5),
new DateOnly(2026, 10, 9),
new DateOnly(2026, 12, 25),
private static readonly HolidayWindow[] HolidayWindows =
{
new(new DateOnly(2026, 1, 1), new DateOnly(2026, 1, 1)),
new(new DateOnly(2026, 2, 16), new DateOnly(2026, 2, 18)),
new(new DateOnly(2026, 3, 1), new DateOnly(2026, 3, 2)),
new(new DateOnly(2026, 5, 5), new DateOnly(2026, 5, 5)),
new(new DateOnly(2026, 6, 6), new DateOnly(2026, 6, 6)),
new(new DateOnly(2026, 8, 15), new DateOnly(2026, 8, 17)),
new(new DateOnly(2026, 9, 24), new DateOnly(2026, 9, 26)),
new(new DateOnly(2026, 10, 3), new DateOnly(2026, 10, 5)),
new(new DateOnly(2026, 10, 9), new DateOnly(2026, 10, 9)),
new(new DateOnly(2026, 12, 25), new DateOnly(2026, 12, 25)),
new(new DateOnly(2027, 1, 1), new DateOnly(2027, 1, 1)),
new(new DateOnly(2027, 2, 6), new DateOnly(2027, 2, 9)),
new(new DateOnly(2027, 3, 1), new DateOnly(2027, 3, 2)),
new(new DateOnly(2027, 5, 5), new DateOnly(2027, 5, 5)),
new(new DateOnly(2027, 5, 13), new DateOnly(2027, 5, 13)),
new(new DateOnly(2027, 6, 6), new DateOnly(2027, 6, 6)),
new(new DateOnly(2027, 8, 15), new DateOnly(2027, 8, 16)),
new(new DateOnly(2027, 9, 14), new DateOnly(2027, 9, 16)),
new(new DateOnly(2027, 10, 3), new DateOnly(2027, 10, 4)),
new(new DateOnly(2027, 10, 9), new DateOnly(2027, 10, 11)),
new(new DateOnly(2027, 12, 25), new DateOnly(2027, 12, 26))
// 2027
new DateOnly(2027, 1, 1),
new DateOnly(2027, 2, 6),
new DateOnly(2027, 2, 7),
new DateOnly(2027, 2, 8),
new DateOnly(2027, 2, 9),
new DateOnly(2027, 3, 1),
new DateOnly(2027, 3, 2),
new DateOnly(2027, 5, 5),
new DateOnly(2027, 5, 13),
new DateOnly(2027, 6, 6),
new DateOnly(2027, 8, 15),
new DateOnly(2027, 8, 16),
new DateOnly(2027, 9, 14),
new DateOnly(2027, 9, 15),
new DateOnly(2027, 9, 16),
new DateOnly(2027, 10, 3),
new DateOnly(2027, 10, 4),
new DateOnly(2027, 10, 9),
new DateOnly(2027, 10, 10),
new DateOnly(2027, 10, 11),
new DateOnly(2027, 12, 25),
new DateOnly(2027, 12, 26)
};
private static readonly HashSet<DateOnly> HolidayDates = BuildHolidayDates();
public static DateOnly GetEffectiveDueDate(DateOnly dueDate)
{
var effectiveDate = dueDate;
@@ -61,19 +72,4 @@ public static class BusinessDayCalculator
public static bool IsBusinessDay(DateOnly date)
=> date.DayOfWeek is not DayOfWeek.Saturday and not DayOfWeek.Sunday
&& !HolidayDates.Contains(date);
private static HashSet<DateOnly> BuildHolidayDates()
{
var holidays = new HashSet<DateOnly>();
foreach (var window in HolidayWindows)
{
foreach (var date in window.Dates())
{
holidays.Add(date);
}
}
return holidays;
}
}
+2
View File
@@ -368,6 +368,7 @@ catch (Exception ex)
app.UsePathBase("/taxbaik");
app.UseResponseCompression();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseRateLimiter();
@@ -385,6 +386,7 @@ if (!app.Environment.IsDevelopment())
app.MapControllers();
app.MapHealthChecks("/healthz");
app.MapRazorPages();
app.MapStaticAssets();
// AllowAnonymous: JWT 미들웨어가 Blazor 셸 요청을 401로 차단하지 않도록 한다.
// 인증은 Blazor AuthorizeRouteView → RedirectToLogin 에서 처리한다.