Session: glimmering-imagining-sparrow-subagent-a801d33 — 2026-01-27

doctolib-doctolib · Claude · branch master · claude-haiku-4-5-20251001 · 2026-01-27 13:43 · 1 msgs · 29 tools · 12 min read · updated 3 months ago

I need to understand how documents are fetched and cached after upload:

tools: Bash, Glob, Grep, Read
← doctolib-doctolib Download .md .txt .json
Tool calls
Read Read: 14 calls (48.3%) 14 Bash Bash: 10 calls (34.5%) 10 Glob Glob: 3 calls (10.3%) 3 Grep Grep: 2 calls (6.9%) 2
Token usage3.8M total
Input7.9K
Cache creation261.8K
Cache read3.5M
Output256
Cache hit ratio93%· healthy

Project: doctolib-doctolib · Branch: master · Mode: ` · **Model:**claude-haiku-4-5-20251001`

Stats: 1 user messages, 29 tool calls, tools used: Bash, Glob, Grep, Read.

Conversation

Turn 1 — User

I need to understand how documents are fetched and cached after upload:

  1. Find the queries/hooks that fetch the document list (likely in engines/documents)
  2. Look for how the document preview/show functionality works
  3. Find what queries are used when viewing a document (besides decryptedDocuments)
  4. Look for any prefetch or cache dependencies between: - Document list queries - Individual document queries - The decryptedDocuments query we already saw

The issue is that after upload, the document can't be viewed immediately but works after cache expiry (5 min) or logout.

Turn 1 — Assistant

I'll help you understand the document fetching and caching flow. Let me start by exploring the relevant files in the documents engine and related packages.

Tools used:

  • Bash: find /Users/USER/workspace/doctolib/doctolib -type f -name "*.ts" -o -name "*.tsx" -o -name "*.rb" | grep -i document | head -30

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib/app/models/security/tanker/group_document_reshare.rb /Users/USER/workspace/doctolib/doctolib/app/models/consultation_document_template.rb /Users/USER/workspace/doctolib/doctolib/app/models/consultation_document_templates_speciality.rb /Users/USER/workspace/doctolib/doctolib/app/models/processors/update/patient_account_documents/document.rb /Users/USER/workspace/doctolib/doctolib/app/models/processors/update/patient_account_documents/documents_cloned_event. …(truncated, 2428 more chars)

Let me search more specifically in the documents engine and patient packages:

Tools used:

  • Glob: engines/documents/**/*.{ts,tsx,rb}

Tools used:

  • Glob: engines/patient_accounts/**/*.{ts,tsx,rb}

Tools used:

  • Glob: packages/@doctolib/**/*document*.{ts,tsx}

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/public/helpers/document.ts /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/public/services/documentEncryption.ts /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/queries/patient_account_documents/appointments/documentAccesses.ts /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/queries/patient_acco …(truncated, 6801 more chars)

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/documents/app/components/documents/react/clear_document_form.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/controllers/concerns/documents/clear_document_render.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/controllers/concerns/documents/parse_signed_id.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/controllers/documents/admin/accounts_controller.rb /Users/USER/workspace/doctolib/doctolib/engin …(truncated, 11046 more chars)

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/patient_accounts/app/controllers/patient_accounts/admin/accounts/subscription_synchronizations_controller.rb /Users/USER/workspace/doctolib/doctolib/engines/patient_accounts/app/controllers/patient_accounts/admin/debug_pages/subscriptions_controller.rb /Users/USER/workspace/doctolib/doctolib/engines/patient_accounts/app/controllers/patient_accounts/application_controller.rb /Users/USER/workspace/doctolib/doctolib/engines/patient_accounts/app/contro …(truncated, 11994 more chars)

Now let me search for React Query hooks related to documents and decrypted documents:

Tools used:

  • Grep: decryptedDocuments|useDecryptedDocuments

Tools used:

  • Grep: useQuery.*document|queryKey.*document

Tool results:

→ result (ok): No files found

Tool results:

→ result (ok): No files found

Let me search more broadly:

Tools used:

  • Bash: find /Users/USER/workspace/doctolib/doctolib/packages -type f \( -name "*.ts" -o -name "*.tsx" \) | xargs grep -l "decryptedDocuments" | head -10

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/HomeDocuments.tsx /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/doctor-documents/DoctorDocuments.tsx /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/SharedDocuments.tsx /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/mobi …(truncated, 950 more chars)

