tia/src/app/(app)/error.tsx
Mannu 7a60132bb2 Add admin observability: error tracking, audit viewer, AI metrics, health
Turns the admin panel into a real monitoring tool so production bugs are
visible instead of silent.

- Error & crash tracking: error_events table (migration 0010) + logError()
  helper + /api/errors ingest; global-error.tsx and (app)/error.tsx report
  crashes automatically; /admin/errors viewer (recent + grouped, filters).
- Full audit-log viewer at /admin/audit over the existing audit_log (all
  actions, not just auth) with action/resource/family/user/text filters.
- AI observability at /admin/ai over ai_usage: per-intent latency (avg/p95),
  tokens, cost, daily trend, slowest calls, medical-redirect count.
- System health at /admin/health: DB latency, migration status, recent error
  volume, and integration config presence.
- Sidebar updated with Health / Errors / Audit Log / AI Usage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 00:27:07 +05:30

48 lines
1.6 KiB
TypeScript

"use client";
import { useEffect } from "react";
// Error boundary for the authenticated (app) segment. Catches render/runtime
// errors in any /(app) page (home, ai, growth, …), shows a friendly recovery
// UI, and reports the crash to /api/errors for the admin error tracker.
export default function AppError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
try {
fetch("/api/errors", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
message: error?.message || "Unknown app error",
stack: error?.stack,
digest: error?.digest,
url: typeof window !== "undefined" ? window.location.pathname : undefined,
level: "error",
metadata: { boundary: "app" },
}),
keepalive: true,
}).catch(() => {});
} catch {}
}, [error]);
return (
<div className="min-h-screen flex flex-col items-center justify-center gap-4 p-6 text-center bg-gradient-to-br from-rose-50 to-amber-50 dark:from-gray-900 dark:to-gray-800">
<div className="text-5xl">😵</div>
<h1 className="text-xl font-bold dark:text-white">Something went wrong</h1>
<p className="text-gray-500 dark:text-gray-400 max-w-sm text-sm">
This screen hit an unexpected error. It&apos;s been reported automatically.
</p>
<button
onClick={() => reset()}
className="bg-rose-400 text-white px-5 py-2.5 rounded-xl font-semibold"
>
Try again
</button>
</div>
);
}