customer-presentation/admin/index.html
Arlind Ukshini 107284801b add hidden /fenjaops admin page (read-only) + is_admin invite flag
- new is_admin column on invites (migration 4) with DEFAULT 0
- requireAdmin middleware returns 404 for non-admins so the route's
  existence isn't leaked; path obscured as /fenjaops (not /admin)
- admin/ dir lives outside public/ and protected/; only reachable via
  the explicit gated mount + /api/fenjaops/{invites,joins} endpoints
- bin/invite.js gains `admin add|remove|list` subcommands
- OPERATIONS.md + CLAUDE.md + PROJECT.md document the hidden URL

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 17:29:19 +02:00

61 lines
2.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="noindex, nofollow" />
<title>Admin — Fenja AI</title>
<link rel="stylesheet" href="/fenjaops/admin.css" />
</head>
<body>
<header class="masthead">
<h1>Fenja AI <span class="dim">— Admin</span></h1>
<p class="meta">Read-only view. Grant/revoke via <code>bin/invite.js admin</code>.</p>
</header>
<section class="panel">
<h2>Stats</h2>
<div class="stats" id="stats">
<div class="stat"><span class="stat-k">Total clicks</span><span class="stat-v" id="stat-clicks"></span></div>
<div class="stat"><span class="stat-k">Unique users</span><span class="stat-v" id="stat-unique"></span></div>
<div class="stat"><span class="stat-k">Invites</span><span class="stat-v" id="stat-invites"></span></div>
<div class="stat"><span class="stat-k">Admins</span><span class="stat-v" id="stat-admins"></span></div>
</div>
</section>
<section class="panel">
<h2>Per-user join summary</h2>
<table class="t" id="t-summary">
<thead><tr>
<th>Email</th><th class="num">Clicks</th><th>First click</th><th>Last click</th>
</tr></thead>
<tbody></tbody>
</table>
<p class="empty" id="empty-summary" hidden>No join clicks yet.</p>
</section>
<section class="panel">
<h2>Invites</h2>
<table class="t" id="t-invites">
<thead><tr>
<th>Email</th><th>Name</th><th>Invited</th><th>By</th><th class="num">Admin</th>
</tr></thead>
<tbody></tbody>
</table>
<p class="empty" id="empty-invites" hidden>No invites yet.</p>
</section>
<section class="panel">
<h2>Raw join log <span class="dim">(newest first)</span></h2>
<table class="t" id="t-clicks">
<thead><tr>
<th>When</th><th>Email</th><th class="mono">Session</th>
</tr></thead>
<tbody></tbody>
</table>
<p class="empty" id="empty-clicks" hidden>No clicks logged yet.</p>
</section>
<script src="/fenjaops/admin.js" defer></script>
</body>
</html>