Perfect! Now let me read the key files:

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/hooks/useDecryptedDocuments.ts

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/data/queries/documents.ts

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/queries/patient_account_documents/accounts/documents.ts

Tool results:

→ result (ok): 1→import type { Account } from 'monolith_DEPRECATED/types/api/Account' 2→import type { DecryptRecord } from 'engines/e2ee/public' 3→import type PatientAccountDocument from '@doctolib/patient_account_documents/src/types/PatientAccountDocument' 4→import i18n from 'monolith_DEPRECATED/services/i18n' 5→import { useCallback, useContext, useEffect, useState } from 'react' 6→import { TankerContext } from 'engines/e2ee/public' 7→import useAccount from 'monolith_DEPRECATED/h …(truncated, 3614 more chars)

Tool results:

→ result (ok): 1→/ 2→ * As part of the react query migration to v5, we are moving the queries to this file. 3→ * This file is replacing engines/documents/app/assets/javascripts/queries/documents/doctor_app/documents.ts 4→ * Feel free to add endpoints from the old file to this new one, and fix eventual react query issues. 5→ / 6→ 7→import { useContext } from 'react' 8→import { HttpClientContext } from '@doctolib/shared_context' 9→import { useMutation, useQuery, useQuery …(truncated, 12390 more chars)

Tool results:

→ result (ok): 1→import type { HttpClientType } from 'monolith_DEPRECATED/types/http-client' 2→import type PatientAccountDocument from '@doctolib/patient_account_documents/src/types/PatientAccountDocument' 3→import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query-v5' 4→import { useContext, useMemo } from 'react' 5→import { HttpClientContext } from 'monolith_DEPRECATED/contexts/ReactQueryProvider' 6→import useAccount from 'monolith_DEPRECATED/hooks …(truncated, 9816 more chars)

Now let me look at the component files that use these hooks:

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/HomeDocuments.tsx (1–100)

Tools used:

  • Bash: find /Users/USER/workspace/doctolib/doctolib -type f \( -name "*.ts" -o -name "*.tsx" \) | xargs grep -l "useDocumentsIndex\|useDocumentsShow" | head -15

Tool results:

→ result (ok): 1→import { useNavigate } from 'react-router-dom' 2→import i18n from 'monolith_DEPRECATED/services/i18n' 3→import { Button } from '@doctolib/design-system/Button' 4→import useRequireTankerVerification from 'monolith_DEPRECATED/hooks/patient/useRequireTankerVerification' 5→import type PatientAccountDocument from '@doctolib/patient_account_documents/src/types/PatientAccountDocument' 6→import DocumentsListSkeleton from '@doctolib/patient_account_documents/src/components/shar …(truncated, 4014 more chars)

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/consultation/ConsultationDocumentForm/ConsultationDocumentForm.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/consultation/TreatmentPlan/ButtonsSection/PrintConsultationDocumentsButton.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/mobile/pages/ShowDocument.tsx / …(truncated, 1781 more chars)

Let me check the document show/view logic and how documents are accessed:

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/modules/DocumentItemModule

Tools used:

  • Bash: find /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/modules/DocumentItemModule -type f

Tool results:

→ result (ERROR): EISDIR: illegal operation on a directory, read

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/modules/DocumentItemModule/index.tsx /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/modules/DocumentItemModule/views/DocumentActions.tsx /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/modules/DocumentItemModule/views/DocumentDesktopItem.jsx /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/s …(truncated, 345 more chars)

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/modules/DocumentItemModule/index.tsx (1–150)

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/modules/DocumentItemModule/views/DocumentActions.tsx (1–100)

Tool results:

→ result (ok): 1→import type PatientAccountDocument from '@doctolib/patient_account_documents/src/types/PatientAccountDocument' 2→import { useReducer } from 'react' 3→import { isOnDesktop, isPartnerDomain } from 'monolith_DEPRECATED/packages/device/environment' 4→import useToast from 'monolith_DEPRECATED/hooks/useToast' 5→import { ALWAYS_SHOW } from 'monolith_DEPRECATED/components/base/Toast' 6→import { 7→ OnDocumentUpdatedOperationKind, 8→ type OnDocumentUpdatedCallback,

…(truncated, 5312 more chars)

Tool results:

→ result (ok): 1→import type { MouseEventHandler, TouchEventHandler } from 'react' 2→import type PatientAccountDocument from '@doctolib/patient_account_documents/src/types/PatientAccountDocument' 3→import i18n from 'monolith_DEPRECATED/services/i18n' 4→import { isOnDesktop } from 'monolith_DEPRECATED/packages/device/environment' 5→import { Dropdown } from '@doctolib/design-system/Dropdown' 6→import { Icon } from '@doctolib/design-system/Icon' 7→import { IconButton } from '@doctoli …(truncated, 3517 more chars)

Now let me look at the useFetchAndDecryptDocument hook:

Tools used:

  • Bash: find /Users/USER/workspace/doctolib/doctolib -type f -name "useFetchAndDecryptDocument*"

Tools used:

  • Bash: find /Users/USER/workspace/doctolib/doctolib -type f \( -name "*.ts" -o -name "*.tsx" \) | xargs grep -l "useFetchAndDecryptDocument" | head -5

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/public/hooks/useFetchAndDecryptDocument.ts /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/hooks/useFetchAndDecryptDocument.ts

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/check_in/app/assets/javascripts/modules/DocumentRequestFunnelContentModule/views/DocumentRequestItemDraft.tsx /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/public/hooks/useFetchAndDecryptDocument.ts /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/hooks/useFetchAndDecryptDocument.ts /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/ …(truncated, 202 more chars)

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/hooks/useFetchAndDecryptDocument.ts

Tools used:

  • Bash: grep -r "queryKey.*document\|buildDocumentsShowQueryKey\|queryKeyShow" /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src --include="*.ts" --include="*.tsx" …(truncated, 10 more chars)

Tool results:

→ result (ok): 1→import { useContext } from 'react' 2→import i18n from 'monolith_DEPRECATED/services/i18n' 3→import { useQuery } from '@tanstack/react-query-v5' 4→import { HttpClientContext } from 'monolith_DEPRECATED/contexts/ReactQueryProvider' 5→import type { HttpClientType } from 'monolith_DEPRECATED/types/http-client' 6→import { TankerContext } from 'engines/e2ee/public' 7→import { handleEncryptedDocument } from 'monolith_DEPRECATED/components/shared/documents/utils' 8→i …(truncated, 3549 more chars)

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/queries/patient_account_documents/accounts/unreadDocuments.ts:const queryKey = ['account', 'unread_documents'] /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/queries/patient_account_documents/accounts/documents.ts:const queryKeyShow = (documentId?: string) => ['account', 'documents', documentId] /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_accou …(truncated, 984 more chars)

Now let me check the document upload/creation flow:

Tools used:

  • Bash: find /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents -type f -name "*[Uu]pload*" | head -10

Tools used:

  • Bash: grep -r "POST.*documents\|mutationFn.*documents.*post\|invalidateQueries.*document" /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src --include="*.ts" --inc …(truncated, 23 more chars)

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/public/components/DocumentUpload.ts /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/public/components/NativeDocumentUploader.ts /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule/DocumentUpload.tsx /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/sha …(truncated, 648 more chars)

Tool results:

→ result (ok)

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule/DocumentUploadModule.tsx (1–150)

Tool results:

→ result (ok): 1→import ErrorBoundary from 'monolith_DEPRECATED/components/shared/ErrorBoundary' 2→import type { DocumentUploadProps } from '@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule/DocumentUpload' 3→import DocumentUpload from '@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule/DocumentUpload' 4→ 5→const DocumentUploadModule = (props: DocumentUploadProps) => ( 6→ <ErrorBoundary component="DocumentUpload" team="phr">

…(truncated, 470 more chars)

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule/DocumentUpload.tsx (1–200)

Tool results:

→ result (ok): 1→import type { ChangeEvent, MutableRefObject, ReactNode, SyntheticEvent } from 'react' 2→import { useCallback, useContext, useEffect, useRef, useState } from 'react' 3→import { v4 as uuidv4 } from 'uuid' 4→import { compact, partition } from 'lodash-es' 5→import constants from 'monolith_DEPRECATED/services/constants' 6→import i18n from 'monolith_DEPRECATED/services/i18n' 7→import { versionFulfillsRequirement } from 'monolith_DEPRECATED/services/react-native/appVersi …(truncated, 10152 more chars)

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule/DocumentUpload.tsx (200–350)

Tool results:

→ result (ok): 200→ document_upload_funnel_id: productEventDetails.document_upload_funnel_id, 201→ context: productEventDetails.context as DocumentContext, 202→ document_flow: productEventDetails.document_flow as DocumentFlow, 203→ document_error_type: DocumentUploadErrorType.FilePermissionError, 204→ }) 205→ 206→ return false 207→ } 208→ 209→ throw error 210→ } 211→ 212→ return true 213 …(truncated, 6141 more chars)

