Enterprise Integration — Quick Reference

One-Line Definition

Enterprise integration for AI connects LLM inference, RAG pipelines, and AI workflows to the existing enterprise data landscape — EHRs, data warehouses, event buses, ESB middleware, and identity providers — without bypassing the governance controls those systems enforce.


Pattern Selection Guide

Requirement Pattern Implementation
User waiting; < 5s SLA Synchronous REST with timeout + fallback
User waiting; 5–60s SSE streaming FastAPI + StreamingResponse
Server-to-server; minutes Async + Webhook Kafka + HMAC webhook
Offline / scheduled Batch Airflow DAG + checkpointing
Client behind firewall Async + Polling Job submission → GET /jobs/{id}

FHIR R4 — Quick Reference

Minimum FHIR Reads for Clinical RAG Context

http
GET /Patient/{id}
GET /Encounter/{id}
GET /Condition?patient={id}&clinical-status=active
GET /MedicationRequest?patient={id}&status=active
GET /Observation?patient={id}&category=laboratory&date=ge{30d_ago}
GET /AllergyIntolerance?patient={id}

Always execute in parallel (asyncio.gather) — sequential FHIR reads in CDS Hooks will exceed the 5-second EHR timeout.

AI Document Write

python
{
    "resourceType": "DocumentReference",
    "docStatus": "preliminary",    # ✅ AI drafts are ALWAYS "preliminary"
    "status": "current",
    "type": {"coding": [{"system": "http://loinc.org", "code": "18842-5"}]},
    "content": [{"attachment": {"contentType": "text/plain", "data": "<base64>"}}],
    "extension": [{"url": "...ai-generated", "valueBoolean": True}]
}

CDS Hooks Response Pattern

python
# EHR SLA: respond within 5 seconds or return empty cards
try:
    cards = await asyncio.wait_for(_generate_cards(request), timeout=4.5)
except asyncio.TimeoutError:
    return CDSResponse(cards=[])   # Empty cards, never block EHR

SMART on FHIR — Quick Reference

Minimum Necessary Scopes

text
CDS Hooks (read-only):
  system/Patient.read
  system/Encounter.read
  system/Condition.read
  system/MedicationRequest.read
  system/Observation.read
  system/AllergyIntolerance.read

AI Document Write (adds):
  system/DocumentReference.write

Never request: system/*.read — over-broad scope is a HIPAA minimum-necessary violation.

Backend Service Auth Flow

text
1. Build JWT assertion (iss, sub, aud, exp, jti)
2. Sign with RSA-384 private key registered with EHR
3. POST to token_endpoint:
   grant_type=client_credentials
   client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
   client_assertion={JWT}
4. Receive access_token (typically 1-hour expiry)
5. Use in Authorization: Bearer {token} for all FHIR calls
6. Refresh 60 seconds before expiry

Kafka Event-Driven AI — Quick Reference

Topic Design Rules

text
Partition by patient_id → guarantees per-patient event ordering
Retention: 7 days minimum → allows replay on consumer restart
DLQ topic: retain 30 days → investigation window for failures

Consumer Idempotency Pattern

python
# Check before processing; commit only after success
if await dedup_cache.exists(f"processed:{event.event_id}"):
    await consumer.commit()
    return

try:
    await ai_processor.process(event)
    await dedup_cache.setex(f"processed:{event.event_id}", 86400, "1")
    await consumer.commit()
except Exception:
    await route_to_dlq(event)
    await consumer.commit()   # commit to avoid infinite retry

Never: enable<em>auto</em>commit=True — commits before processing; events are lost on crash.

Consumer Lag Alerts

text
>1000 messages sustained for 5m → CRITICAL (scale out consumers)
DLQ growing >10 messages → WARNING (investigate failures)

Webhook Security — Quick Reference

Signature Pattern

python
# Sender: sign every delivery
signature = hmac.new(secret, payload_bytes, sha256).hexdigest()
headers["X-AI-Platform-Signature"] = f"sha256={signature}"

# Receiver: verify before processing
expected = hmac.new(secret, body, sha256).hexdigest()
if not hmac.compare_digest(expected, received[7:]):  # strip "sha256="
    return 401   # Reject unverified webhooks

Retry Policy

text
Attempt 1:  5 seconds
Attempt 2: 30 seconds
Attempt 3:  2 minutes
Attempt 4: 10 minutes
Attempt 5: 30 minutes → DLQ on failure

SSE Streaming — Quick Reference

python
# FastAPI SSE response
return StreamingResponse(
    generator(),
    media_type="text/event-stream",
    headers={
        "Cache-Control": "no-cache",
        "X-Accel-Buffering": "no",   # Required: disable nginx buffering
    }
)

# Token event format
yield f"data: {json.dumps({'type': 'token', 'content': text})}\n\n"

# Heartbeat (every 15s to prevent proxy timeout)
yield ": keep-alive\n\n"

# Completion event
yield "data: [DONE]\n\n"

Identity & Access — Quick Reference

Credential Rules

text
✅ Store API keys in Secrets Manager (AWS) or Key Vault (Azure)
✅ Retrieve at runtime; cache for 5 minutes
✅ Rotate on 90-day schedule (LLM API keys)
✅ Dedicated service account per AI platform component
❌ Never hardcode credentials in config or environment variables
❌ Never share service accounts across components

Common Interview Questions

Q: A CDS Hook response is timing out. What are the likely causes? (1) FHIR reads in series instead of parallel — fix with asyncio.gather. (2) AI inference too slow — add 4.5s timeout and return empty cards. (3) No FHIR prefetch configured — EHR makes extra round-trip on every hook call. Always configure prefetch for the FHIR resources the hook needs.

Q: A Kafka consumer is processing duplicate events and writing duplicate AI documents to the EHR. What's the root cause? enable<em>auto</em>commit=True commits the offset before processing. If the consumer crashes between commit and writing to EHR, the event is committed (won't be retried) but the write didn't happen. The reverse — commit after processing — means crashed consumers will reprocess. Fix: manual commit after successful processing + idempotency check (event_id in dedup cache).

Q: What FHIR scopes would you request for a CDS Hooks service? Only the specific resource types the hook reads: Patient.read, Encounter.read, Condition.read, MedicationRequest.read, Observation.read, AllergyIntolerance.read — all as system/ scopes for backend service auth. Never system/*.read. Document write scope only if the hook writes back to the EHR.


See Also