Provider Overview
This page explains how Aivida integrates external lab providers using a single, provider-agnostic architecture.
Why This Exists
- Keep endpoint contracts stable even when providers change.
- Add new providers with adapter registration only.
- Enforce Aivida-first payment control before external booking.
- Persist all critical linkage in Aivida tables for traceability.
High-Level Architecture
flowchart LR
A["Aivida Client"] --> B["POST /api (namespace=labProvider)"]
B --> C["Router Engine"]
C --> D["LabProviderRegistry"]
D --> E["Thyrocare Adapter (LabProviderClient)"]
E --> F["Thyrocare APIs"]
C --> G["Aivida DB (payments, lab_orders, provider_orders, lab_result_files)"]
C --> H["Aivida FileStorage"]Pay-Then-Book Flow
sequenceDiagram
participant App as Aivida App
participant API as Aivida API
participant DB as Aivida DB
participant Reg as Provider Registry
participant T as Thyrocare
App->>API: labProvider.createOrder(providerCode,paymentId,payload)
API->>DB: GetPaymentByID(paymentId, organizationId)
DB-->>API: payment row
alt payment missing or status != success
API-->>App: error (payment-first guard)
else payment status = success
API->>DB: check sourceType/sourceId linkage
alt already linked
API-->>App: existing providerOrderId/labOrderId (idempotent=true)
else not linked
API->>Reg: Resolve(providerCode)
Reg-->>API: LabProviderClient
API->>T: CreateOrder(payload)
T-->>API: externalOrderId
API->>DB: insert lab_orders
API->>DB: insert provider_orders
API->>DB: update payments.sourceType=provider_order
API-->>App: providerOrderId, labOrderId, externalOrderId
end
endReport Fetch Flow
flowchart TD
A["labProvider.getReport"] --> B["Resolve provider via registry"]
B --> C["Provider GetReport(externalOrderId, leadId)"]
C --> D{"report URL present?"}
D -- "No" --> E["Return provider error"]
D -- "Yes" --> F["Download report bytes"]
F --> G["Upload to Aivida FileStorage"]
G --> H["Insert lab_result_files (is_external_result=true)"]
H --> I["Return stable Aivida file URL + metadata"]Data Ownership and Mapping
| Concern | Source of Truth |
|---|---|
| Payment completion | payments |
| External booking reference | lab_orders.order_id |
| Internal provider-order lifecycle | provider_orders |
| Report file metadata | lab_result_files |
| External provider raw response | providerRaw in endpoint response |
Current Provider (v1)
- Supported
providerCode:thyrocare - Namespace:
labProvider - Endpoints:
cataloggetPincodespriceBreakupsearchSlotscreateOrdergetOrderlistOrderscancelOrderrescheduleOrdergetReport
Operational Notes
- v1 uses one platform Thyrocare account.
- Provider operations like cancel/reschedule can be eventually consistent on provider side.
- Status refresh is pull-based in v1 (
getOrder,listOrders), not webhook-driven. - Adding a new provider requires implementing
LabProviderClientand registering it inLabProviderRegistry.
Testing and Smoke Validation
- Endpoint reference: Lab Provider
- Smoke script:
cd backend
./scripts/thyrocare_smoke.sh- Full booking smoke (pay-then-book path):
cd backend
ORG_ID=org_test_thyro \
PAYMENT_ID=<payment_with_status_success> \
PATIENT_ID=<aivida_patient_id> \
./scripts/thyrocare_smoke.sh