import Link from "next/link"; import { sql } from "@/db"; import { requireUserPage } from "@/lib/auth/guard"; import { csrfToken } from "@/lib/auth/session"; import { ingestAction } from "@/lib/admin/actions"; import { Csrf, Notice, PageTitle } from "@/components/admin-ui"; import { STORAGE_DIR } from "@/lib/env"; export default async function Ingest({ searchParams }: { searchParams: Promise> }) { const sp = await searchParams; const u = await requireUserPage(); const rows = await sql`SELECT c.*, f.pages, f.integrity_ok FROM ingest_candidates c LEFT JOIN files f ON f.id = c.file_id ORDER BY (c.status IN ('ready','queued','processing')) DESC, c.created_at DESC LIMIT 200`; const [last] = await sql`SELECT value FROM settings WHERE key = 'ingest.last_scan'`; const [dirs] = await sql`SELECT value FROM settings WHERE key = 'ingest.extra_dirs'`; return (

Scanned directories: {STORAGE_DIR}/inbox{((dirs?.value as string[]) ?? []).map((d) => , {d})} (configure in Settings). Last scan: {last ? `${last.value.at} — ${last.value.found} PDF found, ${last.value.queued} new` : "never"}. Every candidate is checksummed, integrity-checked, text-extracted and checked for duplicates; metadata is a proposal that you must verify before approval. Nothing is published automatically.

{rows.map((c) => { const pr = c.proposal as Record; return ; })}
FileStatusProposed titleWP no.FlagsDuplicatesCreated
{String(c.source_path).split("/").pop()}
{c.pages ?? "?"} p.
{c.status}{pr?.title ?? "—"}{pr?.wp ? `${pr.wp.seriesCode}${pr.wp.number}` : "—"}{(c.flags as { code: string }[]).map((f) => {f.code})}{(c.duplicates as { identifier: string; score: number }[]).slice(0, 2).map((d) => {d.identifier} {(d.score * 100).toFixed(0)}%)}{String(c.created_at).slice(0, 16)}
{rows.length === 0 &&

Queue is empty. Drop PDFs in the inbox directory and scan.

}
); }