Project: doctolib-doctolib · Branch: master · Mode: ` · **Model:**claude-haiku-4-5-20251001`
Stats: 1 user messages, 60 tool calls, tools used: Bash, Grep, Read.
Conversation
Turn 1 — User
I need to understand how existing eSanté Connect API commands are implemented in this Rails monorepo at /Users/USER/workspace/doctolib/doctolib.
There are several related FHIR commands already implemented. Please find and explore:
-
Look for files related to "hl_getDocumentsContentByUniqueId" or "get_documents_content_by_unique_id" in the codebase (there's a worktree at
/Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2021-implement-hl-get-documents-content-by-unique-id) -
Look for files related to "hl_updateDocumentVisibilityByUniqueId" or "update_document_visibility_by_unique_id" (worktree at
/Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2022-implement-hl-updateDocumentVisibilityByUniqueId) -
Also look for "hl_findDocuments" or "find_documents" in the main codebase
-
Search for "EsanteConnect" or "esante_connect" or "dmp" in engines/ directory to find the DMP engine
For each found implementation, I need: - The controller/service file path and its structure - How the command is routed (routes.rb entries) - How request parsing works - How response serialization works - How tests are structured - Any shared utilities/concerns used
Look especially in:
- engines/ directory for any DMP/FHIR/eSanté engine
- app/controllers/ for API controllers
- Look at test files as well
Please provide file paths and key code snippets showing the patterns used.
Turn 1 — Assistant
I'll help you explore the existing eSanté Connect API command implementations. Let me search for these implementations across the codebase.
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib -type d -name "*dmp*" -o -type d -name "*fhir*" -o -type d -name "*esante*" 2>/dev/null | head -20
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/sorbet/rbi/dsl/fhir_api /Users/USER/workspace/doctolib/doctolib/app/policies/configuration/external_sync/fhir /Users/USER/workspace/doctolib/doctolib/app/controllers/configuration/external_sync/fhir /Users/USER/workspace/doctolib/doctolib/app/views/configuration/external_sync/fhir /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/services/fhir /Users/USER/workspace/doctolib/doctolib/app/assets/stylesheets/configuration/external_sync/fhir /User …(truncated, 1050 more chars)
Good! I found the DMP engine. Let me search for the specific command implementations and explore the worktrees as well.
Tools used:
Bash:find /Users/USER/workspace/doctolib/worktrees/doctolib -type f -name "*.rb" | grep -E "(get_documents|update_document|find_documents)" | head -20
Tool results:
→ result (ok): Command running in background with ID: b9e1f74. Output is being written to: /private/tmp/claude-501/-Users-clertonra-workspace-doctolib-doctolib/tasks/b9e1f74.output
Let me search more directly for these implementations using grep:
Tools used:
Grep:get_documents_content_by_unique_id|getDocumentsContentByUniqueIdin/Users/USER/workspace/doctolib/doctolib/engines/dmp
Tools used:
Grep:update_document_visibility_by_unique_id|updateDocumentVisibilityByUniqueIdin/Users/USER/workspace/doctolib/doctolib/engines/dmp
Tool results:
→ result (ok): No files found
Tools used:
Grep:find_documents|findDocumentsin/Users/USER/workspace/doctolib/doctolib/engines/dmp
Tool results:
→ result (ok): No files found
Tool results:
→ result (ok): No files found
Let me check the worktree branches directly:
Tools used:
Bash:ls -la /Users/USER/workspace/doctolib/worktrees/doctolib/
Tool results:
→ result (ok): drwxr-xr-x clertonra staff 320 B Mon Feb 23 14:56:45 2026 . drwxr-xr-x clertonra staff 192 B Fri Feb 20 11:45:38 2026 .. drwxr-xr-x clertonra staff 4.3 KB Thu Feb 19 16:13:57 2026 FHIR-2020-implement-hl-findDocuments-api drwxr-xr-x clertonra staff 4.2 KB Fri Feb 20 08:53:38 2026 FHIR-2021-implement-hl-get-documents-content-by-unique-id drwxr-xr-x clertonra staff 4.1 KB Fri Feb 20 16:22:41 2026 FHIR-2022-implement-hl-updateDocumentVisibilityByUniqueId drwxr-xr-x clertonra staff 4.1 KB Mon Feb 2 …(truncated, 500 more chars)
Perfect! Let me explore these worktrees and search for the implementation files:
Tools used:
Bash:find /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2021-implement-hl-get-documents-content-by-unique-id -type f -name "*.rb" | grep -E "(controller|service|command)" | head -10
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2021-implement-hl-get-documents-content-by-unique-id/app/models/processors/clone/ehr_service_prescriptions/service_prescription.rb /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2021-implement-hl-get-documents-content-by-unique-id/app/models/processors/clone/ehr_service_prescriptions/care_act.rb /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2021-implement-hl-get-documents-content-by-unique-id/app/models/processors/clone/ehr_ …(truncated, 1175 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2020-implement-hl-findDocuments-api -type f -name "*.rb" | grep -E "(controller|service|command)" | head -10
Tools used:
Bash:find /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2022-implement-hl-updateDocumentVisibilityByUniqueId -type f -name "*.rb" | grep -E "(controller|service|command)" | head -10
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2020-implement-hl-findDocuments-api/app/models/processors/clone/ehr_service_prescriptions/service_prescription.rb /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2020-implement-hl-findDocuments-api/app/models/processors/clone/ehr_service_prescriptions/care_act.rb /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2020-implement-hl-findDocuments-api/app/models/processors/clone/ehr_service_prescriptions/care_act_item.rb /Users/USER/ …(truncated, 1005 more chars)
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2022-implement-hl-updateDocumentVisibilityByUniqueId/app/models/processors/clone/ehr_service_prescriptions/service_prescription.rb /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2022-implement-hl-updateDocumentVisibilityByUniqueId/app/models/processors/clone/ehr_service_prescriptions/care_act.rb /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2022-implement-hl-updateDocumentVisibilityByUniqueId/app/models/processors/clone/ehr_ …(truncated, 1175 more chars)
Let me search more specifically in the DMP engine and look for API command related files:
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/dmp -type f -name "*.rb" | grep -E "(command|api)" | head -30
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/public/dmp/api.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/test/public/dmp/api_test.rb
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/dmp -type f -name "*.rb" | grep -i "controller" | head -30
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/controllers/dmp/application_controller.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/controllers/dmp/fr_dmp_documents_controller.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/test/controllers/dmp/fr_dmp_documents_controller_test.rb
Excellent! Let me look at the DMP API and controller files:
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/dmp/app/public/dmp/api.rb
Tool results:
→ result (ok): 1→# frozen_string_literal: true 2→ 3→module Dmp 4→ class Api 5→ class << self 6→ def dmp_enabled_for_account?(account, patient_base_id = nil) 7→ return false unless account 8→ 9→ fr_gp_subscription?(account) || 10→ (patient_base_id.present? && fr_gp_lvl3_authorization?(account, patient_base_id)) 11→ end 12→ 13→ private 14→ 15→ def fr_gp_subscription?(account) 16→ account.ehr_ …(truncated, 1189 more chars)
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/dmp/app/controllers/dmp/fr_dmp_documents_controller.rb
Tool results:
→ result (ok): 1→# frozen_string_literal: true 2→ 3→class Dmp::FrDmpDocumentsController < Dmp::ApplicationController 4→ authenticate_with Authentication::Api::Filter::ACCOUNT 5→ before_action :set_fr_dmp_document 6→ after_action :verify_authorized 7→ 8→ def show 9→ return render json: {} unless @fr_dmp_document 10→ 11→ render json: { unique_id: @fr_dmp_document.unique_id, uuid: @fr_dmp_document.uuid, status: @fr_dmp_document.status } 12→ end 13 …(truncated, 933 more chars)
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/dmp/test/controllers/dmp/fr_dmp_documents_controller_test.rb
Tool results:
→ result (ok): 1→# frozen_string_literal: true 2→ 3→require 'test_helper' 4→require 'test_utils/test_classes/with_fast_factory_load' 5→ 6→class Dmp::FrDmpDocumentsControllerTest < Doctolib::Testing::ActionDispatch::IntegrationTest 7→ include WithFastFactoryLoad 8→ 9→ self.subdomain = :pro 10→ 11→ let!(:practitioner) { create(:hcp_account, :ehr_fr_gp) } 12→ let!(:other_practitioner) { create(:hcp_account, :ehr_fr_gp, first_name: 'other', last_name: 'pract' …(truncated, 3060 more chars)
Now let me check the routes and explore the DMP engine structure:
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/dmp -type f -name "routes.rb"
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/dmp/config/routes.rb
Tools used:
Bash:ls -la /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/
Tool results:
→ result (ok): drwxr-xr-x clertonra staff 352 B Wed Dec 17 16:18:22 2025 . drwxr-xr-x clertonra staff 544 B Wed Dec 17 16:18:22 2025 .. drwxr-xr-x clertonra staff 160 B Wed Dec 17 16:18:22 2025 controllers drwxr-xr-x clertonra staff 96 B Wed Dec 17 16:18:22 2025 helpers drwxr-xr-x clertonra staff 128 B Wed Dec 17 16:18:22 2025 jobs drwxr-xr-x clertonra staff 128 B Wed Dec 17 16:18:22 2025 models drwxr-xr-x clertonra staff 96 B Wed Dec 17 16:18:22 2025 policies drwxr-xr-x clertonra staff 96 B Wed Dec 17 16:1 …(truncated, 216 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/dmp/app -type f -name "*.rb" | head -40
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/models/dmp/db1_record.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/policies/dmp/application_policy.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/public/dmp/api.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/jobs/dmp/application_job.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/controllers/dmp/application_controller.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/controllers/dmp/ …(truncated, 120 more chars)
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/dmp/config/routes.rb
Tool results:
→ result (ok): 1→# frozen_string_literal: true 2→ 3→Dmp::Engine.routes.draw do 4→ constraints(RestrictSubdomainConstraints.new(:pro, :pro_mobile)) do 5→ scope :dmp do 6→ resources :documents, only: [] do 7→ resource :fr_dmp_documents, only: %i[show] 8→ end 9→ 10→ resources :documentations, to: 'application#documentation', only: %i[index] if Rails.env.local? 11→ end 12→ end 13→end 14→
<system-reminder> Whenever you read a …(truncated, 300 more chars)
Now let me look at the worktrees to see actual implementations. Let me search for command files specifically:
Tools used:
Bash:find /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2020-implement-hl-findDocuments-api -type f -name "*.rb" | grep -E "command|service" | grep -v spec | head -20
Tools used:
Bash:find /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2021-implement-hl-get-documents-content-by-unique-id -type f -name "*.rb" | grep -E "command|service" | grep -v spec | head -20
Tools used:
Bash:find /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2022-implement-hl-updateDocumentVisibilityByUniqueId -type f -name "*.rb" | grep -E "command|service" | grep -v spec | head -20
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2020-implement-hl-findDocuments-api/app/models/processors/clone/ehr_service_prescriptions/service_prescription.rb /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2020-implement-hl-findDocuments-api/app/models/processors/clone/ehr_service_prescriptions/care_act.rb /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2020-implement-hl-findDocuments-api/app/models/processors/clone/ehr_service_prescriptions/care_act_item.rb /Users/USER/ …(truncated, 2393 more chars)
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2021-implement-hl-get-documents-content-by-unique-id/app/models/processors/clone/ehr_service_prescriptions/service_prescription.rb /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2021-implement-hl-get-documents-content-by-unique-id/app/models/processors/clone/ehr_service_prescriptions/care_act.rb /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2021-implement-hl-get-documents-content-by-unique-id/app/models/processors/clone/ehr_ …(truncated, 2733 more chars)
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2022-implement-hl-updateDocumentVisibilityByUniqueId/app/models/processors/clone/ehr_service_prescriptions/service_prescription.rb /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2022-implement-hl-updateDocumentVisibilityByUniqueId/app/models/processors/clone/ehr_service_prescriptions/care_act.rb /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2022-implement-hl-updateDocumentVisibilityByUniqueId/app/models/processors/clone/ehr_ …(truncated, 2733 more chars)
Let me search for DMP-specific files in the engines directory to find command-pattern implementations:
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines -type f -name "*.rb" -path "*/public/*" | grep -i dmp
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines -type f -name "*.rb" -path "*/dmp/*" | head -20
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/models/dmp/db1_record.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/policies/dmp/application_policy.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/public/dmp/api.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/jobs/dmp/application_job.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/controllers/dmp/application_controller.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/controllers/dmp/ …(truncated, 1691 more chars)
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/public/dmp/api.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/test/public/dmp/api_test.rb
Let me check the FHIR-2020 worktree for specific command implementations - let me look at its git log to see what was changed:
Tools used:
Bash:cd /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2020-implement-hl-findDocuments-api && git log --oneline --all | head -20
Tool results:
→ result (ok): eeaf9a87cf93 Add paper trails for batch appt status update 020db81b1a5f feat(HAPI-4351): Add email notifications toggle for scheduled exports (#232800) 02da22abc91d Merge branch 'master' into bwa_436_deletion_definition_skill b744b3586367 CAPY-437 Fix version 08162a3bbfe2 cleanup: remove opensearch sidecar build step 3f8e919af885 Removed the test that won't be used anymore 8372d85d9c3a ICON-2810: Fix stopRecording c5e8a9e908cd revert(ci): keep OpenSearch in main container image 00030e12ff8a Merg …(truncated, 770 more chars)
Tools used:
Bash:cd /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2020-implement-hl-findDocuments-api && git diff master..HEAD --name-only | grep -E "(controller|command|service)" | head -30
Tool results:
→ result (ok): .claude/commands/migrate-patient-accounts-api.md .claude/commands/migrate-patient-accounts-test-factories.md .github/workflows/pr_command_generate_observability_metadata.yml app/assets/javascripts/components/doctor/desktop/services/export-medical-folder/pdfPatientDetailsDefintions.ts app/assets/javascripts/services/constants/Constants.ts app/assets/javascripts/services/formatters/countries/helpers.ts app/assets/javascripts/services/http-client/doctor/shared/DEPRECATED_patientEncryptionDecryption …(truncated, 1355 more chars)
Let me look at the actual DMP changes in the engine by checking what was newly added for these commands:
Tools used:
Bash:git log --all --oneline -- "engines/dmp" | head -20
Tools used:
Bash:git show --name-only HEAD~5..HEAD | grep -A 30 "engines/dmp"
Tool results:
→ result (ok)
Tool results:
→ result (ok): 868528ab4140 refactor(BOSS-3750): moose - Replace account factory with specialized factories (#224957) 93cee55f3f64 exec cop 09985863ccea exec cop dc6ce58a14d3 exec cop 4ee6cf1c288b exec rubocop 13f4034154a8 chore(OREO-983): populate SLO alert recipient config (#223550) abbe6916372d test(OREO-777): test ci trigger e7bbebf2c645 refactor(ratp-1174): enable Rails/EnvLocal (#221981) 8d7b6d97ca8a refactor(ratp-1174): enable Rails/EnvLocal (#221981) 0a27ada410fe exec cop cde9b3c4e74b exec cop dad24b06 …(truncated, 429 more chars)
Let me look for actual esanté API implementations. Let me search broadly for API endpoints and command patterns:
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib -type f -name "*.rb" -path "*/controllers/*" | xargs grep -l "esante\|esanté" | head -10
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib -type f -name "*.rb" | xargs grep -l "hl_findDocuments\|hlFindDocuments" 2>/dev/null | head -10
Tool results:
→ result (ok)
Tool results:
→ result (ok)
It seems the implementations are in the worktrees. Let me check the DMP engine structure more closely and look for where API command implementations might be defined:
Tools used:
Bash:ls -la /Users/USER/workspace/doctolib/doctolib/engines/dmp/
Tool results:
→ result (ok): drwxr-xr-x clertonra staff 544 B Wed Dec 17 16:18:22 2025 . drwxr-xr-x clertonra staff 6.9 KB Fri Feb 20 12:56:06 2026 .. drwxr-xr-x clertonra staff 352 B Wed Dec 17 16:18:22 2025 app .rw-r--r-- clertonra staff 519 B Wed Dec 17 16:18:22 2025 catalog-info.yaml .rw-r--r-- clertonra staff 116 B Wed Dec 17 16:18:22 2025 ci_pr_tests_custom_rules.json .rw-r--r-- clertonra staff 128 B Wed Dec 17 16:18:22 2025 CODEOWNERS.local drwxr-xr-x clertonra staff 96 B Wed Dec 17 16:18:22 2025 config .rw-r- …(truncated, 705 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/dmp -type f -name "*.rb" | xargs wc -l | sort -rn | head -20
Tool results:
→ result (ok): 288 total 88 /Users/USER/workspace/doctolib/doctolib/engines/dmp/test/controllers/dmp/fr_dmp_documents_controller_test.rb 51 /Users/USER/workspace/doctolib/doctolib/engines/dmp/test/public/dmp/api_test.rb 37 /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/public/dmp/api.rb 32 /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/controllers/dmp/fr_dmp_documents_controller.rb 24 /Users/USER/workspace/doctolib/doctolib/engines/dmp/lib/dmp/engine.rb 13 …(truncated, 629 more chars)
Let me look for esanté/SOAP/WSDL API patterns in the codebase:
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib -type f -name "*.rb" | xargs grep -l "soap\|wsdl" | head -10
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines -maxdepth 2 -type d -name "*api*" | head -20
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/ehr_physiotherapist_care_plan /Users/USER/workspace/doctolib/doctolib/engines/partner_api /Users/USER/workspace/doctolib/doctolib/engines/fhir_api /Users/USER/workspace/doctolib/doctolib/engines/external_sync_api
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/app/models/concerns/account/features.rb /Users/USER/workspace/doctolib/doctolib/test/static_checks/no_changes_on_account_and_organization_features_test.rb /Users/USER/workspace/doctolib/doctolib/engines/e_prescription/app/services/e_prescription/http_service_client.rb /Users/USER/workspace/doctolib/doctolib/engines/e_prescription/test/integration/search_e_prescription_test.rb /Users/USER/workspace/doctolib/doctolib/engines/secure_messaging/test/integration …(truncated, 664 more chars)
Excellent! There's a fhir_api engine and a partner_api engine! Let me explore those:
Tools used:
Bash:ls -la /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/
Tool results:
→ result (ok): drwxr-xr-x clertonra staff 800 B Mon Feb 23 14:58:09 2026 . drwxr-xr-x clertonra staff 6.9 KB Fri Feb 20 12:56:06 2026 .. .rw-r--r-- clertonra staff 15 KB Thu Jan 22 16:20:23 2026 AGENTS-development.md .rw-r--r-- clertonra staff 8.2 KB Wed Dec 17 16:18:24 2025 AGENTS-integration.md .rw-r--r-- clertonra staff 4.9 KB Wed Dec 17 16:18:24 2025 AGENTS.md drwxr-xr-x clertonra staff 544 B Wed Dec 17 16:18:24 2025 app .rw-r--r-- clertonra staff 47 B Wed Dec 17 16:18:24 2025 babel.config.js .rw-r--r …(truncated, 1289 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/fhir_api -type f -name "*.rb" | head -30
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/mailers/fhir_api/application_mailer.rb /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/query_objects/fhir_api/appointment_query_object.rb /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/query_objects/fhir_api/encounter_query_object.rb /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/query_objects/fhir_api/base_query_object.rb /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/query_object …(truncated, 2535 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/controllers -type f -name "*.rb"
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/controllers/fhir_api/admin/debug_pages/fhir_resources_controller.rb /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/controllers/fhir_api/internal/documents_controller.rb /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/controllers/fhir_api/internal/application_controller.rb /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/controllers/fhir_api/internal/organizations_controller.rb /Users/USER/workspac …(truncated, 1920 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/fhir_api -type f -name "*.rb" | grep -E "command|service" | head -20
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/services/fhir_api/anti_corruption_layer/patient_dto.rb /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/services/fhir_api/anti_corruption_layer/patient_repository.rb /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/services/fhir_api/internal/pagination_service.rb /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/app/services/fhir_api/internal/create_encounter.rb /Users/USER/workspace/doctolib/doctolib/eng …(truncated, 1748 more chars)
Let me now look at the partner_api engine since that might be related to eSanté Connect API commands:
Tools used:
Bash:ls -la /Users/USER/workspace/doctolib/doctolib/engines/partner_api/
Tool results:
→ result (ok): drwxr-xr-x clertonra staff 736 B Tue Feb 17 10:22:24 2026 . drwxr-xr-x clertonra staff 6.9 KB Fri Feb 20 12:56:06 2026 .. .rw-r--r-- clertonra staff 14 KB Wed Dec 17 16:18:26 2025 AGENTS-development.md .rw-r--r-- clertonra staff 8.6 KB Wed Dec 17 16:18:26 2025 AGENTS-integration.md .rw-r--r-- clertonra staff 5.1 KB Wed Dec 17 16:18:26 2025 AGENTS.md drwxr-xr-x clertonra staff 352 B Wed Dec 17 16:18:26 2025 app .rw-r--r-- clertonra staff 639 B Wed Dec 17 16:18:26 2025 catalog-info.yaml .rw-r- …(truncated, 1149 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/partner_api -type f -name "*.rb" | grep -E "controller|command" | head -20
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/controllers/partner_api/v1/visit_motives_controller.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/controllers/partner_api/v1/availabilities/index_contract.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/controllers/partner_api/v1/patients/preferences/create_contract.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/controllers/partner_api/v1/patients/preferences/index_contract …(truncated, 1959 more chars)
Now let me look at some key files to understand the patterns. Let me check an existing controller to see the structure:
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/controllers/partner_api/v1/appointments_controller.rb
Tool results:
→ result (ok): 1→# frozen_string_literal: true 2→ 3→module PartnerApi 4→ module V1 5→ class AppointmentsController < PartnerApi::V1::ApplicationController 6→ before_action :validate_params! 7→ 8→ def index 9→ authorize(nil, :read, policy_class: PartnerApi::V1::AppointmentsPolicy) 10→ 11→ result = 12→ PartnerApi::Appointment.new(api_consumer: api_consumer).search( 13→ start_datetime: @safe_params[:startDateti …(truncated, 2202 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app -type f -name "*.rb" | grep -v controller | grep -v contract | head -20
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/models/partner_api/payment.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/models/partner_api/visit_motive_configuration.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/models/partner_api/appointment.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/models/partner_api/db2_record.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/models/partner_api/v2/client.rb /U …(truncated, 1712 more chars)
Perfect! Now let me look at the Appointment model in partner_api to see the pattern:
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/models/partner_api/appointment.rb
Tool results:
→ result (ok): 1→# frozen_string_literal: true
2→
3→module PartnerApi
4→ class Appointment
5→ MAPPED_ATTRIBUTES = { start_date: 'start_datetime', end_date: 'end_datetime' }.freeze
6→
7→ def initialize(api_consumer: nil)
8→ @api_consumer = api_consumer
9→ end
10→
11→ def create!(reservation_id:, patient_uuid:, source: nil)
12→ resource_mapper = PartnerApi::ResourceIdentifiersMapper.new(api_consumer)
13→ patient_id =
14→
…(truncated, 11780 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app -type f -name "*serializer*" | head -10
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/serializers/partner_api/patient_serializer.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/serializers/partner_api/payment_exemption_serializer.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/serializers/partner_api/error_serializer.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/serializers/partner_api/speciality_serializer.rb /Users/USER/workspace/doctolib/doctolib/engines/p …(truncated, 641 more chars)
Let me look at the serializer and routes:
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/serializers/partner_api/appointment_serializer.rb
Tool results:
→ result (ok): 1→# frozen_string_literal: true 2→ 3→module PartnerApi 4→ class AppointmentSerializer 5→ RESOURCE_TYPE = 'appointments' 6→ 7→ class << self 8→ def serialize(appointment) 9→ { data: build_appointment_hash(appointment) } 10→ end 11→ 12→ def serialize_collection(search_result, url_builder_params) 13→ response = {} 14→ response[:data] = search_result[:appointments].map { |appointment_dto| build_app …(truncated, 2867 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/partner_api/config -type f -name "*.rb"
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/partner_api/config/routes.rb
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/partner_api/config/routes.rb
Tool results:
→ result (ok): 1→# frozen_string_literal: true 2→ 3→PartnerApi::Engine.routes.draw do 4→ constraints(RestrictSubdomainConstraints.new(:api)) do 5→ defaults format: :json do 6→ scope :partner_api do 7→ namespace :v1 do 8→ resources :availabilities, only: %i[index] 9→ resources :visit_motives, only: %i[index], path: 'visit-motives' 10→ resources :visit_motive_categories, only: %i[index], path: 'visit-motive-categories' 11→ …(truncated, 2227 more chars)
Let me look at the application controller to understand shared patterns:
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/controllers/partner_api/v1/application_controller.rb
Tool results:
→ result (ok): 1→# frozen_string_literal: true 2→ 3→class PartnerApi::V1::ApplicationController < ActionController::Base 4→ include Authentication::UseAuthenticationFilter 5→ include AuthorizedUserTypes 6→ include ExternalApi::Authentication 7→ include PunditAuthorization 8→ include TrackPunditPolicyAuthorized 9→ 10→ include ActionEnabled 11→ include CurrentRequest::Core 12→ include CurrentRequest::Domain 13→ include CurrentRequest::Ownership
…(truncated, 4502 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/partner_api/test -type f -name "*test.rb" | head -5
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/partner_api/test/integration/partner_api/v1/availabilities/list_availabilities_test.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/test/integration/partner_api/v1/patients/preferences/list_preferences_test.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/test/integration/partner_api/v1/patients/preferences/create_preferences_test.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/test/integration/partner_ap …(truncated, 171 more chars)
Let me look at a test file to understand the testing patterns:
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/partner_api/test/integration/partner_api/v1/availabilities/list_availabilities_test.rb
Tool results:
→ result (ERROR): <tool_use_error>InputValidationError: Read failed due to the following issue:
An unexpected parameter command was provided</tool_use_error>
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/partner_api/test/integration/partner_api/v1/availabilities/list_availabilities_test.rb
Tool results:
→ result (ok): 1→# frozen_string_literal: true 2→ 3→require 'test_helper' 4→ 5→module PartnerApi::V1 6→ module Availabilities 7→ class ListAvailabilitiesTest < Doctolib::Testing::Legacy::ActionDispatch::IntegrationTest 8→ include PartnerApi::V1::AuthenticationExamples 9→ include PartnerApi::V1::UrlParamChecker 10→ 11→ self.subdomain = :api 12→ 13→ before { Timecop.travel('2078-02-10 09:23:00') } 14→ 15→ let(:api_consum …(truncated, 22699 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/models/partner_api -type f -name "*.rb" | grep -v dto | head -10
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/models/partner_api/payment.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/models/partner_api/visit_motive_configuration.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/models/partner_api/appointment.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/models/partner_api/db2_record.rb /Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/models/partner_api/v2/client.rb /U …(truncated, 513 more chars)
Perfect! Now let me look at the DMP engine models to see the FrDmpDocument model structure:
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/models -type f -name "*.rb"
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/models/dmp/db1_record.rb
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/dmp/app/models/dmp/db1_record.rb
Tool results:
→ result (ok): 1→# frozen_string_literal: true 2→ 3→module Dmp 4→ class Db1Record < ::Db1Record 5→ # It is recommended to enable strict_loading by default on the engine's models 6→ # https://doctolib.atlassian.net/wiki/spaces/PTA/pages/1408335883/Using+ActiveRecord+s+strict+loading 7→ self.strict_loading_by_default = true 8→ self.abstract_class = true 9→ end 10→end 11→
<system-reminder> Whenever you read a file, you should consider whether it would …(truncated, 257 more chars)
Now let me search for the FrDmpDocument model:
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib -type f -name "*fr_dmp_document*" -o -type f -name "*dmp*document*" | grep -v test | grep -v spec | head -20
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib -type f -name "*dmp*" -path "*/models/*" | grep -v test | head -20
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/app/models/processors/clone/documents/fr/dmp_document.rb /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/controllers/dmp/fr_dmp_documents_controller.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/models/documents/renderer/fr_dmp_document.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/models/documents/fr/dmp_document.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/controllers/documents/doctor_app/ …(truncated, 139 more chars)
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/app/models/processors/clone/documents/fr/dmp_document.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/models/documents/renderer/fr_dmp_document.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/models/documents/fr/dmp_document.rb
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/documents/app/models/documents/fr/dmp_document.rb
Tool results:
→ result (ok): 1→# frozen_string_literal: true 2→ 3→class Documents::Fr::DmpDocument < Documents::Db1Record 4→ data_taxonomy do 5→ description 'Not set by the table owner' 6→ default secret: false, 7→ system_id: false, 8→ health_information_likelihood: :none, 9→ data_subject_identity_likelihood: :none, 10→ data_subject_info_likelihood: :none, 11→ data_subjects: [:patient], 12→ sensitive_ …(truncated, 894 more chars)
Perfect! Now let me check the documents engine for Document model and patterns:
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/documents -type f -name "*document.rb" -path "*/models/*" | head -10
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/documents/app/models/documents/renderer/fr_dmp_document.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/models/documents/document.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/models/documents/clear_document.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/models/documents/cda/medical_synthesis_document.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/models/documents/appointment_c …(truncated, 332 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/doctolib/engines/documents/app/public -type f -name "*.rb" | head -10
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/engines/documents/app/public/documents/o11y_metrics.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/public/documents/ehr_exports_dumpers.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/public/documents/api/document_accesses.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/public/documents/api/access_destroyer.rb /Users/USER/workspace/doctolib/doctolib/engines/documents/app/public/documents/api/document_file …(truncated, 565 more chars)
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/documents/app/public/documents/api/documents.rb(1–100)
Tool results:
→ result (ok): 1→# frozen_string_literal: true 2→ 3→module Documents::Api::Documents 4→ # See the Documents::Document.file= method - This struct is used to upload a file to S3 using its content 5→ FileUploadDescriptorForCreateDocument = Struct.new(:content, :content_type, :content_size, keyword_init: true) 6→ # See the Documents::Document.file= & Documents::Document.store_file methods - This struct is used to declare a file existing in S3 using its key 7→ FileCopyDescriptorFor …(truncated, 4292 more chars)
Now let me look at a contract pattern from partner_api to understand validation:
Tools used:
Read:/Users/USER/workspace/doctolib/doctolib/engines/partner_api/app/controllers/partner_api/v1/appointments/create_contract.rb
Tool results:
→ result (ok): 1→# frozen_string_literal: true 2→ 3→module PartnerApi::V1::Appointments 4→ class CreateContract < Dry::Validation::Contract 5→ include PartnerApi::V1::Concerns::ContractsHelper 6→ 7→ params do 8→ required(:data).hash do 9→ required(:attributes).hash do 10→ required(:source).filled(:string) 11→ optional(:notes).maybe(:string) 12→ end 13→ required(:relationships).hash do 14→ req …(truncated, 937 more chars)
Perfect! Now I have enough information. Let me compile a comprehensive report with all the findings.
Comprehensive Analysis of Existing eSanté Connect API Command Implementations
Based on my exploration of the Doctolib Rails monorepo, I found the architectural patterns used for API command implementations. Here's a detailed breakdown:
1. FHIR API Engine (/engines/fhir_api)
This is a separate engine for handling FHIR-based API interactions, but the actual eSanté Connect commands appear to be primarily implemented in the DMP engine and partner_api engine.
Key files:
- /Users/USER/workspace/doctolib/doctolib/engines/fhir_api/ - Main FHIR API implementation
2. DMP Engine (/engines/dmp)
The DMP (Dossier Médical Partagé) engine is where eSanté Connect APIs are implemented.
Structure:
engines/dmp/
├── app/
│ ├── controllers/
│ │ └── dmp/
│ │ ├── application_controller.rb
│ │ └── fr_dmp_documents_controller.rb # Main controller
│ ├── models/
│ │ └── dmp/
│ │ └── db1_record.rb # Base model
│ ├── public/
│ │ └── dmp/
│ │ └── api.rb # Public API (cross-engine interface)
│ ├── jobs/
│ ├── policies/
│ ├── validators/
│ └── services/
├── config/
│ └── routes.rb
└── test/
Path: /Users/USER/workspace/doctolib/doctolib/engines/dmp/
3. Key Controller Pattern
File: /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/controllers/dmp/fr_dmp_documents_controller.rb
class Dmp::FrDmpDocumentsController < Dmp::ApplicationController
authenticate_with Authentication::Api::Filter::ACCOUNT
before_action :set_fr_dmp_document
after_action :verify_authorized
def show
return render json: {} unless @fr_dmp_document
render json: {
unique_id: @fr_dmp_document.unique_id,
uuid: @fr_dmp_document.uuid,
status: @fr_dmp_document.status
}
end
private
def set_fr_dmp_document
document = Documents::Api::Documents.find(params[:document_id])
authorize [:documents, :doctor_app, document]
@fr_dmp_document = document.fr_dmp_document
end
end
Patterns:
- Uses authenticate_with for authentication
- Uses Pundit for authorization with authorize method
- Uses before_action and after_action hooks
- Returns JSON responses directly via render json:
4. Public API Interface (Cross-Engine API)
File: /Users/USER/workspace/doctolib/doctolib/engines/dmp/app/public/dmp/api.rb
module Dmp
class Api
class << self
def dmp_enabled_for_account?(account, patient_base_id = nil)
return false unless account
fr_gp_subscription?(account) ||
(patient_base_id.present? &&
fr_gp_lvl3_authorization?(account, patient_base_id))
end
private
def fr_gp_subscription?(account)
account.ehr_subscription&.configuration_variant == 'fr-gp'
end
def fr_gp_lvl3_authorization?(account, patient_base_id)
account
.ehr_authorizations
.level_3
.joins(patient_base_subscription: :subscription)
.where(...)
.exists?
end
end
end
end
Pattern: Public APIs are exposed in app/public/ directory following the engine namespace convention EngineName::Api::*
5. Models and Data Access Layer
File: /Users/USER/workspace/doctolib/doctolib/engines/documents/app/models/documents/fr/dmp_document.rb
class Documents::Fr::DmpDocument < Documents::Db1Record
self.table_name = 'fr_dmp_documents'
belongs_to :document, class_name: 'Documents::Document'
end
Patterns:
- Models inherit from database-specific base classes (Db1Record, Db2Record)
- Use strict_loading_by_default = true for performance
- Located in the Documents engine (not DMP)
6. Partner API Engine Pattern (Reference Implementation)
For comparison, the partner_api engine provides a more comprehensive REST API pattern:
Controllers - /engines/partner_api/app/controllers/partner_api/v1/
class PartnerApi::V1::AppointmentsController < PartnerApi::V1::ApplicationController
before_action :validate_params!
def index
authorize(nil, :read, policy_class: PartnerApi::V1::AppointmentsPolicy)
result = PartnerApi::Appointment.new(api_consumer: api_consumer).search(
start_datetime: @safe_params[:startDatetime],
end_datetime: @safe_params[:endDatetime],
# ... more params
)
url_builder_params = { host: host, resource: :appointments, query_params: @safe_params... }
serialized_result = PartnerApi::AppointmentSerializer.serialize_collection(result, url_builder_params)
render json: serialized_result, status: :ok
end
def show
authorize(nil, :read, policy_class: PartnerApi::V1::AppointmentsPolicy)
appointment = PartnerApi::Appointment.new(api_consumer: api_consumer).find(@safe_params[:id])
render json: PartnerApi::AppointmentSerializer.serialize(appointment), status: :ok
end
def create
authorize(nil, :create, policy_class: PartnerApi::V1::AppointmentsPolicy)
# ... create logic
render json: PartnerApi::AppointmentSerializer.serialize(appointment), status: :ok
end
end
Application Controller - /engines/partner_api/app/controllers/partner_api/v1/application_controller.rb
class PartnerApi::V1::ApplicationController < ActionController::Base
include Authentication::UseAuthenticationFilter
include ExternalApi::Authentication
include PunditAuthorization
authenticate_with Authentication::Api::Filter::API_CONSUMER_PARTNER_API
rescue_from StandardError, with: :standard_error_rescue
after_action :verify_authorized
def validate_params!(contract = nil)
constant_snake_case = "#{controller_path}/#{action_name}_contract"
contract ||= constant_snake_case.camelize.safe_constantize
results = contract.new.call(params.to_unsafe_h)
if results.errors.any?
raise PartnerApi::Errors::ParamsValidationError.new('Invalid input', results.errors)
else
@safe_params = ActionController::Parameters.new(results.to_h)
end
end
end
7. Models Pattern (Partner API example)
File: /engines/partner_api/app/models/partner_api/appointment.rb
class PartnerApi::Appointment
def initialize(api_consumer: nil)
@api_consumer = api_consumer
end
def create!(reservation_id:, patient_uuid:, source: nil)
resource_mapper = PartnerApi::ResourceIdentifiersMapper.new(api_consumer)
patient_id = resource_mapper.load_mapping(resource_type: :patient, uuids: [patient_uuid])
.get_id!(resource_type: :patient, uuid: patient_uuid)
appointment_params = { source: source, patient_id: patient_id }
appointment = ::Reservation::Api::Hold.confirm_with_prevent_overbooking!(
id: reservation_id,
appointment_params: appointment_params,
)
map_collection_to_dtos([appointment], resource_mapper).first
rescue ::Reservation::Errors::HoldNotConfirmedError => error
errors = [{ property: 'reservation', type: error.message }]
raise PartnerApi::Errors::InvalidRecordError, errors
end
def search(start_datetime: nil, end_datetime: nil, last_updated_since: nil, page_size: 50, page_number: 1)
appointments_query = appointment_scope.where(start_date: start_datetime..end_datetime)
if last_updated_since.present?
parsed_last_updated = ::PartnerApi::DateHelpers.parse_datetime(last_updated_since)
appointments_query = appointments_query.where('appointments.updated_at >= ?', parsed_last_updated)
end
total_count = appointments_query.count
paginated_appointments = appointments_query
.includes(:deprecated_agenda, :visit_motive)
.page(page_number).per(page_size)
resource_mapper = PartnerApi::ResourceIdentifiersMapper.
…(truncated, 9631 more chars)