{message.title}
+{message.summary}
+ {message.detail && {message.detail}} +diff --git a/frontend/package.json b/frontend/package.json
index e1dfd12..166e4b2 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -10,7 +10,7 @@
"test:interview": "node --test src/interviewEngine*.test.js",
"test:resume": "node --test src/resumeStructured.test.js src/dashboardTags.test.js",
"test:seo": "node scripts/verify-search-appearance.mjs",
- "test:clicks": "node scripts/audit-all-clicks.mjs",
+ "test:clicks": "node scripts/run-click-audit.mjs",
"test:layout": "node scripts/audit-responsive-layout.mjs",
"test:bundle": "node scripts/verify-bundle-budget.mjs",
"preview": "vite preview"
diff --git a/frontend/scripts/run-click-audit.mjs b/frontend/scripts/run-click-audit.mjs
new file mode 100644
index 0000000..ad915dc
--- /dev/null
+++ b/frontend/scripts/run-click-audit.mjs
@@ -0,0 +1,33 @@
+import { spawn } from "node:child_process";
+
+const MAX_ATTEMPTS = 2;
+
+function runAudit() {
+ return new Promise((resolve) => {
+ const child = spawn(process.execPath, ["scripts/audit-all-clicks.mjs"], {
+ cwd: process.cwd(),
+ env: process.env,
+ stdio: "inherit",
+ });
+
+ child.once("exit", (code, signal) => {
+ if (signal) {
+ resolve(1);
+ return;
+ }
+ resolve(code ?? 1);
+ });
+ });
+}
+
+for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt += 1) {
+ const exitCode = await runAudit();
+ if (exitCode === 0) process.exit(0);
+
+ if (attempt < MAX_ATTEMPTS) {
+ console.warn(`Click audit attempt ${attempt} failed; retrying once with a fresh Chrome/CDP session.`);
+ } else {
+ console.error(`Click audit failed after ${MAX_ATTEMPTS} independent attempts.`);
+ process.exit(exitCode);
+ }
+}
diff --git a/frontend/src/OpsConsolePage.css b/frontend/src/OpsConsolePage.css
index 808b2bc..282803f 100644
--- a/frontend/src/OpsConsolePage.css
+++ b/frontend/src/OpsConsolePage.css
@@ -1 +1,7 @@
-.ops-page{min-height:100vh;padding:32px;background:#0b1020;color:#edf2ff}.ops-header{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;margin-bottom:18px}.ops-header h1{margin:4px 0 8px;font-size:clamp(2rem,4vw,3.2rem)}.ops-header p{max-width:760px;color:#aeb9d6}.ops-kicker{margin:0;color:#8ea1ff;font-size:.74rem;font-weight:800;letter-spacing:.14em}.ops-env{padding:10px 14px;border-radius:999px;font-size:.78rem;font-weight:900;letter-spacing:.08em;border:1px solid rgba(255,255,255,.16)}.ops-env.production{background:#4a1420;color:#ffd6de}.ops-env.nonprod{background:#133725;color:#c8ffe0}.ops-toolbar{display:flex;justify-content:space-between;gap:16px;align-items:center;margin-bottom:22px;padding:12px 14px;background:#121a31;border:1px solid #263250;border-radius:14px}.ops-toolbar button,.ops-user-search button{border:0;border-radius:10px;padding:10px 14px;background:#6e7cff;color:white;font-weight:800;cursor:pointer}.ops-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;margin-bottom:18px}.ops-card,.ops-panel{background:#121a31;border:1px solid #263250;border-radius:16px}.ops-card{padding:18px;display:grid;gap:7px}.ops-card span,.ops-user-result span{color:#8795b8;font-size:.78rem;text-transform:uppercase;letter-spacing:.06em}.ops-card strong{font-size:1.45rem}.ops-card small{color:#9aa8ca}.healthy{color:#7ef0aa}.degraded{color:#ffb37b}.ops-panel{padding:18px;margin-top:14px}.ops-panel-heading{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.ops-panel-heading p{color:#9aa8ca}.ops-panel h2{margin:3px 0 0;font-size:1.15rem}.ops-table-wrap{overflow:auto}.ops-table{width:100%;border-collapse:collapse;font-size:.86rem}.ops-table th,.ops-table td{text-align:left;padding:10px 8px;border-bottom:1px solid #263250;white-space:nowrap}.ops-table th{color:#8d9abc;font-size:.74rem;text-transform:uppercase}.ops-table code{color:#dbe3ff}.ops-empty,.ops-error{color:#9aa8ca}.ops-error{color:#ffb4b4}.ops-user-search{display:flex;gap:10px;max-width:620px}.ops-user-search input{flex:1;min-width:0;background:#0d1427;color:white;border:1px solid #33415f;border-radius:10px;padding:11px 12px}.ops-user-result{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin-top:16px}.ops-user-result>div{padding:12px;background:#0d1427;border:1px solid #263250;border-radius:12px;display:grid;gap:5px}.ops-team-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.ops-team-card{padding:15px;background:#0d1427;border:1px solid #2a3656;border-radius:14px;display:grid;gap:12px}.ops-team-card>div:first-child{display:grid;gap:3px}.ops-team-card small{color:#91a0c4}.ops-role-list{display:flex;flex-wrap:wrap;gap:8px}.ops-role-list label{display:flex;align-items:center;gap:7px;padding:7px 10px;background:#151f39;border:1px solid #344261;border-radius:999px;cursor:pointer;text-transform:capitalize}.ops-role-list input{accent-color:#8090ff}.ops-bootstrap-badge{width:max-content;padding:5px 8px;border-radius:999px;background:#24365d;color:#bfd0ff;font-size:.72rem;font-weight:800;text-transform:uppercase;letter-spacing:.05em}.ops-audit-list{margin-top:18px;border-top:1px solid #263250;padding-top:14px}.ops-audit-list h3{margin:0 0 10px}.ops-audit-list>div{display:grid;grid-template-columns:minmax(150px,1fr) minmax(140px,.8fr) minmax(220px,1.4fr);gap:10px;padding:9px 0;border-bottom:1px solid #202b46;font-size:.84rem}.ops-audit-list span{color:#93a0bf}.ops-audit-list code{color:#dce4ff;white-space:normal}.ops-denied,.ops-loading{max-width:760px;margin:90px auto;padding:28px;background:#121a31;border:1px solid #263250;border-radius:18px}.ops-denied a{color:#aeb8ff}@media(max-width:900px){.ops-grid,.ops-user-result,.ops-team-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.ops-header{flex-direction:column}.ops-audit-list>div{grid-template-columns:1fr}}@media(max-width:600px){.ops-page{padding:18px}.ops-grid,.ops-user-result,.ops-team-grid{grid-template-columns:1fr}.ops-user-search{flex-direction:column}.ops-toolbar{align-items:flex-start;flex-direction:column}}
\ No newline at end of file
+.ops-page{min-height:100vh;padding:32px;background:#0b1020;color:#edf2ff}.ops-header{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;margin-bottom:18px}.ops-header h1{margin:4px 0 8px;font-size:clamp(2rem,4vw,3.2rem)}.ops-header p{max-width:760px;color:#aeb9d6}.ops-kicker{margin:0;color:#8ea1ff;font-size:.74rem;font-weight:800;letter-spacing:.14em}.ops-env{padding:10px 14px;border-radius:999px;font-size:.78rem;font-weight:900;letter-spacing:.08em;border:1px solid rgba(255,255,255,.16)}.ops-env.production{background:#4a1420;color:#ffd6de}.ops-env.nonprod{background:#133725;color:#c8ffe0}.ops-toolbar{display:flex;justify-content:space-between;gap:16px;align-items:center;margin-bottom:22px;padding:12px 14px;background:#121a31;border:1px solid #263250;border-radius:14px}.ops-toolbar button,.ops-user-search button{border:0;border-radius:10px;padding:10px 14px;background:#6e7cff;color:white;font-weight:800;cursor:pointer}.ops-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;margin-bottom:18px}.ops-card,.ops-panel{background:#121a31;border:1px solid #263250;border-radius:16px}.ops-card{padding:18px;display:grid;gap:7px}.ops-card span,.ops-user-result span{color:#8795b8;font-size:.78rem;text-transform:uppercase;letter-spacing:.06em}.ops-card strong{font-size:1.45rem}.ops-card small{color:#9aa8ca}.healthy{color:#7ef0aa}.degraded{color:#ffb37b}.ops-panel{padding:18px;margin-top:14px}.ops-panel-heading{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.ops-panel-heading p{color:#9aa8ca}.ops-panel h2{margin:3px 0 0;font-size:1.15rem}.ops-table-wrap{overflow:auto}.ops-table{width:100%;border-collapse:collapse;font-size:.86rem}.ops-table th,.ops-table td{text-align:left;padding:10px 8px;border-bottom:1px solid #263250;white-space:nowrap}.ops-table th{color:#8d9abc;font-size:.74rem;text-transform:uppercase}.ops-table code{color:#dbe3ff}.ops-empty,.ops-error{color:#9aa8ca}.ops-error{color:#ffb4b4}.ops-user-search{display:flex;gap:10px;max-width:620px}.ops-user-search input{flex:1;min-width:0;background:#0d1427;color:white;border:1px solid #33415f;border-radius:10px;padding:11px 12px}.ops-user-result{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin-top:16px}.ops-user-result>div{padding:12px;background:#0d1427;border:1px solid #263250;border-radius:12px;display:grid;gap:5px}.ops-team-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.ops-team-card{padding:15px;background:#0d1427;border:1px solid #2a3656;border-radius:14px;display:grid;gap:12px}.ops-team-card>div:first-child{display:grid;gap:3px}.ops-team-card small{color:#91a0c4}.ops-role-list{display:flex;flex-wrap:wrap;gap:8px}.ops-role-list label{display:flex;align-items:center;gap:7px;padding:7px 10px;background:#151f39;border:1px solid #344261;border-radius:999px;cursor:pointer;text-transform:capitalize}.ops-role-list input{accent-color:#8090ff}.ops-bootstrap-badge{width:max-content;padding:5px 8px;border-radius:999px;background:#24365d;color:#bfd0ff;font-size:.72rem;font-weight:800;text-transform:uppercase;letter-spacing:.05em}.ops-audit-list{margin-top:18px;border-top:1px solid #263250;padding-top:14px}.ops-audit-list h3{margin:0 0 10px}.ops-audit-list>div{display:grid;grid-template-columns:minmax(150px,1fr) minmax(140px,.8fr) minmax(220px,1.4fr);gap:10px;padding:9px 0;border-bottom:1px solid #202b46;font-size:.84rem}.ops-audit-list span{color:#93a0bf}.ops-audit-list code{color:#dce4ff;white-space:normal}.ops-denied,.ops-loading{max-width:760px;margin:90px auto;padding:28px;background:#121a31;border:1px solid #263250;border-radius:18px}.ops-denied a{color:#aeb8ff}
+
+.ops-inbox-panel{padding:0;overflow:hidden;background:linear-gradient(180deg,#141d37 0%,#10172b 100%);border-color:#34436b;box-shadow:0 18px 50px rgba(0,0,0,.2)}.ops-inbox-heading{display:flex;justify-content:space-between;gap:20px;padding:22px 22px 18px;border-bottom:1px solid #263250}.ops-inbox-heading>div:first-child{max-width:850px}.ops-inbox-heading h2{display:flex;align-items:center;gap:10px;margin:5px 0 7px;font-size:1.35rem}.ops-inbox-heading p:last-child{margin:0;color:#9aa8ca;line-height:1.55}.ops-inbox-summary{display:grid;grid-template-columns:repeat(2,minmax(100px,1fr));gap:8px;min-width:230px}.ops-inbox-summary>div{display:grid;grid-template-columns:auto auto;gap:3px 8px;align-content:center;padding:12px 14px;background:#0d1427;border:1px solid #2a3656;border-radius:14px}.ops-inbox-summary svg{grid-row:1/3;color:#93a5ff}.ops-inbox-summary strong{font-size:1.2rem}.ops-inbox-summary span{font-size:.72rem;color:#8f9cbb;text-transform:uppercase;letter-spacing:.07em}.ops-inbox-controls{display:flex;justify-content:space-between;gap:12px;align-items:center;padding:13px 18px;background:#0f1629;border-bottom:1px solid #263250}.ops-inbox-tabs{display:flex;gap:7px;flex-wrap:wrap}.ops-inbox-tabs button{display:inline-flex;align-items:center;gap:7px;padding:8px 10px;border-radius:999px;border:1px solid #303e60;background:#151e35;color:#bac5e2;font:inherit;font-size:.82rem;font-weight:750;cursor:pointer}.ops-inbox-tabs button span{display:inline-grid;place-items:center;min-width:20px;height:20px;padding:0 5px;border-radius:999px;background:#263451;color:#dbe3ff;font-size:.72rem}.ops-inbox-tabs button.active{background:#6e7cff;border-color:#8591ff;color:#fff}.ops-inbox-tabs button.active span{background:rgba(8,14,32,.28);color:#fff}.ops-inbox-search{display:flex;align-items:center;gap:8px;min-width:220px;padding:8px 10px;border:1px solid #33415f;border-radius:10px;background:#0b1224;color:#8290b2}.ops-inbox-search input{width:100%;border:0;outline:0;background:transparent;color:#f4f7ff;font:inherit}.ops-inbox-search input::placeholder{color:#73819f}.ops-message-list{display:grid}.ops-message{position:relative;display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:14px;padding:17px 20px;border-bottom:1px solid #222f4b;transition:background .16s ease,border-color .16s ease}.ops-message:last-child{border-bottom:0}.ops-message.unread{background:linear-gradient(90deg,rgba(110,124,255,.08),transparent 42%)}.ops-message:hover{background:#141d34}.ops-message.urgent{border-left:3px solid #ff6f8d}.ops-message.action{border-left:3px solid #ffb968}.ops-message.warning{border-left:3px solid #e7a45e}.ops-message.info{border-left:3px solid #7389ff}.ops-message-icon{display:grid;place-items:center;width:36px;height:36px;border-radius:11px;background:#1b2744;color:#aebaff}.ops-message.urgent .ops-message-icon{background:#431b2a;color:#ffadbf}.ops-message.action .ops-message-icon,.ops-message.warning .ops-message-icon{background:#3c2b1c;color:#ffd09b}.ops-message-body{min-width:0}.ops-message-body h3{margin:5px 0 5px;font-size:1rem}.ops-message-body p{margin:0;color:#b2bdd8;line-height:1.48}.ops-message-body small{display:block;margin-top:7px;color:#7786aa;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;overflow-wrap:anywhere}.ops-message-meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap;color:#7f8daf;font-size:.73rem}.ops-priority{padding:4px 7px;border-radius:999px;font-size:.64rem;font-weight:900;letter-spacing:.07em;text-transform:uppercase}.ops-priority.urgent{background:#4e1b2b;color:#ffb7c6}.ops-priority.action,.ops-priority.warning{background:#3d2c1c;color:#ffd09b}.ops-priority.info{background:#243259;color:#b9c6ff}.ops-unread-dot{display:inline-flex;align-items:center;gap:5px;color:#b9c4ff;font-weight:800}.ops-unread-dot::before{content:"";width:6px;height:6px;border-radius:50%;background:#8290ff;box-shadow:0 0 0 3px rgba(130,144,255,.12)}.ops-sync-badge{padding:4px 7px;border:1px solid #6d4a31;border-radius:999px;color:#ffd2a3;background:#2a201a;font-weight:750}.ops-message-actions{display:flex;align-items:flex-start;justify-content:flex-end;gap:6px;flex-wrap:wrap;max-width:310px}.ops-message-actions button,.ops-message-actions a{display:inline-flex;align-items:center;gap:6px;padding:7px 9px;border:1px solid #33415f;border-radius:9px;background:#10182d;color:#bfc9e4;text-decoration:none;font:inherit;font-size:.74rem;font-weight:750;cursor:pointer}.ops-message-actions button:hover,.ops-message-actions a:hover{border-color:#6e7cff;color:#fff}.ops-inbox-empty{display:grid;justify-items:center;gap:7px;padding:34px 20px;color:#8391b2;text-align:center}.ops-inbox-empty svg{color:#7286e7}.ops-inbox-empty strong{color:#dce4fb;font-size:1rem}.ops-inbox-empty span{font-size:.84rem}
+
+@media(max-width:1050px){.ops-inbox-heading{flex-direction:column}.ops-inbox-summary{min-width:0;width:max-content}.ops-inbox-controls{align-items:stretch;flex-direction:column}.ops-inbox-search{min-width:0}.ops-message{grid-template-columns:auto minmax(0,1fr)}.ops-message-actions{grid-column:2;justify-content:flex-start;max-width:none}}
+@media(max-width:900px){.ops-grid,.ops-user-result,.ops-team-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.ops-header{flex-direction:column}.ops-audit-list>div{grid-template-columns:1fr}}
+@media(max-width:600px){.ops-page{padding:18px}.ops-grid,.ops-user-result,.ops-team-grid{grid-template-columns:1fr}.ops-user-search{flex-direction:column}.ops-toolbar{align-items:flex-start;flex-direction:column}.ops-inbox-heading{padding:18px}.ops-inbox-summary{width:100%;grid-template-columns:repeat(2,minmax(0,1fr))}.ops-inbox-tabs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}.ops-inbox-tabs button{justify-content:space-between}.ops-message{grid-template-columns:1fr;padding:16px}.ops-message-icon{display:none}.ops-message-actions{grid-column:1}.ops-message-actions button,.ops-message-actions a{flex:1;justify-content:center;min-width:120px}}
diff --git a/frontend/src/OpsConsolePage.jsx b/frontend/src/OpsConsolePage.jsx
index 222517c..a83e5f4 100644
--- a/frontend/src/OpsConsolePage.jsx
+++ b/frontend/src/OpsConsolePage.jsx
@@ -1,4 +1,15 @@
-import { useEffect, useState } from "react";
+import { useEffect, useMemo, useState } from "react";
+import {
+ AlertTriangle,
+ Archive,
+ Bell,
+ CheckCheck,
+ Clock3,
+ ExternalLink,
+ Inbox,
+ Info,
+ Search,
+} from "lucide-react";
import {
getOpsAccess,
getOpsAudit,
@@ -11,6 +22,263 @@ import {
import BragStackLoader from "./BragStackLoader.jsx";
import "./OpsConsolePage.css";
+const OPS_INBOX_STORAGE_KEY = "bragstack_ops_inbox_state_v1";
+const ATTENTION_PRIORITIES = new Set(["urgent", "action", "warning"]);
+
+function readInboxState() {
+ if (typeof window === "undefined") return { read: {}, archived: {}, snoozedUntil: {} };
+ try {
+ const parsed = JSON.parse(window.localStorage.getItem(OPS_INBOX_STORAGE_KEY) || "{}");
+ return {
+ read: parsed.read || {},
+ archived: parsed.archived || {},
+ snoozedUntil: parsed.snoozedUntil || {},
+ };
+ } catch {
+ return { read: {}, archived: {}, snoozedUntil: {} };
+ }
+}
+
+function relativeTime(value) {
+ if (!value) return "recently";
+ const timestamp = new Date(value).getTime();
+ if (!Number.isFinite(timestamp)) return "recently";
+ const diffSeconds = Math.round((timestamp - Date.now()) / 1000);
+ const formatter = new Intl.RelativeTimeFormat(undefined, { numeric: "auto" });
+ if (Math.abs(diffSeconds) < 60) return formatter.format(diffSeconds, "second");
+ const diffMinutes = Math.round(diffSeconds / 60);
+ if (Math.abs(diffMinutes) < 60) return formatter.format(diffMinutes, "minute");
+ const diffHours = Math.round(diffMinutes / 60);
+ if (Math.abs(diffHours) < 24) return formatter.format(diffHours, "hour");
+ return formatter.format(Math.round(diffHours / 24), "day");
+}
+
+function isFutureTimestamp(value) {
+ return Number(value || 0) > Date.now();
+}
+
+function buildOpsMessages({ service = {}, persisted = {}, audit = null }) {
+ const messages = [];
+
+ if (service.mongo && service.mongo !== "ok") {
+ messages.push({
+ id: `infra:mongo:${service.mongo}`,
+ source: "Infrastructure",
+ category: "infrastructure",
+ priority: "urgent",
+ title: "MongoDB health needs attention",
+ summary: `The API reports MongoDB as ${service.mongo}. Production data operations may be affected.`,
+ createdAt: new Date().toISOString(),
+ syncRecommended: true,
+ });
+ }
+
+ const serverErrors = Number(persisted.status_classes?.["5xx"] || 0);
+ if (serverErrors > 0) {
+ messages.push({
+ id: `app:5xx:${serverErrors}:${persisted.sample_size || 0}`,
+ source: "Application",
+ category: "application",
+ priority: serverErrors >= 5 ? "urgent" : "warning",
+ title: `${serverErrors} server error${serverErrors === 1 ? "" : "s"} in the retention window`,
+ summary: "BragStack has persisted 5xx responses that are worth reviewing before they become a user-facing pattern.",
+ createdAt: persisted.failures?.[0]?.created_at || persisted.failures?.[0]?.timestamp,
+ syncRecommended: serverErrors >= 5,
+ });
+ }
+
+ (persisted.errors || []).slice(0, 5).forEach((row) => {
+ messages.push({
+ id: `error:${row.fingerprint}`,
+ source: "Application",
+ category: "application",
+ priority: Number(row.count || 0) >= 3 ? "action" : "warning",
+ title: row.error_type || "Grouped backend exception",
+ summary: `${row.method || "REQUEST"} ${row.path || "unknown path"} · ${row.count || 1} occurrence${Number(row.count || 1) === 1 ? "" : "s"}.`,
+ detail: row.version ? `Version ${row.version}` : null,
+ createdAt: row.last_seen,
+ syncRecommended: Number(row.count || 0) >= 3,
+ });
+ });
+
+ (persisted.failures || []).slice(0, 8).forEach((row) => {
+ const status = Number(row.status_code || 0);
+ if (status < 500) return;
+ messages.push({
+ id: `failure:${row.request_id || `${row.method}:${row.path}:${row.created_at || row.timestamp}`}`,
+ source: "Application",
+ category: "application",
+ priority: status >= 500 ? "warning" : "action",
+ title: `${status} response on ${row.path || "request"}`,
+ summary: `${row.method || "REQUEST"} ${row.path || "unknown path"} returned ${status}${row.duration_ms != null ? ` in ${row.duration_ms} ms` : ""}.`,
+ detail: row.request_id ? `Request ${row.request_id}` : null,
+ createdAt: row.created_at || row.timestamp,
+ syncRecommended: status >= 500,
+ });
+ });
+
+ (persisted.slow || []).slice(0, 4).forEach((row) => {
+ const duration = Number(row.duration_ms || 0);
+ if (duration < 2000) return;
+ messages.push({
+ id: `slow:${row.request_id || `${row.method}:${row.path}:${row.created_at || row.timestamp}`}`,
+ source: "Application",
+ category: "performance",
+ priority: duration >= 5000 ? "action" : "info",
+ title: "Slow production request detected",
+ summary: `${row.method || "REQUEST"} ${row.path || "unknown path"} took ${duration} ms.`,
+ detail: row.request_id ? `Request ${row.request_id}` : null,
+ createdAt: row.created_at || row.timestamp,
+ syncRecommended: duration >= 5000,
+ });
+ });
+
+ (audit?.events || []).slice(0, 8).forEach((event, index) => {
+ const isVerification = event.event === "verification_email_resent";
+ messages.push({
+ id: `admin:${event.created_at || index}:${event.event || "activity"}`,
+ source: "Admin",
+ category: "security",
+ priority: "info",
+ title: isVerification ? "Verification email resent" : "Internal access updated",
+ summary: isVerification
+ ? "An authorized operator resent an account verification email."
+ : "An authorized operator changed internal role permissions. The detailed audit record remains below.",
+ createdAt: event.created_at,
+ syncRecommended: false,
+ });
+ });
+
+ const priorityWeight = { urgent: 4, action: 3, warning: 2, info: 1 };
+ return messages.sort((a, b) => {
+ const priorityDiff = (priorityWeight[b.priority] || 0) - (priorityWeight[a.priority] || 0);
+ if (priorityDiff) return priorityDiff;
+ return new Date(b.createdAt || 0).getTime() - new Date(a.createdAt || 0).getTime();
+ });
+}
+
+function PriorityIcon({ priority }) {
+ if (priority === "urgent" || priority === "warning" || priority === "action") return ;
+ return ;
+}
+
+function OpsInbox({ service, persisted, audit }) {
+ const messages = useMemo(() => buildOpsMessages({ service, persisted, audit }), [service, persisted, audit]);
+ const [state, setState] = useState(readInboxState);
+ const [filter, setFilter] = useState("all");
+ const [query, setQuery] = useState("");
+
+ useEffect(() => {
+ try { window.localStorage.setItem(OPS_INBOX_STORAGE_KEY, JSON.stringify(state)); } catch { /* storage is optional */ }
+ }, [state]);
+
+ const isSnoozed = (id) => isFutureTimestamp(state.snoozedUntil[id]);
+ const isArchived = (id) => Boolean(state.archived[id]);
+ const isRead = (id) => Boolean(state.read[id]);
+
+ const unreadCount = messages.filter((message) => !isRead(message.id) && !isArchived(message.id) && !isSnoozed(message.id)).length;
+ const attentionCount = messages.filter((message) => ATTENTION_PRIORITIES.has(message.priority) && !isArchived(message.id) && !isSnoozed(message.id)).length;
+ const snoozedCount = messages.filter((message) => isSnoozed(message.id) && !isArchived(message.id)).length;
+
+ const filteredMessages = messages.filter((message) => {
+ const archived = isArchived(message.id);
+ const snoozed = isSnoozed(message.id);
+ if (filter === "archived" && !archived) return false;
+ if (filter === "snoozed" && (!snoozed || archived)) return false;
+ if (filter !== "archived" && archived) return false;
+ if (filter !== "snoozed" && snoozed) return false;
+ if (filter === "attention" && !ATTENTION_PRIORITIES.has(message.priority)) return false;
+ if (filter === "updates" && message.priority !== "info") return false;
+ if (query.trim()) {
+ const haystack = `${message.title} ${message.summary} ${message.source} ${message.category}`.toLowerCase();
+ if (!haystack.includes(query.trim().toLowerCase())) return false;
+ }
+ return true;
+ });
+
+ function markRead(id) {
+ setState((current) => ({ ...current, read: { ...current.read, [id]: true } }));
+ }
+
+ function archiveMessage(id) {
+ setState((current) => ({
+ ...current,
+ read: { ...current.read, [id]: true },
+ archived: { ...current.archived, [id]: !current.archived[id] },
+ }));
+ }
+
+ function snoozeMessage(id) {
+ setState((current) => ({
+ ...current,
+ read: { ...current.read, [id]: true },
+ snoozedUntil: { ...current.snoozedUntil, [id]: Date.now() + (60 * 60 * 1000) },
+ }));
+ }
+
+ const filters = [
+ ["all", "All", messages.filter((message) => !isArchived(message.id) && !isSnoozed(message.id)).length],
+ ["attention", "Needs attention", attentionCount],
+ ["updates", "Updates", messages.filter((message) => message.priority === "info" && !isArchived(message.id) && !isSnoozed(message.id)).length],
+ ["snoozed", "Snoozed", snoozedCount],
+ ["archived", "Archived", messages.filter((message) => isArchived(message.id)).length],
+ ];
+
+ return FOUNDER · OPS INBOX Important production, admin, performance, and future integration updates without the raw-log noise. GitHub, PostHog, HubSpot, Metricool, Stripe, Netlify, Render, and Atlas can plug into this normalized message stream as integrations are wired. {message.summary} Messages worth reading
+ {message.title}
+
No matching request events yet.
; return| Time | Method | Path | Status | Duration | Request ID |
|---|---|---|---|---|---|
| {new Date(row.created_at || row.timestamp).toLocaleTimeString()} | {row.method} | {row.path} | {row.status_code} | {row.duration_ms} ms | {row.request_id} |
INTERNAL · CONTROLLED ACCESS
Live application diagnostics, persistent request tracing, grouped errors, database health, safe user-state debugging, and audited internal access management.
INTERNAL · CONTROLLED ACCESS
Founder operations, live application diagnostics, persistent request tracing, grouped errors, database health, safe user-state debugging, and audited internal access management.
PERSISTENT OBSERVABILITY V2
Sanitized fingerprints survive restarts and deployments without storing request bodies, headers, tokens, query strings, or exception messages.
PERSISTENT FAILURES
PERSISTENT PERFORMANCE