# πŸ“Š Endobest Dashboard - Visual Flowcharts & Diagrams **Visual Reference for Understanding System Flow** --- ## 1️⃣ Main Execution Flow ``` START β”‚ β”œβ”€β†’ [USER INPUT] β”‚ β”œβ”€ Credentials (login) β”‚ β”œβ”€ Number of threads (1-20) β”‚ └─ Execution mode (normal/excel_only/check_only) β”‚ β”œβ”€β†’ [AUTHENTICATION] β”‚ β”œβ”€ IAM Login: POST /api/auth/ziwig-pro/login β”‚ β”œβ”€ Token Exchange: POST /api/auth/config-token β”‚ └─ βœ… Get access_token + refresh_token β”‚ β”œβ”€β†’ [CONFIGURATION LOADING] β”‚ β”œβ”€ Load Endobest_Dashboard_Config.xlsx β”‚ β”œβ”€ Parse 5 sheets: β”‚ β”‚ β”œβ”€ Inclusions_Mapping β”‚ β”‚ β”œβ”€ Organizations_Mapping β”‚ β”‚ β”œβ”€ Excel_Workbooks β”‚ β”‚ β”œβ”€ Excel_Sheets β”‚ β”‚ └─ Regression_Check β”‚ └─ βœ… Validate all configs β”‚ β”œβ”€β†’ [PHASE 2: ORG + COUNTERS] (5-8 sec) β”‚ β”œβ”€ GET /api/inclusions/getAllOrganizations β”‚ β”œβ”€ POST /api/inclusions/inclusion-statistics (20 workers) β”‚ β”œβ”€ Optional: Load eb_org_center_mapping.xlsx β”‚ └─ βœ… Organizations with counts ready β”‚ β”œβ”€β†’ [PHASE 3: DATA COLLECTION] (2-4 min) β”‚ β”œβ”€ Outer Loop: 20 workers per organization β”‚ β”‚ β”œβ”€ GET /api/inclusions/search β”‚ β”‚ └─ For each patient (sequential): β”‚ β”‚ β”œβ”€ POST /api/records/byPatient β”‚ β”‚ β”œβ”€ POST /api/surveys/filter/with-answers β”‚ β”‚ β”œβ”€ Submit: GET /api/requests/by-tube-id (async) β”‚ β”‚ └─ Process: Field mapping + transformation β”‚ └─ βœ… All inclusion data collected β”‚ β”œβ”€β†’ [PHASE 4: QUALITY CHECKS] (10-15 sec) β”‚ β”œβ”€ Coherence Check: β”‚ β”‚ └─ Compare API stats vs actual data β”‚ β”œβ”€ Non-Regression Check: β”‚ β”‚ └─ Compare current vs previous run β”‚ └─ Decision Point: β”‚ β”œβ”€ βœ… No critical issues β†’ Continue β”‚ └─ ❌ Critical issues β†’ Prompt user β”‚ β”œβ”€β†’ [USER CONFIRMATION] β”‚ └─ "Critical issues detected. Write anyway? [Y/N]" β”‚ β”œβ”€ YES β†’ Continue to export β”‚ └─ NO β†’ Exit (files NOT modified) β”‚ β”œβ”€β†’ [PHASE 5: EXPORT] β”‚ β”œβ”€ Backup old files β”‚ β”œβ”€ Write JSON outputs β”‚ β”‚ β”œβ”€ endobest_inclusions.json β”‚ β”‚ └─ endobest_organizations.json β”‚ β”œβ”€ Generate Excel (if configured) β”‚ β”‚ β”œβ”€ Load templates β”‚ β”‚ β”œβ”€ Apply filters/sorts β”‚ β”‚ β”œβ”€ Fill data β”‚ β”‚ └─ Recalculate formulas β”‚ └─ βœ… All files written β”‚ β”œβ”€β†’ [COMPLETION] β”‚ β”œβ”€ Display elapsed time β”‚ β”œβ”€ Log summary β”‚ └─ Press Enter to exit β”‚ END ``` --- ## 2️⃣ Data Collection Detail (Phase 3) ``` [PHASE 3: DATA COLLECTION] β”‚ β”œβ”€ Setup: Thread Pools β”‚ β”œβ”€ Main Pool: ThreadPoolExecutor(N workers, max 20) β”‚ └─ Async Pool: ThreadPoolExecutor(40 workers) β”‚ β”œβ”€ Outer Loop: FOR each Organization (20 workers) β”‚ β”‚ β”‚ β”œβ”€ [1] GET /api/inclusions/search β”‚ β”‚ └─ Response: list of patients for this org β”‚ β”‚ β”‚ β”œβ”€ For Each Patient (Sequential): β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ [2] POST /api/records/byPatient β”‚ β”‚ β”‚ └─ Response: clinical_record β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ [3] POST /api/surveys/filter/with-answers ⚑ OPTIMIZED β”‚ β”‚ β”‚ └─ Response: all questionnaires + answers in 1 call β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ [4] Submit async task (Async Pool): β”‚ β”‚ β”‚ β”‚ GET /api/requests/by-tube-id/{tubeId} β”‚ β”‚ β”‚ β”‚ └─ Fetched in background while main thread processes β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─ [CONTINUE] Process Field Mappings: β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ For Each Field in Config: β”‚ β”‚ β”‚ β”‚ β”œβ”€ Determine Source β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ q_id/q_name/q_category β†’ Find questionnaire β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ record β†’ Use clinical record β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ inclusion β†’ Use patient data β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ request β†’ Use lab request β”‚ β”‚ β”‚ β”‚ β”‚ └─ calculated β†’ Execute function β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ Extract Value (JSON path + wildcard support) β”‚ β”‚ β”‚ β”‚ β”œβ”€ Check Condition (if defined) β”‚ β”‚ β”‚ β”‚ β”œβ”€ Apply Transformations: β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ true_if_any (convert to boolean) β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ value_labels (map to text) β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ field_template (format) β”‚ β”‚ β”‚ β”‚ β”‚ └─ List joining (flatten arrays) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─ Store: output_inclusion[group][field] = value β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ Wait: Lab request from async pool β”‚ β”‚ β”‚ └─ Final: Complete inclusion record ready β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ [5] Update Progress Bars β”‚ β”‚ β”‚ β”œβ”€ Organization progress β”‚ β”‚ β”‚ β”œβ”€ Overall progress β”‚ β”‚ β”‚ └─ (Thread-safe with lock) β”‚ β”‚ β”‚ β”‚ β”‚ └─ [NEXT PATIENT] β”‚ β”‚ β”‚ └─ [NEXT ORGANIZATION] β”‚ └─ Combine All Inclusions └─ βœ… All data collected ``` --- ## 3️⃣ Field Processing Pipeline ``` [INPUT: Configuration field entry] β”‚ β”œβ”€ Field Name: "Patient_Age" β”œβ”€ Source Type: "calculated" β”œβ”€ Field Path: ["extract_age_from_birthday", "Patient_Birthday"] β”œβ”€ Condition: undefined β”œβ”€ Value Labels: undefined β”œβ”€ Field Template: undefined └─ True If Any: undefined β”‚ β–Ό [STEP 1: Determine Source] β”‚ β”œβ”€ Is source "calculated"? β”‚ └─ YES β†’ Call custom function β”‚ execute_calculated_field( β”‚ "extract_age_from_birthday", β”‚ ["Patient_Birthday"] β”‚ ) β”‚ β–Ό [STEP 2: Extract Raw Value] β”‚ β”œβ”€ Get function result β”œβ”€ raw_value = 49 (calculated) β”‚ β–Ό [STEP 3: Check Condition] β”‚ β”œβ”€ Condition field: undefined β”œβ”€ Action: Skip condition check β”‚ β–Ό [STEP 4: Apply Transformations] β”‚ β”œβ”€ true_if_any: undefined (skip) β”œβ”€ value_labels: undefined (skip) β”œβ”€ field_template: undefined (skip) β”œβ”€ List joining: N/A (not a list) β”‚ β–Ό [STEP 5: Format Score Dictionary] β”‚ β”œβ”€ Is value dict with {total, max}? β”‚ └─ NO β†’ Keep as 49 β”‚ β–Ό [OUTPUT: final_value = 49] β”‚ └─ Store: output_inclusion["Patient_Identification"]["Patient_Age"] = 49 ``` --- ## 4️⃣ Questionnaire Optimization Impact ``` SCENARIO: Patient with 15 questionnaires ❌ OLD APPROACH (SLOW): β”‚ β”œβ”€ Loop: for each questionnaire ID β”‚ β”œβ”€ API Call 1: GET /api/surveys/qcm_1/answers?subject=patient_id β”‚ β”œβ”€ API Call 2: GET /api/surveys/qcm_2/answers?subject=patient_id β”‚ β”œβ”€ API Call 3: GET /api/surveys/qcm_3/answers?subject=patient_id β”‚ └─ ... (15 calls total) β”‚ β”œβ”€ Per Patient: 15 API calls β”œβ”€ Total (1200 patients): 18,000 API calls β”œβ”€ Estimated Time: 15-30 minutes └─ Result: SLOW ⏳ β”‚ βœ… NEW APPROACH (FAST - OPTIMIZED): β”‚ β”œβ”€ Single API Call: β”‚ β”‚ β”‚ └─ POST /api/surveys/filter/with-answers β”‚ { β”‚ "context": "clinic_research", β”‚ "subject": patient_id β”‚ } β”‚ ↓ β”‚ Response: [ β”‚ {questionnaire: {...}, answers: {...}}, β”‚ {questionnaire: {...}, answers: {...}}, β”‚ ... (all 15 questionnaires in 1 response) β”‚ ] β”‚ β”œβ”€ Per Patient: 1 API call β”œβ”€ Total (1200 patients): 1,200 API calls β”œβ”€ Estimated Time: 2-5 minutes └─ Result: FAST ⚑ (4-5x improvement) ``` --- ## 5️⃣ Multithreading Architecture ``` MAIN THREAD β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ PHASE 2: Counter Fetching (Sequential Wait) β”‚ β”‚ β”‚ β”‚ Thread Pool: 20 workers β”‚ β”‚ β”œβ”€ Worker 1: Fetch counters for Org 1 β”‚ β”‚ β”œβ”€ Worker 2: Fetch counters for Org 2 β”‚ β”‚ β”œβ”€ Worker 3: Fetch counters for Org 3 β”‚ β”‚ └─ ... β”‚ β”‚ β”‚ β”‚ β”‚ └─ Wait: tqdm.as_completed() [All done] β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ (Sequential barrier) β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ PHASE 3: Inclusion Collection (Nested) β”‚ β”‚ β”‚ β”‚ Outer Thread Pool: 20 workers (Orgs) β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ Worker 1: Process Org 1 β”‚ β”‚ β”‚ β”œβ”€ GET /api/inclusions/search β”‚ β”‚ β”‚ └─ For each patient: β”‚ β”‚ β”‚ β”œβ”€ Process clinical record β”‚ β”‚ β”‚ β”œβ”€ Process questionnaires β”‚ β”‚ β”‚ └─ [ASYNC] Submit lab fetch: β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─ Inner Pool (40 workers) β”‚ β”‚ β”‚ β”œβ”€ Worker A: Fetch lab for Pat1 β”‚ β”‚ β”‚ β”œβ”€ Worker B: Fetch lab for Pat2 β”‚ β”‚ β”‚ └─ ... β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ Worker 2: Process Org 2 [same pattern] β”‚ β”‚ β”œβ”€ Worker 3: Process Org 3 [same pattern] β”‚ β”‚ └─ ... β”‚ β”‚ β”‚ β”‚ β”‚ └─ Wait: tqdm.as_completed() [All done] β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ (Sequential barrier) β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ PHASE 4: Quality Checks (Sequential) β”‚ β”‚ β”œβ”€ Coherence check (single-threaded) β”‚ β”‚ β”œβ”€ Non-regression check (single-threaded) β”‚ β”‚ └─ Results ready β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ PHASE 5: Export (Sequential) β”‚ β”‚ β”œβ”€ Write JSON files β”‚ β”‚ β”œβ”€ Generate Excel (single-threaded) β”‚ β”‚ └─ Done β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## 6️⃣ Quality Checks Logic ``` [INPUT: Current data, Previous data, Config rules] β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ COHERENCE CHECK β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ For each organization: β”‚ β”‚ β”œβ”€ API Count = from statistics β”‚ β”‚ β”œβ”€ Actual Count = from inclusions β”‚ β”‚ └─ Compare: β”‚ β”‚ β”œβ”€ Ξ” ≀ 10% β†’ Warning β”‚ β”‚ └─ Ξ” > 10% β†’ CRITICAL ⚠️ β”‚ β”‚ β”‚ β”‚ Result: has_coherence_critical β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ NON-REGRESSION CHECK β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ For each regression rule: β”‚ β”‚ β”œβ”€ Load previous data β”‚ β”‚ β”œβ”€ Build field selection (pipeline) β”‚ β”‚ β”œβ”€ Find key field for matching β”‚ β”‚ └─ For each inclusion: β”‚ β”‚ β”œβ”€ Match with previous record β”‚ β”‚ β”œβ”€ Check transitions β”‚ β”‚ β”œβ”€ Apply exceptions β”‚ β”‚ └─ Report violations: β”‚ β”‚ β”œβ”€ ⚠️ Warning β”‚ β”‚ └─ πŸ”΄ CRITICAL β”‚ β”‚ β”‚ β”‚ Result: has_regression_critical β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ DECISION POINT β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ If has_coherence_critical OR β”‚ β”‚ has_regression_critical: β”‚ β”‚ β”‚ β”‚ β”‚ └─→ [PROMPT USER] β”‚ β”‚ "Critical issues detected! β”‚ β”‚ Write results anyway? [Y/N]" β”‚ β”‚ β”œβ”€ YES β†’ Proceed to export β”‚ β”‚ └─ NO β†’ Cancel, exit β”‚ β”‚ Else: β”‚ β”‚ └─→ [PROCEED] to export β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό [EXPORT PHASE] ``` --- ## 7️⃣ Excel Export Pipeline ``` [INPUT: Inclusions data, Organizations data, Config] β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ LOAD CONFIGURATION β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ Excel_Workbooks table: β”‚ β”‚ β”œβ”€ workbook_name: "Endobest_Output" β”‚ β”‚ β”œβ”€ template_path: "templates/Endobest.xlsx" β”‚ β”‚ β”œβ”€ output_filename: "{name}_{date_time}.xlsx" β”‚ β”‚ └─ output_exists_action: "Increment" β”‚ β”‚ β”‚ β”‚ Excel_Sheets table: β”‚ β”‚ β”œβ”€ workbook_name: "Endobest_Output" β”‚ β”‚ β”œβ”€ sheet_name: "Inclusions" β”‚ β”‚ β”œβ”€ source_type: "Inclusions" β”‚ β”‚ β”œβ”€ target: "DataTable" β”‚ β”‚ β”œβ”€ column_mapping: JSON β”‚ β”‚ β”œβ”€ filter_condition: JSON β”‚ β”‚ β”œβ”€ sort_keys: JSON β”‚ β”‚ └─ value_replacement: JSON β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ FOR EACH WORKBOOK β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ [1] Load template from Excel file β”‚ β”‚ β”‚ β”‚ β”‚ [2] FOR EACH SHEET IN WORKBOOK β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ Determine data source β”‚ β”‚ β”‚ β”‚ β”œβ”€ Inclusions β†’ Use patient data β”‚ β”‚ β”‚ β”‚ β”œβ”€ Organizations β†’ Use org stats β”‚ β”‚ β”‚ β”‚ └─ Variable β†’ Use template variables β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ [FILTER] Apply AND conditions β”‚ β”‚ β”‚ β”‚ └─ Keep only rows matching all filters β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ [SORT] Apply multi-key sorting β”‚ β”‚ β”‚ β”‚ β”œβ”€ Primary: Organization Name (desc) β”‚ β”‚ β”‚ β”‚ β”œβ”€ Secondary: Date (asc) β”‚ β”‚ β”‚ β”‚ └─ Tertiary: Patient Name (asc) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ [REPLACE] Apply value transformations β”‚ β”‚ β”‚ β”‚ β”œβ”€ Boolean: trueβ†’"Yes", falseβ†’"No" β”‚ β”‚ β”‚ β”‚ β”œβ”€ Status codes: 1β†’"Active", 0β†’"Inactive" β”‚ β”‚ β”‚ β”‚ └─ Enum values: Mapped to display text β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ [FILL] Write data to sheet β”‚ β”‚ β”‚ β”‚ β”œβ”€ Load column mapping β”‚ β”‚ β”‚ β”‚ β”œβ”€ For each row in filtered+sorted dataβ”‚ β”‚ β”‚ β”‚ β”‚ └─ Write to row in Excel β”‚ β”‚ β”‚ β”‚ └─ Fill target (cell or named range) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─ [NEXT SHEET] β”‚ β”‚ β”‚ β”‚ β”‚ [3] Handle file conflicts β”‚ β”‚ β”‚ β”œβ”€ Overwrite: Replace existing file β”‚ β”‚ β”‚ β”œβ”€ Increment: Create _1, _2, _3 variants β”‚ β”‚ β”‚ └─ Backup: Rename existing to _backup β”‚ β”‚ β”‚ β”‚ β”‚ [4] Save workbook (openpyxl) β”‚ β”‚ β”‚ β”‚ β”‚ [5] Recalculate formulas (win32com) [OPTIONAL] β”‚ β”‚ β”‚ β”œβ”€ If win32com available β”‚ β”‚ β”‚ β”œβ”€ Open in Excel β”‚ β”‚ β”‚ β”œβ”€ Force recalculation β”‚ β”‚ β”‚ β”œβ”€ Save β”‚ β”‚ β”‚ └─ Close β”‚ β”‚ β”‚ β”‚ β”‚ └─ [NEXT WORKBOOK] β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό [OUTPUT: Excel files created βœ…] ``` --- ## 8️⃣ Error Handling & Recovery ``` [API CALL] β”‚ β–Ό [TRY] Execute HTTP request β”‚ β”œβ”€ SUCCESS (200-299) β”‚ └─→ Return response β”‚ └─ FAILURE β”‚ β”œβ”€ HTTP 401 (Unauthorized) β”‚ β”‚ β”‚ β”œβ”€β†’ Lock acquired (token_refresh_lock) β”‚ β”œβ”€β†’ new_token(): Refresh token β”‚ β”‚ POST /api/auth/refreshToken β”‚ β”‚ └─ Update global tokens β”‚ β”œβ”€β†’ Lock released β”‚ └─→ RETRY the original request β”‚ β”œβ”€ Network Error (timeout, connection refused, etc.) β”‚ β”‚ β”‚ β”œβ”€β†’ Log warning with attempt number β”‚ β”œβ”€β†’ RETRY after WAIT_BEFORE_RETRY seconds β”‚ └─→ Increment attempt counter β”‚ └─ Other HTTP Error (4xx, 5xx) β”‚ β”œβ”€β†’ Log warning with attempt number β”œβ”€β†’ RETRY after WAIT_BEFORE_RETRY seconds └─→ Increment attempt counter [LOOP: Repeat for ERROR_MAX_RETRY times (10 attempts)] β”‚ β”œβ”€ Attempt 1, 2, 3, ..., 9 β”‚ └─→ If any succeeds: Return response β”‚ └─ Attempt 10 β”‚ β”œβ”€ Still failing? β”‚ β”‚ β”‚ └─→ Log CRITICAL error β”‚ └─→ Raise exception (propagate to main) β”‚ └─ Main catches exception β”œβ”€β†’ Display error message β”œβ”€β†’ Log to dashboard.log └─→ Exit gracefully ``` --- ## 9️⃣ Configuration-Driven Execution ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ ENDOBEST_DASHBOARD_CONFIG.XLSX β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ Sheet 1: Inclusions_Mapping β”‚ β”‚ β”œβ”€ Row 1: Headers β”‚ β”‚ β”œβ”€ Row 2+: Field definitions β”‚ β”‚ β”‚ β”œβ”€ field_group: "Patient_Identification" β”‚ β”‚ β”‚ β”œβ”€ field_name: "Patient_Id" β”‚ β”‚ β”‚ β”œβ”€ source_id: "q_name" β”‚ β”‚ β”‚ β”œβ”€ source_value: "Demographics" β”‚ β”‚ β”‚ β”œβ”€ field_path: ["patient_id"] β”‚ β”‚ β”‚ └─ ... (more transformations) β”‚ β”‚ β”‚ β”‚ β”‚ Sheet 2: Organizations_Mapping β”‚ β”‚ β”‚ β”œβ”€ Defines org fields β”‚ β”‚ β”‚ └─ Rarely modified β”‚ β”‚ β”‚ β”‚ β”‚ Sheet 3: Excel_Workbooks β”‚ β”‚ β”‚ β”œβ”€ Workbook metadata β”‚ β”‚ β”‚ β”œβ”€ Template references β”‚ β”‚ β”‚ └─ Output filename templates β”‚ β”‚ β”‚ β”‚ β”‚ Sheet 4: Excel_Sheets β”‚ β”‚ β”‚ β”œβ”€ Sheet configurations β”‚ β”‚ β”‚ β”œβ”€ Data transformation rules β”‚ β”‚ β”‚ └─ Filters, sorts, replacements β”‚ β”‚ β”‚ β”‚ β”‚ Sheet 5: Regression_Check β”‚ β”‚ β”‚ β”œβ”€ Quality check rules β”‚ β”‚ β”‚ β”œβ”€ Field selection pipelines β”‚ β”‚ β”‚ β”œβ”€ Transition patterns β”‚ β”‚ β”‚ └─ Severity levels β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ [APPLICATION LOADS] β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ LOADED IN MEMORY β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ INCLUSIONS_MAPPING_CONFIG = [...] β”‚ β”‚ REGRESSION_CHECK_CONFIG = [...] β”‚ β”‚ EXCEL_EXPORT_CONFIG = {...} β”‚ β”‚ β”‚ β”‚ [USED BY] β”‚ β”‚ β”œβ”€ Field extraction (all fields) β”‚ β”‚ β”œβ”€ Quality checks (regression rules) β”‚ β”‚ └─ Excel generation (workbook config) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ [CHANGES = AUTOMATIC ON NEXT RUN] β”‚ └─→ NO CODE RECOMPILATION NEEDED βœ… └─→ NO RESTART NEEDED βœ… ``` --- ## πŸ”Ÿ File I/O & Backup Strategy ``` [INITIAL STATE] β”œβ”€ endobest_inclusions.json (today's data) β”œβ”€ endobest_inclusions_old.json (yesterday's data) β”œβ”€ endobest_organizations.json (today's stats) └─ endobest_organizations_old.json (yesterday's stats) [EXECUTION STARTS] β”‚ β”œβ”€ [Collect new data] β”œβ”€ [Run quality checks] └─ [If quality checks passed] β”‚ └─→ [Backup old β†’ old.old] β”œβ”€ endobest_inclusions.json β†’ endobest_inclusions_old.json └─ endobest_organizations.json β†’ endobest_organizations_old.json β”‚ └─→ [Write new files] β”œβ”€ NEW endobest_inclusions.json (written) └─ NEW endobest_organizations.json (written) β”‚ └─→ [COMPLETION] [FINAL STATE] β”œβ”€ endobest_inclusions.json (NEW data) β”œβ”€ endobest_inclusions_old.json (TODAY's data, now old) β”œβ”€ endobest_organizations.json (NEW stats) └─ endobest_organizations_old.json (TODAY's stats, now old) [IF CRITICAL ISSUES] β”‚ β”œβ”€ [Skip backup & write] β”œβ”€ [Old files preserved] β”œβ”€ [User prompted: write anyway?] β”‚ β”œβ”€ YES β†’ Write new files (override) β”‚ └─ NO β†’ Abort, keep old files β”‚ └─ [No data loss] ``` --- ## File Format Examples ### endobest_inclusions.json Structure ``` [ { "Patient_Identification": { "Organisation_Id": "...", "Organisation_Name": "...", "Center_Name": "..." (from mapping), "Patient_Id": "...", "Pseudo": "...", "Patient_Name": "...", "Patient_Birthday": "...", "Patient_Age": ... }, "Inclusion": { "Consent_Signed": true/false, "Inclusion_Date": "...", "Inclusion_Status": "...", ... }, "Extended_Fields": { "Custom_Field_1": "...", "Custom_Field_2": ..., ... }, "Endotest": { "Request_Sent": true/false, "Diagnostic_Status": "...", ... } } ] ``` ### endobest_organizations.json Structure ``` [ { "id": "org-uuid", "name": "Hospital Name", "Center_Name": "HOSP-A" (from mapping), "patients_count": 45, "preincluded_count": 8, "included_count": 35, "prematurely_terminated_count": 2 } ] ``` --- **All diagrams above show the complete system flow from start to finish.** **For detailed implementation, see technical documentation files.**