From 648abfa3f7c91395b5eeca543f70e0b6ea59e9e0 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Fri, 10 Jul 2026 21:54:23 +0800 Subject: [PATCH 1/4] docs: align readiness runtime version --- docs/production-readiness-checklist.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/production-readiness-checklist.md b/docs/production-readiness-checklist.md index e38e98c7f..1596dc639 100644 --- a/docs/production-readiness-checklist.md +++ b/docs/production-readiness-checklist.md @@ -2,9 +2,9 @@ This is the runbook to make the app publishable in one focused pass. -Last reviewed: 2026-07-04. Applies to any feature branch or release candidate. +Last reviewed: 2026-07-10. Applies to any feature branch or release candidate. -- Runtime target: Next.js 16.2.9, Node 24.x, npm 11.x. +- Runtime target: Next.js 16.2.10, Node 24.x, npm 11.x. - Supabase target: `sjrfecxgysukkwxsowpy` (`Clinical KB Database`). ## Immediate completion targets From 67f5bb2744939922ceb280fab8785ee0259b26f2 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sat, 11 Jul 2026 03:51:25 +0800 Subject: [PATCH 2/4] fix: wire document search command centre to live /api/search The /documents/search "Search command centre" filtered a hardcoded fixture array, so real queries (e.g. "lithium") returned "No documents match" even though the corpus is indexed. Replace the fixtures + client filter in MasterDocumentSearch with a POST /api/search (mode: documents) fetch: map documentMatches + result source_metadata into the existing table and mobile cards (status, version, evidence counts, relevance, snippet), add loading/error/empty states, and pass the auth header so signed-in users get owner-scoped results and anonymous users get the public corpus. Open links now target the real document viewer. Co-Authored-By: Claude Opus 4.8 --- .../master-document-flow-mockups.tsx | 425 ++++++++++++------ 1 file changed, 282 insertions(+), 143 deletions(-) diff --git a/src/components/master-document-flow-mockups.tsx b/src/components/master-document-flow-mockups.tsx index dee63477d..03e317e6b 100644 --- a/src/components/master-document-flow-mockups.tsx +++ b/src/components/master-document-flow-mockups.tsx @@ -20,6 +20,7 @@ import { ImageIcon, Layers3, List, + Loader2, MessageSquareText, MoreVertical, PanelRight, @@ -31,11 +32,14 @@ import { Table2, type LucideIcon, } from "lucide-react"; -import { ReactNode, useMemo, useState } from "react"; +import { ReactNode, useEffect, useMemo, useState } from "react"; import { CrossModeLinksSection } from "@/components/clinical-dashboard/cross-mode-links"; +import { documentRelevancePercent } from "@/components/clinical-dashboard/relevance-score"; import { cn } from "@/components/ui-primitives"; import { documentEvidenceHref, documentReaderHref, documentsSearchHref } from "@/lib/document-flow-routes"; +import { useAuthSession } from "@/lib/supabase/client"; +import type { DocumentMatch } from "@/lib/types"; type EvidenceType = "table" | "quote" | "image" | "related"; @@ -284,17 +288,6 @@ function searchHref(query = defaultQuery) { return documentsSearchHref({ query }); } -function evidenceForType(document: DocumentFixture, type: "all" | EvidenceType) { - if (type !== "all") return document.evidence.find((evidence) => evidence.type === type); - return document.evidence[0]; -} - -function evidenceLabel(evidence: EvidenceFixture) { - if (evidence.type === "quote") return "Quote"; - if (evidence.type === "related") return "Related"; - return evidence.label; -} - function evidenceCountLabel(document: DocumentFixture, type: EvidenceType, label: string) { return `${label} ${document.evidence.filter((evidence) => evidence.type === type).length}`; } @@ -306,13 +299,6 @@ function evidenceTypeIconFor(type: EvidenceType): LucideIcon { return Layers3; } -function evidenceTypeLabel(type: EvidenceType) { - if (type === "table") return "Table evidence"; - if (type === "quote") return "Quote evidence"; - if (type === "image") return "Image evidence"; - return "Related evidence"; -} - function Pill({ children, active = false, @@ -448,18 +434,19 @@ function DocumentSearchCategoryRail() { ); } -function SearchResultMobileCard({ - document, - query, - selected, - activeType = "all", -}: { - document: DocumentFixture; - query: string; - selected: boolean; - activeType?: "all" | EvidenceType; -}) { - const evidence = evidenceForType(document, activeType); +function DocumentEvidencePills({ row }: { row: DocumentSearchRow }) { + const hasEvidence = row.tableCount > 0 || row.imageCount > 0; + return ( +
+ {row.tableCount > 0 ? {`Tables ${row.tableCount}`} : null} + {row.imageCount > 0 ? {`Images ${row.imageCount}`} : null} + {!hasEvidence ? Text match : null} + {row.page ? p.{row.page} : null} +
+ ); +} + +function SearchResultMobileCard({ row, selected }: { row: DocumentSearchRow; selected: boolean }) { return (
-
-
- {evidence ? ( - <> - - {evidenceTypeLabel(evidence.type)} - · - p.{evidence.page} - · - {evidence.relevance}% - - ) : ( - <> -
+
+
{selected ? Best match : }
@@ -501,56 +477,40 @@ function SearchResultMobileCard({
- {document.title} + {row.title}

- {document.kind} · {document.version} + {row.metaLine} + {row.version ? ` · ${row.version}` : ""}

- {evidence ? ( -

- {evidence.title} -

- ) : null}
-

- {evidence ? evidence.body : document.snippet} -

+

{row.snippet}

- - {document.status} - - {evidence ? evidenceLabel(evidence) : "No extracted evidence"} + {row.statusLabel ? ( + + {row.statusLabel} + + ) : null} +
-
+
Open document
); @@ -590,13 +550,6 @@ function evidenceTone(type: EvidenceType): "teal" | "amber" | "blue" | "violet" return "violet"; } -function EvidenceTypeIcon({ type, className }: { type: EvidenceType; className?: string }) { - if (type === "table") return