Project: doctolib-doctolib · Branch: master · Mode: · Model: claude-haiku-4-5-20251001 Stats: 1 user messages, 38 tool calls, tools used: Glob, Grep, Bash, Read. Conversation Turn 1 — User Search for the frontend code that handles document uploads and decides whether to use v1 (/doctor_app/documents) or v2 (/doctor_app/v2/documents) endpoints. Focus on: 1. Document upload hooks or API calls in TypeScript/React 2. Any code that switches between v1 and v2 endpoints based on feature flags 3. The document import workflow, particularly around "dokumente anzeigen" (show documents) functionality4. Any code that handles document retrieval and display after upload Look in: - React components for document imports/uploads - TypeScript packages related to documents - API client code that makes requests to document endpoints Turn 1 — Assistant I'll search for the document upload code that handles switching between v1 and v2 endpoints. Let me start with a comprehensive search across the codebase. Tools used: - Glob: /packages//.ts Tools used: - Glob: /app//document Tools used: - Grep: doctor_app/documents|doctor_app/v2/documents Tools used: - Grep: dokumente anzeigen|show documents Tool results: → result (ok): No files found Tool results: → result (ok): No files found Tool results: → result (ok): No files found Tool results: → result (ok): No files found Let me try more specific searches for document-related code: Tools used: - Grep: upload.document|document.upload Tools used: - Grep: /doctor_app/ Tool results: → result (ok): No files found Tools used: - Grep: featureFlag|feature.flag|Feature Tool results: → result (ok): No files found Tool results: → result (ok): No files found Let me check the directory structure to better understand the codebase layout: Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f -name ".ts" -o -name ".tsx" | head -20 Tools used: - Bash: ls -la /Users/USER/workspace/doctolib/doctolib/ Tool results: → result (ok): drwxr-xr-x clertonra staff 4.3 KB Mon Feb 2 14:45:13 2026 . drwxr-xr-x clertonra staff 736 B Fri Jan 30 15:13:45 2026 .. .rw-r--r-- clertonra staff 40 B Mon Feb 2 14:45:13 2026 .billeo-version .rw-r--r-- clertonra staff 540 B Wed Dec 17 16:18:17 2025 .browserslistrc .rw-r--r-- clertonra staff 50 B Wed Dec 17 16:18:17 2025 .bundle-option .rw-r--r-- clertonra staff 33 B Wed Dec 17 16:18:17 2025 .byebugrc drwxr-xr-x clertonra staff 736 B Wed Jan 28 11:11:47 2026 .cherry .rw-r--r-- clerto …(truncated, 9433 more chars) Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/entrypoints-content/patient-navbar.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/entrypoints-content/front-desk.ts /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/entrypoints-content/doctor-desktop-providers.mock.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/entrypoints-content/doctor-desktop.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/entrypoints-content …(truncated, 1646 more chars) Now let me search for document-related code more specifically: Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f \( -name ".ts" -o -name ".tsx" \) | xargs grep -l "doctor_app" | head -20 Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f \( -name ".ts" -o -name ".tsx" \) | xargs grep -l "document" | grep -E "(upload|import)" | head -20 Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f \( -name ".ts" -o -name ".tsx" \) -path "/doctor" | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/entrypoints-content/doctor-desktop-providers.mock.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/entrypoints-content/doctor-desktop.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/entrypoints-content/doctor-billing-mobile-offline.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/sections/doctor/mobile/DocumentEditSection/useDocumentEditSectionNavigation.ts /Users/USER/workspace/ …(truncated, 1997 more chars) Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/sections/doctor/mobile/DocumentEditSection/useDocumentEditSectionController.ts /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/types/doctor/api/Appointment.ts /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/types/doctor/api/BaseAppointment.ts /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/types/doctor/api/Patient.ts /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/types/doct …(truncated, 1852 more chars) Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/configuration/modules/components/ehr_imports/ReadOnlyEhrImport.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/consultation/UploadedDocument/uploadedDocumentHelper.ts /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/modules/doctor/mobile/document-upload/ProgressBarAndActionModule/ProgressBarAndActionModule.tsx /Users/U …(truncated, 2382 more chars) Great! I found document-related code. Let me search for the DocumentImportContext and API calls: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/contexts/doctor/desktop/DocumentImportContext.tsx Tool results: → result (ok): 1→import type { FunctionComponent, ReactNode } from 'react' 2→import { useCallback, useEffect, useMemo, useRef, useState } from 'react' 3→import { v4 as uuidv4 } from 'uuid' 4→import { isEmpty } from 'lodash-es' 5→// TODO - CAT : Fix useQueryClient usage in TT-20637 6→// eslint-disable-next-line doctolib-custom-rules/react-query/react-query-monolith-conventions,doctolib-custom-rules/react-query/restricted-imports 7→import { useQueryClient } from '@tanstack/react-que …(truncated, 27638 more chars) Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f \( -name ".ts" -o -name ".tsx" \) | xargs grep -l "dokumente anzeigen\|show documents" 2>/dev/null | head -10 Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f \( -name ".ts" -o -name ".tsx" \) -path "doctor" | xargs grep -l "/documents" 2>/dev/null | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/sections/doctor/mobile/DocumentEditSection/useDocumentEditSectionNavigation.ts /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/sections/doctor/mobile/DocumentEditSection/useDocumentEditSectionController.ts /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/sections/doctor/mobile/DocumentsUploadSection/useDocumentsUploadSectionNavigation.ts /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/types …(truncated, 2291 more chars) Tool results: → result (ok) Great! I found the DocumentImportContext. Now let me search for the documents API queries to find where v1/v2 endpoint switching occurs: Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -path "documents" -name ".ts" | grep -E "query|api" | head -30 Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/modules/doctor/mobile/document-upload Tool results: → result (ERROR): EISDIR: illegal operation on a directory, read Tool results: → result (ERROR): Sibling tool call errored Let me search for the documents queries in engines: Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib/engines -type f -name ".ts" | grep -i document | grep -E "(query|index)" | head -20 Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f -path "documentsqueries" -name ".ts" | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/engines/check_in/app/assets/javascripts/modules/DocumentRequestFunnelContentModule/index.tsx /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/patient-clear-documents/index.ts /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/hooks/doctor/shared/useDocumentEdit/index.ts Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/patient_app/appointments/clearDocuments.ts /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/doctor_app/patients/documents.ts /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/doctor_app/appointments/treatmentFormActions.ts /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascript …(truncated, 2295 more chars) Perfect! Now let me read the key document query files: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/doctor_app/documents.ts Tool results: → result (ok): 1→/ 2→ @file 3→ @deprecated This file is deprecated and will be removed in future releases. 4→ Please use the new implementation in packages/@doctolib/documents-ui/src/data/queries/documents.ts. 5→ This refactor happens because of the react query migration to v5. 6→ Feel free to move endpoints to this new file. 7→ / 8→ 9→import path from 'path' 10→import { useContext } from 'react' 11→import type { DoctorAppDocument } from '@doctolib/f …(truncated, 25461 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/doctor_app/unclassifiedDocuments.ts Tool results: → result (ok): 1→import { useContext } from 'react' 2→import type { UseQueryResult } from '@tanstack/react-query' 3→import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' 4→import type { HttpClientType } from 'types/http-client' 5→import { HttpClientContext } from 'contexts/ReactQueryProvider' 6→import { TankerContext } from 'engines/e2ee/public' 7→import useToast from 'hooks/useToast' 8→import i18n from 'services/i18n' 9→import { isDefined } from …(truncated, 6254 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/doctor_app/patients/documents.ts Tool results: → result (ok): 1→import { useContext } from 'react' 2→import { useQuery, useQueryClient, type UseQueryOptions } from '@tanstack/react-query-v5' 3→import { decodeOrNull } from '@doctolib/security' 4→import { isFeatureEnabled } from '@doctolib/variation_management' 5→import { HttpClientContext } from 'monolith_DEPRECATED/contexts/ReactQueryProvider' 6→import type { HttpClientType } from 'monolith_DEPRECATED/types/http-client' 7→import useDocumentDecryption from 'monolith_DEPRECATED/ …(truncated, 3436 more chars) Excellent! I found the v1/v2 endpoint switch! Now let me look for buildDocumentEndpoint which is the key function: Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f \( -name ".ts" -o -name ".tsx" \) | xargs grep -l "buildDocumentEndpoint" 2>/dev/null Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib/packages -type f -path "documents-ui" | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/.swc/plugins/v7_macos_aarch64_14.0.0/c2c663d61736be5d062f4c5f4580649c0681472920d8563ad220f1b89847bacd /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/.swc/plugins/macos_aarch64_23.0.0/79d0e296d7c824847dbba8c1c0a870c0d4678b54b305126c2a0e58a3a1860079.wasmer-v7 /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/.swc/plugins/macos_aarch64_23.0.0/54aa3e07ecbf7df5c7c598c1396d97031c230bb …(truncated, 1887 more chars) Tool results: → result (ERROR): Exit code 1 /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/modules/doctor/mobile/document-upload/ConfirmationModule/useConfirmationModuleController.tsx /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/doctor_app/documents.ts /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/financial_os_care_plan/src/modules/carePlanHelper.ts /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/index.ts /Users/USER/ …(truncated, 1230 more chars) Perfect! Let me read the buildDocumentEndpoint file which contains the v1/v2 switching logic: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/helpers/buildDocumentEndpoint.ts Tool results: → result (ok): 1→import { isFeatureEnabled } from '@doctolib/variation_management' 2→import type { FeatureSwitchOverride } from './types' 3→ 4→// Helper function to determine if V2 API should be used 5→export function shouldUseV2Api(featureSwitchOrOverride?: string | FeatureSwitchOverride): boolean { 6→ // Handle FeatureSwitchOverride object 7→ if (typeof featureSwitchOrOverride === 'object' && featureSwitchOrOverride !== null) { 8→ const override = featureSwitchOrOverri …(truncated, 1654 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/helpers/buildDocumentEndpoint.test.ts Tool results: → result (ok): 1→import { isFeatureEnabled } from '@doctolib/variation_management' 2→import { buildDocumentEndpoint, shouldUseV2Api } from './buildDocumentEndpoint' 3→ 4→jest.mock('@doctolib/variation_management', () => ({ 5→ isFeatureEnabled: jest.fn(), 6→})) 7→ 8→const mockIsFeatureEnabled = isFeatureEnabled as jest.MockedFunction 9→ 10→describe('shouldUseV2Api', () => { 11→ afterEach(() => { 12→ jest.clearAllMocks() 13→ } …(truncated, 12052 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/data/queries/documents.ts 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, 12622 more chars) Perfect! Now let me search for any components that show documents or access the "dokumente anzeigen" functionality: Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f \( -name ".ts" -o -name ".tsx" \) | xargs grep -l "dokumente\|documents" 2>/dev/null | grep -E "(component|section|module)" | head -20 Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/modules/doctor/mobile/document-upload/ConfirmationModule/useConfirmationModuleController.tsx Tool results: → result (ok): 1→import { useContext, useState } from 'react' 2→import { capturePro } from '@doctolib/product-event-wrapper' 3→import i18n from 'services/i18n' 4→import useToast from 'hooks/useToast' 5→import SuccessToast from 'modules/doctor/mobile/document-upload/views/SuccessToast' 6→import { DEPRECATED_post } from 'services/DEPRECATED_fetch' 7→import { NewDocumentStep } from 'types/doctor/api/DocumentUploadFlow' 8→import { useMedicalFolder } from '@doctolib/ehr-core' …(truncated, 6914 more chars) Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/entrypoints-content/components/AppConfiguration.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/sections/doctor/mobile/DocumentEditSection/useDocumentEditSectionNavigation.ts /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/sections/doctor/mobile/DocumentEditSection/useDocumentEditSectionController.ts /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/sections/doctor/mobile/DocumentsUpload …(truncated, 2472 more chars) Great! Now let me check if there's any "show documents" related component in the patient file: Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f -path "patient-file" -name ".tsx" | xargs grep -l "document" 2>/dev/null | head -10 Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/consultation/UploadedDocument/uploadedDocumentHelper.ts Tool results: → result (ok): 1→import { getDecryptedFileUrl } from 'components/shared/documents/utils' 2→import { printOpenAndSetDocument } from 'services/pdf-templates/shared/PdfVisualizer' 3→import httpClient from 'services/http-client/doctor/desktop/httpClient' 4→import type { Account } from 'types/api/Account' 5→import type { DecryptFile } from 'engines/e2ee/public' 6→import type { ToastContextType } from '@doctolib/shared_context' 7→import type { Document } from 'types/doctor/api/Document' …(truncated, 2542 more chars) Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/clinical-document/ClinicalDocumentFormModule/ClinicalDocumentFormVariantModule.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/clinical-document/ClinicalDocumentFormModule/tests/ClinicalDocumentFormModule.test.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop …(truncated, 1600 more chars) Now let me check the shared context to understand the structure better: Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib/packages/@doctolib -type f -name ".ts" | xargs grep -l "UPLOAD_DOCUMENT_FEATURE_SWITCH_OVERRIDE\|MOBILE_CONFIRMATION_UPLOAD" 2>/dev/null Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui -type f -name ".ts" | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/components/DocumentCard.test.tsx /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/components/shared/DocumentActions.tsx /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/components/shared/HoverContainer.tsx /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/components/shared/DocumentInfo.tsx /Users/USER/workspace/doctolib/doctolib/packages/@doc …(truncated, 1705 more chars) Tool results: → result (ERROR): Exit code 1 /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/constants.ts /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/index.ts Let me check the constants file and the index: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/constants.ts Tool results: → result (ok): 1→import type { FeatureSwitchOverride } from './helpers/types' 2→ 3→// Feature switch override for upload_document_write double-write mode 4→export const UPLOAD_DOCUMENT_FEATURE_SWITCH_OVERRIDE: FeatureSwitchOverride = { 5→ featureSwitch: 'upload_document_write', 6→ mode: 'double-write', 7→} 8→ 9→// Feature switch override for mobile confirmation module upload double-write mode 10→export const MOBILE_CONFIRMATION_UPLOAD_FEATURE_SWITCH_OVERRIDE: Featu …(truncated, 476 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/index.ts Tool results: → result (ok): 1→import { DocumentCard } from './components/DocumentCard' 2→ 3→export { DocumentCard } 4→ 5→export type { 6→ DocumentPayload, 7→ DocumentFormBody, 8→ EncryptableDocumentField, 9→ FeatureSwitchOverride, 10→ DocumentEncryptionFeature, 11→ TrackingContext, 12→} from './helpers/types' 13→export { buildDocumentEndpoint, shouldUseV2Api } from './helpers/buildDocumentEndpoint' 14→export { buildPresignedUrlEndpoint } from './helpers/buil …(truncated, 1740 more chars) Perfect! Now let me check the types to understand the feature switch structure: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/helpers/types.ts Tool results: → result (ok): 1→import type { OcrResult } from 'monolith_DEPRECATED/hooks/doctor/useOCR/types' 2→ 3→/ 4→ Valid field names that can be encrypted in document forms. 5→ These correspond to fields in the document API that support encryption. 6→ / 7→export type EncryptableDocumentField = 8→ | 'filename' 9→ | 'ocr_result' 10→ | 'originating_email_sender' 11→ | 'originating_email_subject' 12→ | 'originating_email_body' 13→ | 'originating_email_add …(truncated, 3314 more chars) Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f -name ".ts*" | xargs grep -l "enable_new_documents_controllers" 2>/dev/null | head -5 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/doctor_app/patients/documents.ts /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/doctor_app/appointments/documents.ts Excellent! Now let me look at the appointments documents query to see the other case: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/doctor_app/appointments/documents.ts Tool results: → result (ok): 1→import { useContext } from 'react' 2→import { useQuery, useQueryClient, type UseQueryOptions } from '@tanstack/react-query-v5' 3→import { decodeOrNull } from '@doctolib/security' 4→import { isFeatureEnabled } from '@doctolib/variation_management' 5→import { HttpClientContext } from 'monolith_DEPRECATED/contexts/ReactQueryProvider' 6→import type { HttpClientType } from 'monolith_DEPRECATED/types/http-client' 7→import useDocumentDecryption from 'monolith_DEPRECATED/ …(truncated, 3964 more chars) Perfect! Now I have all the information I need. Let me compile a comprehensive report of my findings. Summary I've successfully mapped the frontend code that handles document uploads and the v1/v2 endpoint switching logic. Here's what I found: 1. Core Endpoint Switching Logic File: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/helpers/buildDocumentEndpoint.ts The buildDocumentEndpoint() function is the central hub for switching between v1 and v2 endpoints: export function buildDocumentEndpoint( documentId?: string, featureSwitchOverride?: string | FeatureSwitchOverride ): string { const version = shouldUseV2Api(featureSwitchOverride) ? '/v2' : '' const documentPath = documentId ? /${documentId} : '' return /doctor_app${version}/documents${documentPath} } Endpoint mapping: - V1 (legacy): /doctor_app/documents or /doctor_app/documents/{documentId} - V2 (new): /doctor_app/v2/documents or /doctor_app/v2/documents/{documentId} 2. Feature Flag Logic The decision to use V2 is based on the shouldUseV2Api() function which checks: 1. Global feature flags (checked in order): - document_single_write - enables V2 write operations - document_double_write - enables V2 with simultaneous v1/v2 writes 2. Override feature switches (with priority over global flags): - Specific team/feature switches like upload_document_write or mobile_upload_document_confirmation_write - These allow granular control per feature with mode: 'single-write' | 'double-write' 3. Document Upload Workflow File: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/contexts/doctor/desktop/DocumentImportContext.tsx Key upload process: 1. Files are collected in DocumentImportContext (line 152: const DOCUMENTS_URL = '/doctor_app/documents') 2. The context uses useDocumentsCreate() hook to upload documents via the documentsCreate mutation 3. Files are encrypted using buildEncryptedFormData() from @doctolib/documents-ui 4. Upload endpoint is determined by buildDocumentEndpoint() with feature switch override 4. Document Retrieval After Upload Two parallel mechanisms exist: A. Patient Documents (New Controller - Preferred) File: /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/doctor_app/patients/documents.ts // NEW: With feature flag 'enable_new_documents_controllers' httpClient.get( /doctor_app/patients/${patientId}/documents ) // LEGACY: Fallback httpClient.get( '/doctor_app/documents.json', { query: { patient_id: patientId } } ) B. Appointment Documents (Similar Pattern) File: /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/doctor_app/appointments/documents.ts // NEW: With feature flag 'enable_new_documents_controllers' httpClient.get( /doctor_app/appointments/${appointmentId}/documents ) // LEGACY: Fallback httpClient.get( '/doctor_app/documents.json', { query: { appointment_id: appointmentId } } ) 5. Feature Switch Overrides File: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/documents-ui/src/constants.ts Two pre-configured overrides: export const UPLOAD_DOCUMENT_FEATURE_SWITCH_OVERRIDE: FeatureSwitchOverride = { featureSwitch: 'upload_document_write', mode: 'double-write', // Writes to both v1 and v2 simultaneously } export const MOBILE_CONFIRMATION_UPLOAD_FEATURE_SWITCH_OVERRIDE: FeatureSwitchOverride = { featureSwitch: 'mobile_upload_document_confirmation_write', mode: 'double-write', } 6. Document Display/Printing File: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/consultation/UploadedDocument/uploadedDocumentHelper.ts Documents are displayed using: - Decrypted file URL for encrypted documents - Legacy path /doctor_app/documents/{documentId} for non-encrypted documents 7. Mobile Document Upload File: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/modules/doctor/mobile/document-upload/ConfirmationModule/useConfirmationModuleController.tsx Mobile uploads also use buildDocumentEndpoint() with MOBILE_CONFIRMATION_UPLOAD_FEATURE_SWITCH_OVERRIDE to determine which endpoint to use. Key Architectural Insights 1. Migration Strategy: The codebase uses feature flags to gradually migrate from v1 to v2 without forcing immediate cutover 2. Double-write Mode: Allows writing to both endpoints simultaneously for safety during migration 3. Decryption: All documents are encrypted with Tanker and decrypted client-side before display 4. Query Invalidation: After uploads, React Query caches are invalidated to refresh document lists 5. Centralized Control: @doctolib/documents-ui package centralizes all document API logic, making it easy to maintain the v1/v2 switching logic