<!doctype html>
<html lang="ko">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title><%= service.name %> Ledger DB Migration</title>
    <link rel="stylesheet" href="/css/admin.css">
  </head>
  <body>
    <main class="shell">
      <header class="topbar">
        <div>
          <p class="eyebrow"><%= service.mode %></p>
          <h1>Ledger DB Migration</h1>
        </div>
        <div class="top-actions">
          <form method="post" action="/admin/ledger-migration/dry-run">
            <button class="nav-button" type="submit">Dry-run 생성</button>
          </form>
          <form method="post" action="/admin/ledger-migration/observation-compare">
            <button class="nav-button" type="submit">Observation 비교</button>
          </form>
          <a class="nav-button" href="/admin">Admin</a>
          <a class="nav-button" href="/explorer">Explorer</a>
          <a class="nav-button subtle" href="/admin/logout">Logout</a>
          <div class="status"><span></span>Port <%= service.port %></div>
        </div>
      </header>

      <section class="grid metrics" aria-label="Migration metrics">
        <article><strong><%= migration.currentBackend %></strong><span>Current Backend</span></article>
        <article><strong><%= migration.targetBackend %></strong><span>Target Backend</span></article>
        <article><strong><%= migration.readinessScore %>%</strong><span>Readiness</span></article>
        <article><strong><%= migration.totalRows %></strong><span>Total Rows</span></article>
        <article><strong><%= migration.dryRun.exists ? migration.dryRun.totalDocuments : 0 %></strong><span>Dry-run Docs</span></article>
        <article><strong><%= migration.db.configured ? 'READY' : 'MISSING' %></strong><span>DB URI</span></article>
        <article><strong><%= migration.staging.summary.exists ? migration.staging.summary.totalDocuments : 0 %></strong><span>Staging Docs</span></article>
        <article><strong><%= migration.mongoObservation.compare && migration.mongoObservation.compare.ok ? 'OK' : 'CHECK' %></strong><span>Mongo Observe</span></article>
      </section>

      <section class="grid">
        <article class="panel">
          <div class="panel-title"><h2>Storage Source</h2><span><%= migration.mode %></span></div>
          <div class="stat-list">
            <div class="stat-row"><span>ledger path</span><code><%= migration.ledgerPath %></code></div>
            <div class="stat-row"><span>file size</span><strong><%= migration.fileInfo.sizeBytes %> bytes</strong></div>
            <div class="stat-row"><span>updated</span><strong><%= migration.fileInfo.updatedAt || '-' %></strong></div>
            <div class="stat-row"><span>tmp/broken files</span><strong><%= migration.tmpFiles.length %></strong></div>
          </div>
        </article>
        <article class="panel">
          <div class="panel-title"><h2>DB Target</h2><span>switch locked</span></div>
          <div class="stat-list">
            <div class="stat-row"><span>configured</span><strong><%= migration.db.configured ? 'yes' : 'no' %></strong></div>
            <div class="stat-row"><span>uri preview</span><code><%= migration.db.uriPreview || '-' %></code></div>
            <div class="stat-row"><span>dual-write request</span><strong><%= migration.dualWrite.requested ? 'yes' : 'no' %></strong></div>
            <div class="stat-row"><span>DB writes</span><strong><%= migration.dualWrite.dbWriteEnabled ? 'requested / locked' : 'disabled' %></strong></div>
            <div class="stat-row"><span>shadow adapter</span><strong><%= migration.dualWrite.active ? 'active' : 'standby' %></strong></div>
            <div class="stat-row"><span>shadow docs</span><strong><%= migration.dualWrite.totalDocuments || 0 %></strong></div>
            <div class="stat-row"><span>shadow sync</span><strong><%= migration.dualWrite.latestSyncedAt || '-' %></strong></div>
            <div class="stat-row"><span>shadow dir</span><code><%= migration.dualWrite.shadowDir || '-' %></code></div>
            <div class="stat-row"><span>backend switch</span><strong><%= migration.canSwitchBackend ? 'enabled' : 'disabled' %></strong></div>
          </div>
        </article>
      </section>

      <section class="panel">
        <div class="panel-title"><h2>Dry-run Result</h2><span><%= migration.dryRun.exists ? migration.dryRun.mode : 'not-run' %></span></div>
        <div class="stat-list">
          <div class="stat-row"><span>last run</span><strong><%= migration.dryRun.createdAt || '-' %></strong></div>
          <div class="stat-row"><span>output</span><code><%= migration.dryRun.dryRunPath %></code></div>
          <div class="stat-row"><span>documents</span><strong><%= migration.dryRun.totalDocuments %></strong></div>
          <div class="stat-row"><span>warnings</span><strong class="<%= migration.dryRun.warningCount ? 'warn-text' : 'ok-text' %>"><%= migration.dryRun.warningCount %></strong></div>
          <div class="stat-row"><span>DB write</span><strong>blocked</strong></div>
        </div>
        <% if (migration.dryRun.warnings && migration.dryRun.warnings.length) { %>
          <% migration.dryRun.warnings.forEach(function(warning) { %>
            <div class="item"><strong class="warn-text"><%= warning %></strong></div>
          <% }) %>
        <% } %>
      </section>

      <section class="panel">
        <div class="panel-title">
          <h2>MongoDB Staging</h2>
          <span class="<%= migration.staging.compare.ok ? 'ok-text' : 'warn-text' %>"><%= migration.staging.compare.ok ? 'OK' : 'CHECK' %></span>
        </div>
        <div class="stat-list">
          <div class="stat-row"><span>mode</span><strong><%= migration.staging.summary.mode || 'not-run' %></strong></div>
          <div class="stat-row"><span>live collections</span><strong><%= migration.staging.summary.writesLiveCollections ? 'written' : 'not touched' %></strong></div>
          <div class="stat-row"><span>summary output</span><code><%= migration.staging.summary.path || '-' %></code></div>
          <div class="stat-row"><span>compare output</span><code><%= migration.staging.compare.path || '-' %></code></div>
          <div class="stat-row"><span>expected / actual</span><strong><%= migration.staging.compare.totalExpected || 0 %> / <%= migration.staging.compare.totalActual || 0 %></strong></div>
          <div class="stat-row"><span>failed collections</span><strong class="<%= migration.staging.compare.failedCollections ? 'warn-text' : 'ok-text' %>"><%= migration.staging.compare.failedCollections || 0 %></strong></div>
          <div class="stat-row"><span>checked</span><strong><%= migration.staging.compare.checkedAt || '-' %></strong></div>
        </div>
        <div class="table-wrap">
          <table>
            <thead><tr><th>Collection</th><th>Expected</th><th>Actual</th><th>Status</th></tr></thead>
            <tbody>
              <% (migration.staging.compare.rows || []).forEach(function(row) { %>
                <tr>
                  <td><code><%= row.stagingCollection %></code><br><small class="muted"><%= row.key %></small></td>
                  <td><%= row.expectedCount %></td>
                  <td><%= row.actualCount %></td>
                  <td><span class="badge <%= row.ok ? 'badge-ok' : 'badge-warn' %>"><%= row.ok ? 'match' : 'diff' %></span></td>
                </tr>
              <% }) %>
            </tbody>
          </table>
        </div>
      </section>
      <section class="panel">
        <div class="panel-title">
          <h2>Shadow Consistency</h2>
          <span class="<%= migration.consistency.ok ? 'ok-text' : 'warn-text' %>"><%= migration.consistency.ok ? 'OK' : 'CHECK' %></span>
        </div>
        <div class="stat-list">
          <div class="stat-row"><span>checked</span><strong><%= migration.consistency.checkedAt || '-' %></strong></div>
          <div class="stat-row"><span>latest shadow sync</span><strong><%= migration.consistency.latestShadowSync || '-' %></strong></div>
          <div class="stat-row"><span>source / shadow rows</span><strong><%= migration.consistency.totalSourceRows %> / <%= migration.consistency.totalShadowRows %></strong></div>
          <div class="stat-row"><span>issues</span><strong class="<%= migration.consistency.issueCount ? 'warn-text' : 'ok-text' %>"><%= migration.consistency.issueCount %></strong></div>
        </div>
        <div class="table-wrap">
          <table>
            <thead><tr><th>Collection</th><th>Source</th><th>Shadow</th><th>Count</th><th>Hash</th><th>Status</th></tr></thead>
            <tbody>
              <% migration.consistency.collections.forEach(function(row) { %>
                <tr>
                  <td><strong><%= row.collection %></strong><br><small class="muted"><%= row.label %></small></td>
                  <td><%= row.sourceCount %></td>
                  <td><%= row.shadowCount %></td>
                  <td><span class="badge <%= row.countMatches ? 'badge-ok' : 'badge-warn' %>"><%= row.countMatches ? 'match' : 'diff' %></span></td>
                  <td><span class="badge <%= row.hashMatches ? 'badge-ok' : 'badge-warn' %>"><%= row.hashMatches ? 'match' : 'diff' %></span></td>
                  <td><span class="badge <%= row.ok ? 'badge-ok' : 'badge-warn' %>"><%= row.ok ? 'ok' : row.issue %></span></td>
                </tr>
              <% }) %>
            </tbody>
          </table>
        </div>
      </section>

      <section class="panel">
        <div class="panel-title">
          <h2>MongoDB Observation</h2>
          <span class="<%= migration.mongoObservation.compare && migration.mongoObservation.compare.ok ? 'ok-text' : 'warn-text' %>"><%= migration.mongoObservation.compare && migration.mongoObservation.compare.ok ? 'OK' : 'CHECK' %></span>
        </div>
        <div class="stat-list">
          <div class="stat-row"><span>requested</span><strong><%= migration.mongoObservation.requested ? 'yes' : 'no' %></strong></div>
          <div class="stat-row"><span>write enabled</span><strong><%= migration.mongoObservation.writeEnabled ? 'yes' : 'no' %></strong></div>
          <div class="stat-row"><span>live collections</span><strong><%= migration.mongoObservation.writesLiveCollections ? 'written' : 'not touched' %></strong></div>
          <div class="stat-row"><span>synced docs</span><strong><%= migration.mongoObservation.totalDocuments || 0 %></strong></div>
          <div class="stat-row"><span>synced at</span><strong><%= migration.mongoObservation.syncedAt || '-' %></strong></div>
          <div class="stat-row"><span>expected / actual</span><strong><%= migration.mongoObservation.compare ? migration.mongoObservation.compare.totalExpected || 0 : 0 %> / <%= migration.mongoObservation.compare ? migration.mongoObservation.compare.totalActual || 0 : 0 %></strong></div>
          <div class="stat-row"><span>failed collections</span><strong class="<%= migration.mongoObservation.compare && migration.mongoObservation.compare.failedCollections ? 'warn-text' : 'ok-text' %>"><%= migration.mongoObservation.compare ? migration.mongoObservation.compare.failedCollections || 0 : 0 %></strong></div>
          <div class="stat-row"><span>window samples</span><strong><%= migration.mongoObservation.window ? migration.mongoObservation.window.sampleCount || 0 : 0 %></strong></div>
          <div class="stat-row"><span>consecutive OK</span><strong class="<%= migration.mongoObservation.window && migration.mongoObservation.window.ok ? 'ok-text' : 'warn-text' %>"><%= migration.mongoObservation.window ? migration.mongoObservation.window.consecutiveOk || 0 : 0 %></strong></div>
          <div class="stat-row"><span>window status</span><strong class="<%= migration.mongoObservation.window && migration.mongoObservation.window.ok ? 'ok-text' : 'warn-text' %>"><%= migration.mongoObservation.window && migration.mongoObservation.window.ok ? 'ready' : 'observing' %></strong></div>
        </div>
        <div class="table-wrap">
          <table>
            <thead><tr><th>Collection</th><th>Expected</th><th>Actual</th><th>Status</th></tr></thead>
            <tbody>
              <% ((migration.mongoObservation.compare && migration.mongoObservation.compare.rows) || []).forEach(function(row) { %>
                <tr>
                  <td><code><%= row.observationCollection %></code><br><small class="muted"><%= row.key %></small></td>
                  <td><%= row.expectedCount %></td>
                  <td><%= row.actualCount %></td>
                  <td><span class="badge <%= row.ok ? 'badge-ok' : 'badge-warn' %>"><%= row.ok ? 'match' : 'diff' %></span></td>
                </tr>
              <% }) %>
            </tbody>
          </table>
        </div>
      </section>
      <section class="panel">
        <div class="panel-title">
          <h2>MongoDB Read Monitor</h2>
          <span class="<%= migration.mongoReadMonitor && migration.mongoReadMonitor.ok ? 'ok-text' : 'warn-text' %>"><%= migration.mongoReadMonitor && migration.mongoReadMonitor.ok ? 'READY' : 'WATCH' %></span>
        </div>
        <div class="stat-list">
          <div class="stat-row"><span>latest sample</span><strong class="<%= migration.mongoReadMonitor && migration.mongoReadMonitor.latestSample && migration.mongoReadMonitor.latestSample.ok ? 'ok-text' : 'warn-text' %>"><%= migration.mongoReadMonitor && migration.mongoReadMonitor.latestSample ? (migration.mongoReadMonitor.latestSample.ok ? 'OK' : 'CHECK') : 'not-run' %></strong></div>
          <div class="stat-row"><span>expected / actual</span><strong><%= migration.mongoReadMonitor && migration.mongoReadMonitor.latestSample ? (migration.mongoReadMonitor.latestSample.totalActual || 0) + ' / ' + (migration.mongoReadMonitor.latestSample.totalExpected || 0) : '0 / 0' %></strong></div>
          <div class="stat-row"><span>failed collections</span><strong class="<%= migration.mongoReadMonitor && migration.mongoReadMonitor.latestSample && migration.mongoReadMonitor.latestSample.failedCollections ? 'warn-text' : 'ok-text' %>"><%= migration.mongoReadMonitor && migration.mongoReadMonitor.latestSample ? migration.mongoReadMonitor.latestSample.failedCollections || 0 : 0 %></strong></div>
          <div class="stat-row"><span>window samples</span><strong><%= migration.mongoReadMonitor && migration.mongoReadMonitor.window ? migration.mongoReadMonitor.window.sampleCount || 0 : 0 %></strong></div>
          <div class="stat-row"><span>consecutive OK</span><strong class="<%= migration.mongoReadMonitor && migration.mongoReadMonitor.window && migration.mongoReadMonitor.window.ok ? 'ok-text' : 'warn-text' %>"><%= migration.mongoReadMonitor && migration.mongoReadMonitor.window ? migration.mongoReadMonitor.window.consecutiveOk || 0 : 0 %></strong></div>
          <div class="stat-row"><span>updated</span><strong><%= migration.mongoReadMonitor ? migration.mongoReadMonitor.updatedAt || '-' : '-' %></strong></div>
          <div class="stat-row"><span>output</span><code><%= migration.mongoReadMonitor ? migration.mongoReadMonitor.path : '-' %></code></div>
        </div>
        <div style="display:flex;gap:10px;flex-wrap:wrap;margin-top:14px">
          <form method="post" action="/admin/ledger-migration/read-monitor/sample">
            <button class="nav-button" type="submit">Read Monitor 샘플</button>
          </form>
          <span class="muted">6회 이상 연속 OK일 때 Mongo read 전환 판단 근거로 사용합니다.</span>
        </div>
      </section>
      <section class="panel">
        <div class="panel-title">
          <h2>MongoDB Post Switch Guard</h2>
          <span class="<%= migration.mongoPostSwitchGuard && migration.mongoPostSwitchGuard.ok ? 'ok-text' : 'warn-text' %>"><%= migration.mongoPostSwitchGuard && migration.mongoPostSwitchGuard.ok ? 'HEALTHY' : 'CHECK' %></span>
        </div>
        <div class="stat-list">
          <div class="stat-row"><span>requested backend</span><strong><%= migration.mongoPostSwitchGuard ? migration.mongoPostSwitchGuard.requestedBackend || '-' : '-' %></strong></div>
          <div class="stat-row"><span>endpoint health</span><strong class="<%= migration.mongoPostSwitchGuard && migration.mongoPostSwitchGuard.endpointOk ? 'ok-text' : 'warn-text' %>"><%= migration.mongoPostSwitchGuard && migration.mongoPostSwitchGuard.endpointOk ? 'OK' : 'CHECK' %></strong></div>
          <div class="stat-row"><span>read monitor</span><strong class="<%= migration.mongoPostSwitchGuard && migration.mongoPostSwitchGuard.monitor && migration.mongoPostSwitchGuard.monitor.latestSample && migration.mongoPostSwitchGuard.monitor.latestSample.ok ? 'ok-text' : 'warn-text' %>"><%= migration.mongoPostSwitchGuard && migration.mongoPostSwitchGuard.monitor && migration.mongoPostSwitchGuard.monitor.latestSample ? (migration.mongoPostSwitchGuard.monitor.latestSample.totalActual || 0) + ' / ' + (migration.mongoPostSwitchGuard.monitor.latestSample.totalExpected || 0) : '0 / 0' %></strong></div>
          <div class="stat-row"><span>rollback prepared</span><strong class="<%= migration.mongoPostSwitchGuard && migration.mongoPostSwitchGuard.rollbackPrepared ? 'warn-text' : 'ok-text' %>"><%= migration.mongoPostSwitchGuard && migration.mongoPostSwitchGuard.rollbackPrepared ? 'yes' : 'no' %></strong></div>
          <div class="stat-row"><span>checked</span><strong><%= migration.mongoPostSwitchGuard ? migration.mongoPostSwitchGuard.checkedAt || '-' : '-' %></strong></div>
          <div class="stat-row"><span>output</span><code><%= migration.mongoPostSwitchGuard ? migration.mongoPostSwitchGuard.path : '-' %></code></div>
        </div>
        <div class="table-wrap">
          <table>
            <thead><tr><th>Endpoint</th><th>Status</th><th>Time</th></tr></thead>
            <tbody>
              <% ((migration.mongoPostSwitchGuard && migration.mongoPostSwitchGuard.endpoints) || []).forEach(function(row) { %>
                <tr>
                  <td><code><%= row.url %></code></td>
                  <td><span class="badge <%= row.ok ? 'badge-ok' : 'badge-warn' %>"><%= row.statusCode || 0 %></span></td>
                  <td><%= row.durationMs || 0 %>ms</td>
                </tr>
              <% }) %>
            </tbody>
          </table>
        </div>
        <div style="display:flex;gap:10px;flex-wrap:wrap;margin-top:14px">
          <form method="post" action="/admin/ledger-migration/post-switch-guard/run">
            <button class="nav-button" type="submit">Post Switch 점검</button>
          </form>
          <span class="muted">실패 시 자동 롤백은 CLI의 명시 옵션에서만 수행합니다.</span>
        </div>
      </section>
      <section class="panel">
        <div class="panel-title">
          <h2>MongoDB Read Backend</h2>
          <span class="<%= migration.mongoReadBackend && migration.mongoReadBackend.enabled ? 'ok-text' : 'warn-text' %>"><%= migration.mongoReadBackend ? migration.mongoReadBackend.mode : 'json-read-active' %></span>
        </div>
        <div class="stat-list">
          <div class="stat-row"><span>requested</span><strong><%= migration.mongoReadBackend && migration.mongoReadBackend.requested ? 'yes' : 'no' %></strong></div>
          <div class="stat-row"><span>manual approval</span><strong class="<%= migration.mongoReadBackend && migration.mongoReadBackend.approved ? 'ok-text' : 'warn-text' %>"><%= migration.mongoReadBackend && migration.mongoReadBackend.approved ? 'approved' : 'not approved' %></strong></div>
          <div class="stat-row"><span>read adapter</span><strong class="<%= migration.mongoReadBackend && migration.mongoReadBackend.enabled ? 'ok-text' : 'warn-text' %>"><%= migration.mongoReadBackend && migration.mongoReadBackend.enabled ? 'enabled' : 'standby' %></strong></div>
          <div class="stat-row"><span>live backfill</span><strong class="<%= migration.mongoReadBackend && migration.mongoReadBackend.liveBackfill && migration.mongoReadBackend.liveBackfill.ok ? 'ok-text' : 'warn-text' %>"><%= migration.mongoReadBackend && migration.mongoReadBackend.liveBackfill ? migration.mongoReadBackend.liveBackfill.mode : 'not-run' %></strong></div>
          <div class="stat-row"><span>read compare</span><strong class="<%= migration.mongoReadBackend && migration.mongoReadBackend.compare && migration.mongoReadBackend.compare.ok ? 'ok-text' : 'warn-text' %>"><%= migration.mongoReadBackend && migration.mongoReadBackend.compare ? (migration.mongoReadBackend.compare.totalActual || 0) + ' / ' + (migration.mongoReadBackend.compare.totalExpected || 0) : '0 / 0' %></strong></div>
          <div class="stat-row"><span>read snapshot</span><strong class="<%= migration.mongoReadBackend && migration.mongoReadBackend.snapshot && migration.mongoReadBackend.snapshot.ok ? 'ok-text' : 'warn-text' %>"><%= migration.mongoReadBackend && migration.mongoReadBackend.snapshot ? (migration.mongoReadBackend.snapshot.totalDocuments || 0) + ' docs' : 'not-ready' %></strong></div>
          <div class="stat-row"><span>failed collections</span><strong class="<%= migration.mongoReadBackend && migration.mongoReadBackend.compare && migration.mongoReadBackend.compare.failedCollections ? 'warn-text' : 'ok-text' %>"><%= migration.mongoReadBackend && migration.mongoReadBackend.compare ? migration.mongoReadBackend.compare.failedCollections || 0 : 0 %></strong></div>
          <div class="stat-row"><span>live writer</span><strong class="<%= migration.mongoReadBackend && migration.mongoReadBackend.liveWriter && migration.mongoReadBackend.liveWriter.writeEnabled ? 'ok-text' : 'warn-text' %>"><%= migration.mongoReadBackend && migration.mongoReadBackend.liveWriter && migration.mongoReadBackend.liveWriter.writeEnabled ? 'enabled' : 'standby' %></strong></div>
          <div class="stat-row"><span>live writer docs</span><strong><%= migration.mongoReadBackend && migration.mongoReadBackend.liveWriter ? migration.mongoReadBackend.liveWriter.totalDocuments || 0 : 0 %></strong></div>
          <div class="stat-row"><span>reason</span><strong><%= migration.mongoReadBackend ? migration.mongoReadBackend.reason : '-' %></strong></div>
          <div class="stat-row"><span>env read backend</span><strong class="<%= migration.readBackendSwitch && migration.readBackendSwitch.readBackend === 'mongodb' ? 'ok-text' : 'warn-text' %>"><%= migration.readBackendSwitch ? migration.readBackendSwitch.readBackend : 'json-file' %></strong></div>
          <div class="stat-row"><span>env file</span><code><%= migration.readBackendSwitch ? migration.readBackendSwitch.envPath : '-' %></code></div>
        </div>
        <div style="display:flex;gap:10px;flex-wrap:wrap;margin-top:14px">
          <form method="post" action="/admin/ledger-migration/read-backend/request-mongo">
            <button class="nav-button" type="submit" <%= migration.dbReadiness.readSwitchPreflightOk && migration.mongoReadBackend && migration.mongoReadBackend.snapshot && migration.mongoReadBackend.snapshot.ok && !(migration.mongoReadBackend && migration.mongoReadBackend.enabled) ? '' : 'disabled' %>>Mongo Read 요청</button>
          </form>
          <form method="post" action="/admin/ledger-migration/read-backend/rollback-json">
            <button class="nav-button" type="submit">JSON Read 롤백</button>
          </form>
          <span class="muted">버튼 적용 후 PM2 재시작이 필요합니다.</span>
        </div>
      </section>      <section class="panel">
        <div class="panel-title">
          <h2>DB Backend Readiness</h2>
          <span class="<%= migration.dbReadiness.canAttachWriter ? 'ok-text' : 'warn-text' %>"><%= migration.dbReadiness.score %>%</span>
        </div>
        <div class="stat-list">
          <div class="stat-row"><span>target backend</span><strong><%= migration.dbReadiness.targetBackend %></strong></div>
          <div class="stat-row"><span>DB URI</span><code><%= migration.dbReadiness.uriPreview || '-' %></code></div>
          <div class="stat-row"><span>driver</span><strong class="<%= migration.dbReadiness.driverAvailable ? 'ok-text' : 'warn-text' %>"><%= migration.dbReadiness.driverPackage %> / <%= migration.dbReadiness.driverAvailable ? 'ready' : 'missing' %></strong></div>
          <div class="stat-row"><span>attach writer</span><strong class="<%= migration.dbReadiness.canAttachWriter ? 'ok-text' : 'warn-text' %>"><%= migration.dbReadiness.canAttachWriter ? 'allowed' : 'locked' %></strong></div>
          <div class="stat-row"><span>read preflight</span><strong class="<%= migration.dbReadiness.readSwitchPreflightOk ? 'ok-text' : 'warn-text' %>"><%= migration.dbReadiness.readSwitchPreflightOk ? 'ready' : 'blocked' %></strong></div>
          <div class="stat-row"><span>manual approval</span><strong class="<%= migration.dbReadiness.readSwitchApproved ? 'ok-text' : 'warn-text' %>"><%= migration.dbReadiness.readSwitchApproved ? 'approved' : 'required' %></strong></div>
          <div class="stat-row"><span>read switch</span><strong class="<%= migration.dbReadiness.canSwitchReads ? 'ok-text' : 'warn-text' %>"><%= migration.dbReadiness.canSwitchReads ? 'approval ready' : 'locked' %></strong></div>
          <div class="stat-row"><span>approval id</span><code><%= migration.dbReadiness.readSwitchApproval && migration.dbReadiness.readSwitchApproval.approvalId ? migration.dbReadiness.readSwitchApproval.approvalId : '-' %></code></div>
          <div class="stat-row"><span>approved at</span><strong><%= migration.dbReadiness.readSwitchApproval && migration.dbReadiness.readSwitchApproval.approvedAt ? migration.dbReadiness.readSwitchApproval.approvedAt : '-' %></strong></div>
          <div class="stat-row"><span>approval file</span><code><%= migration.dbReadiness.readSwitchApproval && migration.dbReadiness.readSwitchApproval.path ? migration.dbReadiness.readSwitchApproval.path : '-' %></code></div>
          <div class="stat-row"><span>lock reason</span><strong><%= migration.dbReadiness.switchLockReason %></strong></div>
        </div>
        <div style="display:flex;gap:10px;flex-wrap:wrap;margin-top:14px">
          <form method="post" action="/admin/ledger-migration/read-switch/approve">
            <button class="nav-button" type="submit" <%= migration.dbReadiness.readSwitchPreflightOk && !migration.dbReadiness.readSwitchApproved ? '' : 'disabled' %>>Read Switch 승인 기록</button>
          </form>
          <form method="post" action="/admin/ledger-migration/read-switch/revoke">
            <button class="nav-button" type="submit" <%= migration.dbReadiness.readSwitchApproved ? '' : 'disabled' %>>Read Switch 승인 취소</button>
          </form>
        </div>
        <div class="table-wrap">
          <table>
            <thead><tr><th>Check</th><th>Severity</th><th>Status</th><th>Detail</th></tr></thead>
            <tbody>
              <% migration.dbReadiness.checks.forEach(function(check) { %>
                <tr>
                  <td><strong><%= check.label %></strong></td>
                  <td><%= check.severity %></td>
                  <td><span class="badge <%= check.ok ? 'badge-ok' : 'badge-warn' %>"><%= check.ok ? 'ok' : 'check' %></span></td>
                  <td><%= check.detail %></td>
                </tr>
              <% }) %>
            </tbody>
          </table>
        </div>
      </section>

      <section class="panel">
        <div class="panel-title"><h2>Readiness Checks</h2><span><%= migration.readinessScore %>%</span></div>
        <div class="stat-list">
          <% migration.checks.forEach(function(check) { %>
            <div class="stat-row">
              <span><%= check.label %><br><small class="muted"><%= check.detail %></small></span>
              <strong class="<%= check.ok ? 'ok-text' : 'warn-text' %>"><%= check.ok ? 'OK' : 'CHECK' %></strong>
            </div>
          <% }) %>
        </div>
      </section>

      <section class="panel">
        <div class="panel-title"><h2>Collection Map</h2><span>JSON key -> DB collection</span></div>
        <div class="table-wrap">
          <table>
            <thead><tr><th>Label</th><th>JSON Key</th><th>DB Collection</th><th>Rows</th><th>Dry-run Samples</th><th>Critical</th></tr></thead>
            <tbody>
              <% migration.collections.forEach(function(row) { %>
                <% const dryRow = (migration.dryRun.collections || []).find(function(item) { return item.key === row.key; }); %>
                <tr>
                  <td><strong><%= row.label %></strong></td>
                  <td><code><%= row.key %></code></td>
                  <td><code><%= row.collection %></code></td>
                  <td><%= row.count %></td>
                  <td><code><%= dryRow && dryRow.sampleIds.length ? dryRow.sampleIds.join(', ') : '-' %></code></td>
                  <td><span class="badge <%= row.critical ? 'badge-warn' : 'badge-ok' %>"><%= row.critical ? 'yes' : 'no' %></span></td>
                </tr>
              <% }) %>
            </tbody>
          </table>
        </div>
      </section>

      <section class="panel">
        <div class="panel-title"><h2>Next Steps</h2><span>no backend switch yet</span></div>
        <% migration.nextSteps.forEach(function(step, index) { %>
          <div class="item"><strong><%= index + 1 %>. <%= step %></strong></div>
        <% }) %>
      </section>
    </main>
  </body>
</html>











