Product EngineeringFeaturesIntegration Dashboard

Design Decisions

Key design constraints, architectural rationale, and tradeoffs for the Integration Dashboard system.

👤 Neha Lakhdive📅 Updated: Apr 6, 2026🏷️ feature

Design Decisions

These decisions prioritize decoupling, observability, and resilience — ensuring that integration failures never affect core product workflows and that every execution is fully traceable.


1. Event-Driven Configuration via Action IDs

The Problem

Hardcoding integration logic (URLs, headers, auth) inside business controllers (e.g., billing.save) makes each controller brittle. Adding a new vendor requires modifying core business logic.

The Decision

Use stable, business-event-based identifiers — Action IDs (e.g., 57 for Patient Registration, 1 for Bill Generation) — defined in crm.integrations.constants. Each labIntegration row maps an Action ID to a specific endpoint configuration.

Why:

  • Dynamic mapping — a single business event can fan out to multiple integrations based purely on database configuration. No code change needed to add a vendor.
  • Separation of concerns — the business controller only declares that an event occurred. It does not know or care what happens next.
  • Standardized context — metadata (lab ID, bill ID, patient ID) is consistently extracted using the same mechanism for every action type.

2. Centralized Trigger Functions (Common Functions)

The Decision

All integration triggers are routed through named "common functions" (e.g., commomFunctionForIntegrationBillCategory, common_integration_sample_receive) rather than calling integration APIs directly.

Why:

  • Consistency — whether a record is created via UI, bulk upload, or API, the same integration logic runs. No parallel code paths.
  • Code reuse — payload preparation, labIntegration lookup, and Fusion queueing all live in one place per action family.
  • Retryability — the _prepare_kwargs_* pattern can map any failed log back to the same function, making retry reconstruction predictable.

3. Async Dispatch through Fusion

The Decision

All outbound integrations are queued through Fusion async workers rather than being dispatched inline.

Why:

  • Latency isolation — user actions (signing a report, finalizing a bill) complete immediately. Third-party network delays have zero impact on the product experience.
  • Reliability — Fusion provides built-in queuing and isolation from transient failures.
  • Throughput control — high-volume report events don't overwhelm downstream partners; workers consume the queue at a controlled rate.

4. Decorator-Based Logging (IntegrationDirectoryLogger)

The Decision

Logging is implemented as Python decorator classes applied to specific API views and webhook handlers, not as imperative logging calls inside business logic.

Why:

  • Non-invasive — the business function doesn't know logging is happening. Adding observability requires one line (@IntegrationDirectoryLogger()), not changes to the function body.
  • Guaranteed capture — the decorator always runs after the function, even if the function raises. The log reflects what actually happened.
  • Lifecycle tracking — inbound decorators capture the full request → execute → response cycle. Outbound decorators update a pre-created QUEUED log to SUCCESS or FAIL.
  • Fault tolerance — if the active DB transaction is in a broken state (needs_rollback=True), the decorator falls back to a Fusion webhook so the log record is never silently lost.

5. DocumentDB for Integration Logs

The Decision

IntegrationDirectory and IntegrationRetryLog are stored in DocumentDB (MongoDB-compatible), not relational tables.

Why:

  • Schema flexibility — every vendor returns a different JSON shape. A fixed relational schema would require migrations for every new integration or response structure change.
  • Append-only retry historyIntegrationRetryLog grows without modifying the parent record. Relational normalization would add unnecessary join complexity for an operational read pattern.
  • Payload size — webhook payloads (base64 PDFs, HL7 messages, large JSON bodies) don't belong as RDBMS columns.
  • Read pattern fit — dashboard queries are operational log reads and aggregations, not transactional joins. DocumentDB handles this efficiently.

6. Centralized Internal Dispatcher (integrationWebhookAPI)

The Decision

All Fusion-queued integration tasks are routed back through a centralized internal API (integrationWebhookAPI in labs/pyhtonRQAPI.py) rather than calling third-party endpoints directly from trigger functions.

Why:

  • Just-in-time payload enrichment — binary content (base64 PDFs of reports or bills) is injected at dispatch time, not at trigger time. This avoids holding large payloads in the Fusion queue.
  • Unified auth handling — token refreshes and auth header construction happen in one place.
  • Callback coordination — the dispatcher manages the integration_status_callback lifecycle, keeping status update logic out of individual trigger functions.

7. Intent Reconstruction for Retries (_prepare_kwargs_*)

The Decision

Retries do not replay the original serialized HTTP request body. Instead, the system re-fetches live domain objects from the database and calls the original trigger function with fresh arguments.

Why:

  • Stateless workers — background workers cannot safely reuse stale Python objects from a prior execution context. Only DB IDs and primitive values are safely serializable into a retry context.
  • Data accuracy — if a patient record, bill, or report was corrected between the first failure and the retry, the retry should use the corrected data. Replaying a stale payload would re-dispatch incorrect information.

Summary

DecisionRationale
Action IDsDecouples business events from integration handlers — no code change to add a vendor
Common functionsEnsures consistent trigger logic regardless of how an event was initiated
Fusion workersIsolates user workflows from third-party network instability
Decorator loggingKeeps business code clean, guarantees capture, supports fault-tolerant fallback
DocumentDBHandles schema-variable payloads and append-only retry history at scale
Central dispatcherHandles just-in-time enrichment, unified auth, and callback coordination
Intent reconstructionEnsures retries use fresh, accurate domain data — not stale serialized state

On this page