import { sql } from "@/db"; import { requireUserPage } from "@/lib/auth/guard"; import { csrfToken } from "@/lib/auth/session"; import { systemAction } from "@/lib/admin/actions"; import { Csrf, Notice, PageTitle } from "@/components/admin-ui"; import { embeddingsEnabled, verifyEmbeddingModel } from "@/lib/ai/embeddings"; import { STORAGE_DIR } from "@/lib/env"; export default async function System({ searchParams }: { searchParams: Promise> }) { const sp = await searchParams; const u = await requireUserPage(); const csrf = csrfToken(u); const [jobs, backups, [storage], ai] = await Promise.all([sql`SELECT * FROM jobs ORDER BY created_at DESC LIMIT 60`, sql`SELECT * FROM backups ORDER BY created_at DESC LIMIT 15`, sql`SELECT count(*)::int AS files, coalesce(sum(bytes), 0)::bigint AS bytes FROM files`, embeddingsEnabled() ? verifyEmbeddingModel() : Promise.resolve({ ok: false, model: "—", reason: "AI provider disabled (AI_PROVIDER=none)" })]); const Btn = ({ op, label }: { op: string; label: string }) =>
; return (

Storage

{storage.files} files · {(Number(storage.bytes) / 1e6).toFixed(1)} MB

{STORAGE_DIR}

AI embeddings

{ai.ok ? OK · {ai.model} : off · {ai.reason}}

Optional. Search and relations degrade to lexical signals without it.

Worker schedule

stats 00:10 · relations 03:00 · backup 04:40 (node local time)

Backups

{backups.map((b) => )}
WhenOKRemoteSizeLog
{new Date(b.created_at).toLocaleString("en-CA")}{b.ok ? "✓" : ✗}{b.remote_ok === null ? "—" : b.remote_ok ? "✓" : ✗}{(Number(b.bytes) / 1e6).toFixed(1)} MB{b.log}

Jobs (latest 60)

{jobs.map((j) => )}
IDKindStatusAttemptsCreatedFinishedError
{j.id}{j.kind}{j.status}{j.attempts}{new Date(j.created_at).toLocaleString("en-CA")}{j.finished_at ? new Date(j.finished_at).toLocaleString("en-CA") : ""}{j.last_error ?? ""}
); }