PR: #545: Story-2168: Document Page v2 — Original·Insights routes, live notes, Details/Reclassify by @ankitmaheshwari-com
View PR →

Files changed

74 file(s), +5415 / -52 lines

Path Role + -
messages/en.jsonConfig+71-2
messages/hi.jsonConfig+71-2
openapi/app-api.jsonConfig+381-0
openapi/permission-map.jsonConfig+51-0
src/app/[locale]/(workspace)/matters/[matterId]/record/doc/[documentId]/insights/page.tsxApp route+49-0
src/app/[locale]/(workspace)/matters/[matterId]/record/doc/[documentId]/layout.tsxApp route+9-0
src/app/api/internal/documents/[docId]/annotations/[annotationId]/dismiss/route.tsApp route+4-0
src/app/api/internal/documents/[docId]/annotations/[annotationId]/keep/route.tsApp route+4-0
src/app/api/internal/documents/[docId]/annotations/route.tsApp route+84-0
src/app/api/internal/documents/[docId]/insight-brief/route.tsApp route+5-0
src/app/api/internal/matters/[matterId]/documents/[docId]/declared-side/route.tsApp route+11-0
src/app/api/internal/matters/[matterId]/documents/[docId]/home/route.tsApp route+11-0
src/components/documents/viewer/annotations-presentation.tsComponent+120-0
src/components/documents/viewer/details-presentation.tsComponent+59-0
src/components/documents/viewer/document-counsel-bar.stories.tsxComponent+22-0
src/components/documents/viewer/document-counsel-bar.tsxComponent+96-0
src/components/documents/viewer/document-details-sheet.stories.tsxComponent+51-0
src/components/documents/viewer/document-details-sheet.tsxComponent+161-0
src/components/documents/viewer/document-gutter-mark.tsxComponent+60-0
src/components/documents/viewer/document-insights-live.tsxComponent+36-0
src/components/documents/viewer/document-insights-view.stories.tsxComponent+36-0
src/components/documents/viewer/document-insights-view.tsxComponent+174-0
src/components/documents/viewer/document-original-pane.tsxComponent+72-19
src/components/documents/viewer/document-pdf-canvas.tsxComponent+8-1
src/components/documents/viewer/document-permalink-shell.stories.tsxComponent+30-2
src/components/documents/viewer/document-permalink-shell.tsxComponent+77-23
src/components/documents/viewer/document-reading-surface.tsxComponent+152-0
src/components/documents/viewer/document-reclassify-dialog.stories.tsxComponent+36-0
src/components/documents/viewer/document-reclassify-dialog.tsxComponent+136-0
src/components/documents/viewer/document-viewer-header.tsxComponent+7-1
src/components/documents/viewer/insights-fixtures.tsComponent+147-0
src/components/documents/viewer/insights-presentation.tsComponent+97-0
src/components/documents/viewer/insights-types.tsComponent+51-0
src/components/documents/viewer/use-document-annotations.tsComponent+190-0
src/components/documents/viewer/use-document-reclassify.tsComponent+57-0
src/gen/client/appGetDocumentInsightBrief.tsGenerated contract+67-0
src/gen/client/index.tsGenerated contract+1-0
src/gen/hooks/index.tsGenerated contract+8-0
src/gen/hooks/useAppGetDocumentInsightBrief.tsGenerated contract+131-0
src/gen/hooks/useAppGetDocumentInsightBriefSuspense.tsGenerated contract+134-0
src/gen/index.tsGenerated contract+48-0
src/gen/schemas/authorityCited.jsonGenerated contract+111-0
src/gen/schemas/builtFrom.jsonGenerated contract+19-0
src/gen/schemas/documentInsightBrief.jsonGenerated contract+642-0
src/gen/schemas/enrichmentStamp.jsonGenerated contract+36-0
src/gen/schemas/insightPin.jsonGenerated contract+96-0
src/gen/schemas/positionAdmission.jsonGenerated contract+111-0
src/gen/schemas/punchCard.jsonGenerated contract+217-0
src/gen/schemas/silence.jsonGenerated contract+111-0
src/gen/types/AppGetDocumentInsightBrief.tsGenerated contract+70-0
src/gen/types/AuthorityCited.tsGenerated contract+24-0
src/gen/types/BuiltFrom.tsGenerated contract+18-0
src/gen/types/DocumentInsightBrief.tsGenerated contract+68-0
src/gen/types/EnrichmentStamp.tsGenerated contract+31-0
src/gen/types/InsightPin.tsGenerated contract+30-0
src/gen/types/PositionAdmission.tsGenerated contract+24-0
src/gen/types/PunchCard.tsGenerated contract+34-0
src/gen/types/Silence.tsGenerated contract+24-0
src/gen/types/index.tsGenerated contract+20-0
src/gen/zod/appGetDocumentInsightBriefSchema.tsGenerated contract+88-0
src/gen/zod/authorityCitedSchema.tsGenerated contract+29-0
src/gen/zod/builtFromSchema.tsGenerated contract+22-0
src/gen/zod/documentInsightBriefSchema.tsGenerated contract+90-0
src/gen/zod/enrichmentStampSchema.tsGenerated contract+27-0
src/gen/zod/index.tsGenerated contract+19-0
src/gen/zod/insightPinSchema.tsGenerated contract+36-0
src/gen/zod/positionAdmissionSchema.tsGenerated contract+27-0
src/gen/zod/punchCardSchema.tsGenerated contract+42-0
src/gen/zod/silenceSchema.tsGenerated contract+27-0
src/lib/documents/annotation-resolve-helper.tsLibrary+55-0
src/lib/documents/gateway.tsLibrary+144-0
src/lib/documents/reclassify-route-helper.tsLibrary+84-0
src/lib/kubb-client.tsLibrary+12-0
src/lib/surface-registry/route-registry.tsLibrary+12-2