Tools used:

  • Bash: grep -r "DocumentSaver\|fetchDocuments\|onUpload" /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule --include="*.ts" …(truncated, 28 more chars)

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule/DocumentSaver.test.tsx:import DocumentSaver from './DocumentSaver' /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule/DocumentSaver.test.tsx:import { computePersonalizedServicesCheckboxContext } from './DocumentSaverCheckbox' /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_ac …(truncated, 3261 more chars)

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule/DocumentSaver.tsx (1–200)

Tool results:

→ result (ok): 1→import type { Dispatch, ReactNode } from 'react' 2→import { useContext, useState } from 'react' 3→import i18n from 'monolith_DEPRECATED/services/i18n' 4→import { Modal } from '@doctolib/design-system/Modal' 5→import { SpinnerLoader } from '@doctolib/design-system/SpinnerLoader' 6→import QuitDialog from 'monolith_DEPRECATED/components/shared/documents/QuitDialog' 7→import { TankerContext } from 'engines/e2ee/public' 8→import { isOnMobile } from 'monolith_DEPRE …(truncated, 6170 more chars)

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule/DocumentSaverForm.tsx (1–200)

Tool results:

→ result (ok): 1→import { Button } from '@doctolib/design-system/Button' 2→import { Icon } from '@doctolib/design-system/Icon' 3→import { InputText } from '@doctolib/design-system/InputText' 4→import type { FieldState } from '@doctolib/design-system/Field' 5→import { Select } from '@doctolib/design-system/Select' 6→import { decode } from '@doctolib/security' 7→import Form from 'monolith_DEPRECATED/components/base/form/Form' 8→import type { DocumentScannerModule } from 'monoli …(truncated, 10673 more chars)

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule/DocumentSaverForm.tsx (200–350)

