← back to Lifestyle Asset Intel

views/admin_audit.ejs

82 lines

<%- include('partials/head') %>
<main class="container">
  <p class="crumbs"><a href="/">&larr; Console</a></p>
  <h1>Audit — recent API calls</h1>
  <p class="muted">
    Reading the immutable <code>valuation_calls</code> log. Showing the last
    <%= calls.length %> rows. Filter by <code>?slug=&lt;asset-slug&gt;</code> or
    <code>?limit=&lt;1..1000&gt;</code>. JSON: <a href="/api/audit/recent">/api/audit/recent</a>.
  </p>

  <form method="get" action="/admin/audit" class="audit-filter">
    <label>
      <span class="lbl">Asset slug</span>
      <input type="text" name="slug" value="<%= filterSlug || '' %>" placeholder="birkin-30-togo-gold-ghw-us">
    </label>
    <label>
      <span class="lbl">Limit</span>
      <input type="number" name="limit" value="<%= limit %>" min="1" max="1000" step="1">
    </label>
    <button type="submit">Apply</button>
    <% if (filterSlug || limit !== 100) { %>
      <a class="reset" href="/admin/audit">Reset</a>
    <% } %>
  </form>

  <% if (!calls.length) { %>
    <p class="muted">No audit rows match the current filter.</p>
  <% } else { %>
    <table class="audit-table">
      <thead>
        <tr>
          <th>Called at</th>
          <th>Method</th>
          <th>Route</th>
          <th>Slug</th>
          <th class="num">Status</th>
          <th class="num">Latency</th>
          <th>Caller</th>
          <th>Request ID</th>
        </tr>
      </thead>
      <tbody>
        <% calls.forEach(function (c) { %>
          <tr>
            <td class="mono"><%= fmtTs(c.called_at) %></td>
            <td class="mono"><%= c.method %></td>
            <td class="mono"><%= c.route %></td>
            <td>
              <% if (c.asset_slug) { %>
                <a href="/asset/<%= c.asset_slug %>"><%= c.asset_slug %></a>
              <% } else { %>
                <span class="muted">—</span>
              <% } %>
            </td>
            <td class="num <%= statusClass(c.response_status) %>"><%= c.response_status %></td>
            <td class="num"><%= c.latency_ms != null ? c.latency_ms + ' ms' : '—' %></td>
            <td class="mono"><%= c.caller_ip || '—' %></td>
            <td class="mono small"><%= (c.request_id || '').slice(0,8) %></td>
          </tr>
        <% }); %>
      </tbody>
    </table>
  <% } %>
</main>
<%
function fmtTs(v){
  if(!v) return '—';
  try { return new Date(v).toISOString().replace('T',' ').slice(0,19) + 'Z'; }
  catch(e){ return String(v); }
}
function statusClass(s){
  var n = parseInt(s,10);
  if(!isFinite(n)) return '';
  if(n >= 500) return 'status-5xx';
  if(n >= 400) return 'status-4xx';
  if(n >= 300) return 'status-3xx';
  if(n >= 200) return 'status-2xx';
  return '';
}
%>
<%- include('partials/foot') %>