Story-2168: The Document Page v2 — Original · Insights, live

Every uploaded document becomes a conversation. This story ships the Document Page per the Claude Design contract (cd-document-view-v2.dc.html) and the desk RFD: a route-per-mode page whose Original view is untouched paper you talk to (select → Counsel Control Bar → note, wired live to the span-anchored notes substrate), whose Insights view is "a briefing, not a brief" (THE READ + accordions), and whose header carries the document's identity + a Details card + Reclassify. Text is demoted to a machine-copy utility link.

The one load-bearing discovery (founder-ratified path)

The brief assumed the Original anchored notes to an existing document_pages blocks read path with normalized bbox. That path does not exist — the Text route reads one derived/text.txt blob (no blocks, no bbox, no char/page map; CE-17 unmirrored), and the live PDF rendered its text layer off. Founder ratified the honest path: turn the pdfjs text layer on, anchor each note by quote (byte-exact V-CITE) + pageNumber (blockIndex = null = whole page), render page-level gutter marks v1, and design the overlay/gutter/margin components to upgrade to per-¶ when the blocks/bbox endpoint lands (an optional blocks prop; absent = page-level). The blocks read-path story is filed separately on pramaan-functions.

Design states → what shipped

CD stateShipped
4a/4b Header identity stripLive header (serif title, type/side/REGISTERED chips, uploaded·size meta, Download · Copy permalink · Details).
4d Details cardDocumentDetailsSheet — right-edge sheet: classification (type/side/home/tags), provenance (original file/uploaded), integrity (sha256 + copy, size, duplicate-of, legal hold, status). Real DTO data; missing field → "—".
4e ReclassifyDocumentReclassifyDialog — two-question (whose · where), wired live to the new PATCH home / declared-side proxies; on save re-reads (router refresh).
1a Original at restClean paper — pdfjs canvas, left gutter lane, right margin. Nothing boxed at rest.
1b Paragraph hover / selectionText selection raises the DocumentCounselBar (Explain · What-this-means dimmed "wired next"; Note · Copy ¶-link live). No "Cite".
1c/2b Margin notes + composingSelect → Note → inline composer in the margin; posts to the live annotations API. Card appears + page gets a gutter ● the instant you commit (optimistic).
1a gutter ● indexDocumentGutterMark — page-level ● note mark with count (◐ insight / ⚠ contradiction kinds ready for when those land).
3a Insights — THE READDocumentInsightsView — headline + punch cards (one quiet pin each) + accordions (facts/positions/authorities/silences/notes), closed by default, freshness stamp.
3a Honest pendingThe live Insights route renders the honest pending state — "Read pending, this document hasn't been read against the matter yet" — because Station 4 has not processed these docs. Never fabricated.
1f Pin-click landingA punch-card / accordion pin deep-links to Original ?page=N; the pane seeds that page on arrival.
TabsOriginal | Insights are sibling routes (route-per-mode); Text is a machine-copy utility link. pdfjs loads only on Original.

Live wiring (no fixtures on the shipped path)

Storybook (verify here)

Verification

Live-data seams (honest, reported on the issue): (1) Insights content — no read/facts-derived endpoint exists (Station 4). The route renders the pending state; the full layout is fixture-driven in Storybook and lights up when the read-brief endpoint lands. (2) Per-¶ fidelity — the gutter/margin are page-level until the document_pages blocks (text + bbox + kind per page) read path ships; the components take an optional blocks prop to upgrade with zero call-site changes. (3) Explain / What-this-means route to the matter agent — present but dimmed ("wired next") pending the Wave B app sender. The on-staging check is a real note on the Order_S.17 doc (3ee1dc28, matter 13): select → Note → it persists and reloads, and the page gets a gutter ●.