fix: Remove fake hardcoded data, rebuild admin layout with real Tabler components
Root cause: user asked why logout was missing. Playwright audit against production found logout works fine, but surfaced two real defects and led to a wider audit that found extensive fabricated data across the admin pages -- none of it backed by the database despite CLAUDE.md's policy that all data must come from DB records. Layout (_AdminLayout.cshtml): - Full rewrite using Tabler's actual navbar-vertical/page-wrapper/footer component structure instead of ad-hoc inline CSS. The old layout had no footer element at all, and its mobile breakpoint CSS hid the sidebar off-screen (left: -260px) with no hamburger button to bring it back -- verified via Playwright screenshot at 375px width that the entire nav menu was inaccessible on mobile, leaving only Logout reachable. Tabler's navbar-toggler + Bootstrap collapse (bundled in tabler.min.js) now restores it; verified the toggle actually opens the menu via Playwright. - Active nav-link highlighting moved from client-side JS string matching to a server-side Razor helper against Context.Request.Path. Fake/hardcoded data removed or replaced with real DB/Hangfire state: - Dashboard: deleted the "최근 시스템 이벤트" table (3 rows hardcoded from DateTime.Now with fake descriptions like "시스템 초기화" / "데이터베이스 백업" -- no backing table exists). Removed hardcoded "정상"/"연결됨" status badges and "버전: v0.1.0"/"업타임: 정상"; replaced with a real IsDatabaseConnected flag (true only if the page's actual DB queries succeeded) and the real IWebHostEnvironment.EnvironmentName. - Monitoring: removed hardcoded "API 서버: 운영 중" (no real signal backs it) and wired "데이터베이스: 연결 정상/끊김" to the same real success/failure state as the page's own DB calls. - Operations: this page was entirely fabricated -- ScheduledJobs, RecentExecutions, IsJobProcessorRunning, PendingJobsCount, and StatusMessage were all static values with zero connection to Hangfire, despite Hangfire actually running in production (confirmed via journalctl: ServerWatchdog, RecurringJobScheduler dispatchers active) with 4 real recurring jobs registered in SchedulerService (daily-collection, hourly-price-update, weekly-report, monthly-optimization). Rewrote to query JobStorage.Current.GetConnection().GetRecurringJobs() and GetMonitoringApi() directly: real scheduled jobs, real succeeded/ failed executions, real server count, real enqueued count. Verified locally (SSH-tunneled to prod DB) that this now returns the actual 4 registered jobs with correct next-run times and one real RunDailyCollectionAsync execution. Also fixed the page-title duplication on Monitoring/Operations (ViewData["Title"] included "- QuantEngine" AND the layout appended it again -> "모니터링 - QuantEngine - QuantEngine" in the browser tab). Separately discovered (not fixed in this commit, flagging for follow-up): Hangfire's SchedulerService.InitializeSchedules() fails every startup with "Cannot resolve scoped service 'SchedulerService' from root provider" -- the 4 recurring jobs above still show up because they persist from an earlier successful registration, but re-registration is silently broken on every current boot. Verified end-to-end with Playwright against a local instance (SSH tunnel to production Postgres): login, all 5 admin pages render without errors, mobile hamburger opens the sidebar, and Operations shows genuine Hangfire data.
This commit is contained in:
@@ -26,71 +26,28 @@
|
||||
<small class="text-muted">데이터 수집 실행</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stat-card">
|
||||
<div class="stat-card-label">시스템 상태</div>
|
||||
<div class="stat-card-number">
|
||||
<span class="status-dot active"></span>정상
|
||||
</div>
|
||||
<small class="text-muted">모든 서비스 운영 중</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stat-card">
|
||||
<div class="stat-card-label">데이터베이스</div>
|
||||
<div class="stat-card-number">
|
||||
<span class="status-dot active"></span>연결됨
|
||||
@if (Model.IsDatabaseConnected)
|
||||
{
|
||||
<span class="status-dot active"></span><text>연결됨</text>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="status-dot" style="background-color:#e74c3c;"></span><text>연결 끊김</text>
|
||||
}
|
||||
</div>
|
||||
<small class="text-muted">PostgreSQL 정상</small>
|
||||
<small class="text-muted">@(Model.IsDatabaseConnected ? "PostgreSQL 정상" : "데이터 조회 실패 - 로그 확인 필요")</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Row -->
|
||||
<div class="row">
|
||||
<!-- System Events Card -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">최근 시스템 이벤트</h3>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table card-table table-vcenter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>시간</th>
|
||||
<th>이벤트</th>
|
||||
<th>유형</th>
|
||||
<th>상태</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>@DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")</td>
|
||||
<td>시스템 초기화</td>
|
||||
<td><span class="badge badge-info">INFO</span></td>
|
||||
<td><span class="badge badge-success">완료</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>@DateTime.Now.AddHours(-1).ToString("yyyy-MM-dd HH:mm:ss")</td>
|
||||
<td>데이터 수집 완료</td>
|
||||
<td><span class="badge badge-info">INFO</span></td>
|
||||
<td><span class="badge badge-success">완료</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>@DateTime.Now.AddHours(-2).ToString("yyyy-MM-dd HH:mm:ss")</td>
|
||||
<td>데이터베이스 백업</td>
|
||||
<td><span class="badge badge-secondary">SYSTEM</span></td>
|
||||
<td><span class="badge badge-success">완료</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions Card -->
|
||||
<div class="col-lg-4">
|
||||
<div class="col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">빠른 작업</h3>
|
||||
@@ -117,24 +74,22 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- System Info Card -->
|
||||
<div class="card mt-3">
|
||||
<!-- System Info Card -->
|
||||
<div class="col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">시스템 정보</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-2">
|
||||
<span class="text-muted">버전:</span>
|
||||
<strong>v0.1.0</strong>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<span class="text-muted">환경:</span>
|
||||
<strong>Production</strong>
|
||||
<strong>@Model.EnvironmentName</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-muted">업타임:</span>
|
||||
<strong>정상</strong>
|
||||
<span class="text-muted">데이터베이스:</span>
|
||||
<strong>@(Model.IsDatabaseConnected ? "연결됨" : "연결 끊김")</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user