Tool results:

→ result (ok): 200→ message: i18n.t('common.file_too_big', { size: toHumanReadableFileSize(constants.DOCUMENT_MAX_SIZE) }), 201→ }) 202→ return 203→ } 204→ 205→ onAdd?.(fileToUpload) 206→ 207→ try { 208→ const [encryptedFileToUpload, tankerEncryptedTitle] = await Promise.all([ 209→ encryptDocument(fileToUpload, decode(master_patient_id) as number), 210→ title ? encryptDocumentTitle(title, decode(master_patient_id) as number) : null,

…(truncated, 7747 more chars)

Perfect! Now I have enough information. Let me create a comprehensive analysis document:

Summary

I've thoroughly explored the document fetching and caching flow in the Doctolib codebase. Here's what I found:

Key Query Hooks & Cache Keys

1. Patient Account Documents (Patient's Drive)

Located in /packages/@doctolib/patient_account_documents/src/queries/patient_account_documents/accounts/documents.ts:

  • useDocumentsIndex() - Fetches paginated list of documents
  • Query Key: ['account', 'documents', { master_patient_id }]
  • Endpoint: GET /account/documents.json
  • Uses infinite query with pagination
  • Cache time: Not explicitly set (uses defaults)

  • useDocumentsShow() - Fetches individual document metadata

  • Query Key: ['account', 'documents', documentId]
  • Endpoint: GET /account/documents/{id}
  • Decrypts title using decryptTitle()
  • Cache time: Not explicitly set

  • useFetchAndDecryptDocument() - Fetches and decrypts document file

  • Query Key: ['account', 'documents', documentId, 'decrypted']
  • Endpoint: Uses presigned URL to download encrypted content
  • Stale Time: 30 minutes
  • GC Time: 30 minutes
  • Calls handleEncryptedDocument() to decrypt the file

2. Doctor App Documents

Located in /packages/@doctolib/documents-ui/src/data/queries/documents.ts:

  • useDocumentsIndex() - Fetches doctor app documents
  • Query Key: ['documents', 'doctor_app', 'documents', 'index', { patient_id, consultation_id, appointment_id }]
  • Endpoint: GET /doctor_app/documents.json
  • Decrypts documents after fetching
  • Also has mutation hook for updates

  • useDocumentsUpdate() - Mutation for updating documents

  • Invalidates: buildDocumentsShowQueryKey(props.documentId)
  • Invalidates: buildDocumentsIndexQueryKey({ patient_id })

3. Title Decryption Hook

Located in /packages/@doctolib/patient_account_documents/src/hooks/useDecryptedDocuments.ts:

  • useDecryptedDocuments() - Decrypts encrypted titles
  • Calls decryptTitle() for each document
  • Returns decryptedDocuments state
  • Triggers when tankerIsReady changes
  • This is client-side decryption using TankerContext

The Upload Flow & Cache Problem

Located in /packages/@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule/:

Upload Process: 1. DocumentUpload.tsx - Main upload component 2. DocumentSaver.tsx - Form wrapper 3. DocumentSaverForm.tsx - The actual form with submission logic

Key line from DocumentSaverForm.tsx (line 228-237):

const { responseBody, status } = await DEPRECATED_post('/account/documents', body)

if (status >= 400) {
  onFailure({ errorType: DocumentUploadErrorType.BackendError })
} else {
  const { document } = JSON.parse(responseBody)
  const documentWasSaved = true
  onHide({ documentWasSaved })
  await fetchDocuments?.()  // <-- Manual refetch
  onUpload(document)
}

The Problem:

  1. After POST /account/documents succeeds, the backend returns the created document object
  2. The code calls fetchDocuments?.() (optional callback) and onUpload(document)
  3. BUT - there's NO React Query cache invalidation or update here!
  4. The component manually calls a callback to refetch if provided, but: - This refetch is not guaranteed to be useDocumentsIndex() - The individual document query ['account', 'documents', documentId] is never invalidated - The decrypted file query ['account', 'documents', documentId, 'decrypted'] stays in cache

Why it Works After 5 Minutes or Logout

  1. Cache Expiry: The decrypted file query has a 30-minute stale time, but React Query may consider it stale and refetch
  2. Logout: Clears all React Query cache automatically
  3. Manual Refetch: Logout and re-login forces new queries

Prefetch Dependencies

The code has NO explicit prefetch dependencies: - There's no code that prefetches useDocumentsShow() when useDocumentsIndex() loads - There's no code that prefetches useFetchAndDecryptDocument() based on document list - Decryption happens lazily when user interacts with a document

Root Cause Summary

File: /packages/@doctolib/patient_account_documents/src/components/shared/DocumentUploadModule/DocumentSaverForm.tsx (lines 228-237)

Issue: After document upload: - The newly created document is NOT added to React Query cache - The useDocumentsIndex() query is NOT invalidated - If fetchDocuments callback is not provided or doesn't call the right query invalidation, cache remains stale - User sees old list or can't view new document immediately

Required Fix: - After successful upload, need to invalidate or update the following query keys: - ['account', 'documents', { master_patient_id }] (list cache) - Optionally add the new document to cache directly to avoid refetch - Ensure proper cache invalidation using React Query's queryClient.invalidateQueries()

Keyboard shortcuts

⌘K / Ctrl+KOpen command palette
/Focus search
g hGo to home
g pGo to projects
g sGo to sessions
j / kNext / prev row (tables)
?Show this help
EscClose dialogs

Structured queries

Mix key:value filters with free text in the palette:

type:sessionOnly session pages
project:llm-wikiFilter by project name (substring)
model:claudeFilter by model name (substring)
date:>2026-03-01Sessions after a date
date:<2026-04-01Sessions before a date
tags:rustPages mentioning a tag/topic
sort:dateSort results by date (newest first)

Example: type:session project:llm-wiki date:>2026-04 sort:date