Corpus Selection
Frontend: Selected Corpus and Document State (with deep links)¶
This document explains how URL deep linking and selection state work for corpuses and documents. It covers the router routes, the global URL→state synchronizer, where we push navigation, and how components fetch and hydrate data.
Terminology¶
- Selected corpus: The corpus the user is viewing or interacting with (e.g., its dashboard, documents, annotations, analyses, extracts, or settings).
 - Selected document: A single document the user has opened for viewing or actions.
 - Reactive vars: Apollo client-side reactive variables defined in 
frontend/src/graphql/cache(e.g.,openedCorpus,openedDocument, and filter/search vars). 
Selected Corpus (Router-based in Corpuses.tsx)¶
 The selected corpus is synchronized with the URL and reactive vars. The URL is the source of truth, and deep-links are supported.
- Route param: 
:corpusId(viauseParams) indicates the intended selected corpus. - Two-way sync:
 - Route → reactive var: When 
corpusIdchanges, the app setsopenedCorpus(...)to match (from the list if present, or via a lazy fetch). - Reactive var → route: When 
openedCorpuschanges, the app updates the URL to/corpuses/:corpusId(or/corpusesif cleared), guarding against flicker during initial loading. - Deep-link hydration: If the selected corpus is not in the current paginated list, the app lazily fetches the corpus metadata by id and then hydrates 
openedCorpus. - Dependent data refresh:
 - When 
openedCorpusupdates, the app refreshes: corpus metadata viaGET_CORPUS_METADATAand corpus stats viaGET_CORPUS_STATS(polling every 5 seconds). - Search/query view state remains local UI state and is not reflected in the URL.
 - Auth guard: On login/logout, the app refetches corpuses, refreshes metadata if authenticated, and clears selection and navigates to 
/corpuseson logout. 
Key flows in frontend/src/views/Corpuses.tsx:
- Route 
corpusId→ match in fetched list →openedCorpus(match); otherwise trigger lazy fetch by id. - On lazy fetch completion → 
openedCorpus(corpusByIdData.corpus). - On 
opened_corpuschange → update URL and refresh metadata/stats; clear route if selection is removed after loading. 
Result: The selected corpus is fully deep-linkable and shareable via URL, and switching corpuses drives the rest of the UI and data fetching.
Selected Document (Router-based KB + reactive filters in lists)¶
We support deep links that open the Knowledge Base for a document with or without a corpus context. The global documents list and filters remain driven by reactive vars.
- Routes
 /corpus/:corpusId/document/:documentId→ opens KB with corpus context./documents/:documentId→ opens KB in corpus-less mode.- Both support 
?ann=id1,id2to pre-select annotations. - Lists and filters
 - The global list (
views/Documents.tsx) uses reactive vars for filtering:filterToCorpus,filterToLabelId,filterToLabelsetId,documentSearchTerm. - Clicking a document navigates to the appropriate KB route (see State → URL navigation below).
 
Routing overview¶
/corpuses→ Corpus list and dashboard navigation (views/Corpuses.tsx)./corpuses/:corpusIdor/corpus/:corpusId→ Selected corpus views (same component)./corpus/:corpusId/document/:documentId→ KB with corpus (components/routes/DocumentKBRoute.tsx)./documents→ Global documents list (views/Documents.tsx)./documents/:documentId→ KB without corpus (components/routes/DocumentKBDocRoute.tsx).- Optional query 
?ann=id1,id2,...on both document routes seeds selected annotation ids. 
URL → state synchronization¶
- Implemented centrally in 
hooks/RouteStateSync.tsand installed inApp.tsx. - On route changes, it updates reactive vars:
 /corpuses/:corpusIdor/corpus/:corpusId→openedCorpus({ id })./corpus/:corpusId/document/:documentId→openedCorpus({ id }),openedDocument({ id })./documents/:documentId→openedDocument({ id }).?ann=→selectedAnnotationIds([...]).- Navigating away clears selections where appropriate.
 
Note: This hook is one-way (URL → state) to avoid feedback loops. Components push navigation explicitly.
State → URL navigation¶
- Corpuses (
views/Corpuses.tsx) - Ensures URL reflects 
opened_corpus; fetches metadata by id on deep link (GET_CORPUS_METADATA) and polls stats (GET_CORPUS_STATS). - Documents
 CorpusDocumentCards.tsxhandles click navigation:- If a corpus is active → 
/corpus/:corpusId/document/:documentId. - Otherwise → 
/documents/:documentId. 
- If a corpus is active → 
 - The 
DocumentItemcontext menu “Open Knowledge Base” follows the same rules. 
Deep-link hydration and data fetching¶
- KB with corpus: 
DocumentKBRouterendersDocumentKnowledgeBasewithdocumentIdandcorpusId, which queriesGET_DOCUMENT_KNOWLEDGE_AND_ANNOTATIONSand hydrates document, annotations, relationships, and corpus labels. - KB without corpus: 
DocumentKBDocRouterendersDocumentKnowledgeBasewith justdocumentId, which queriesGET_DOCUMENT_ONLYand loads the viewer with editing disabled and an “Add to Corpus” ribbon. - Both pass 
onClose={() => navigate(-1)}so closing returns to the previous route, andDocumentKnowledgeBaseclearsopenedDocument(null)on unmount. 
Documents list and filters¶
views/Documents.tsxbuildsGET_DOCUMENTSvariables from reactive vars (filterToCorpus,filterToLabelsetId,filterToLabelId,documentSearchTerm) and refetches on changes.- While any document has 
backendLock, a timer refetches periodically to surface progress. 
Quick reference¶
- Routes: 
/corpuses,/corpuses/:corpusId(or/corpus/:corpusId),/corpus/:corpusId/document/:documentId,/documents,/documents/:documentId, optional?ann=.... - URL → state: 
useRouteStateSyncupdatesopenedCorpus,openedDocument,selectedAnnotationIds. - State → URL: components navigate explicitly (corpus selection; document clicks/context menu).
 - Deep-link hydration: corpuses 
GET_CORPUS_METADATA; documents with corpusGET_DOCUMENT_KNOWLEDGE_AND_ANNOTATIONS; documents without corpusGET_DOCUMENT_ONLY(usescorpusSet). 
Quick reference¶
- Selected corpus: URL param 
:corpusId↔openedCorpuswith lazy hydration; dependent metadata/stats refreshed and polled. - Selected document: Full deep-linking support via routes 
/corpus/:corpusId/document/:documentIdand/documents/:documentIdwith optional?ann=id1,id2annotation selection. - Document filters: 
filterToCorpus,filterToLabelId,filterToLabelsetId, anddocumentSearchTermfeedGET_DOCUMENTSvariables.