Skip to content

tiagoepr/ClinicalNotifierAPI

Repository files navigation

Clinical Notifier API

Scalable API for Clinical Recommendations with Event-Driven Notifications

by Tiago Rodrigues, 2025

Overview

This project implements a scalable, secure, and event-driven backend service for clinical recommendations.
Built with Python and FastAPI, it exposes a RESTful API to process patient health data and return clinical recommendations based on predefined business rules.
The system is fully containerized with Docker and leverages RabbitMQ for event-driven processing, Redis for caching, and SQLite for persistent storage.

Key Features:

  • REST API for patient data and recommendations
  • Rule-based engine simulating clinical recommendation logic
  • Event-driven architecture: recommendations trigger background events
  • Asynchronous, scalable, and cache-optimized (Redis)
  • JWT-based authentication for secure access
  • Out-of-the-box Docker deployment
  • OpenAPI (Swagger) documentation

Assumptions

  • We consider that a patient shall only be subjected to a Post-Op Rehabilitation Plan if it is from orthopaedics surgery, for instance. Other departments may be included on .venv variable ADMISSIBLE_DEPARTMENTS_FOR_REHAB.
  • The API does not generate Patient, Procedures, neither Recommendation IDs (Usually that role belongs to the Hospital MPI and HIS). Instead, it expects these IDs to be unique and to be sent on the methods' payload.
  • A POST /evaluate should accept patient data and return a mock clinical recommendation. For that, it is required for that patient to have procedure history, registered beforehand via API. The method therefore only requires the Patient ID.
  • The GET /recommendation method was replaced by the GET /patient_recommendation for API consistency. It allows GET by patient_id, procedure_id and object expansion.
  • No actual email or phone call was implemented. Instead, a placeholder method is in place, which logs a hypothetical email.

Considerations:

  • The API only generates internal IDs, such as key association between patient and procedure, and patient and recommendation. Also accepting external ones as long as it does not violate DBs integrity.
  • In order to evaluate patient history, a procedure shall be registered and linked to the patient previously via API.
  • The API relies on its database, which is delivered empty. Refer to MAKE commands to seed it with Mock data before testing. With this data:
    • Patient with ID 108 shall be recommended with “Physical Therapy” and “Post-Op Rehabilitation Plan”
    • Patient with ID 105 shall be recommended with "Weight Management Program"
    • Patient with ID 102 shall be recommended with “Post-Op Rehabilitation Plan”
  • The recommendation logic should be easy to replace by actual AI modeled recommendations.
  • OpenAPI is intrinsically provided by FastAPI
  • A Makefile is delivered with a set of commands for easy running, implementations, and testing. Check below.

Implementation Details

Architecture

  • FastAPI serves as the main API, handling patient data, authentication, and recommendation requests.
  • Rule Engine applies business logic to generate recommendations:
    • Age > 65 & chronic pain → "Physical Therapy"
    • BMI > 30 → "Weight Management Program"
    • Recent surgery → "Post-Op Rehabilitation Plan"
  • Event Producer: When a recommendation is generated, an event is published to RabbitMQ.
  • Event Consumer: A separate process listens for events, logs recommendations, simulates notifications, and appends analytics.
  • Redis: Caches frequent queries for performance.
  • SQLite: Stores all persistent data (patients, procedures, recommendations, users).
  • JWT Auth: Secures all endpoints except authentication.
  • Pseudo-pagination with limitation of DB entries

Running the Project

The project includes a Makefile to simplify common operations, data seeding, and API validation. Check help for full command list.

make help

1. App Local Run - DEV/QA

1. Start Redis and RabbitMQ (recommended: via Docker)
make run-rabbitmq
make run-redis
2. Create a virtual environment and install dependencies

Note: If needed, set environment variables (or copy from .env.example) before creating the venv.

make venv
3. Run the API
make run-app
4. Run the consumer
make run-consumer

API docs: http://localhost:8000/docs

RabbitMQ UI: http://localhost:15672 (guest/guest)

5. Stop Redis and RabbitMQ

make stop-rabbitmq
make rm-rabbitmq
make stop-redis
make rm-redis

2. App Docker Run - PROD

1. Start All Docker Services

For a simple running test, docker shall be used. Start Docker stack: API, Consumer, RabbitMQ, and Redis.

make docker-up

You may need to way a few seconds for RabbitMQ to start and the Consumer to be able to connect to it. The Consumer will retry the connection until it actually succeeds. You may check the logs with:

make logs  
make logs-rabbit
make logs-redis

2. Stop and Remove Docker Containers

make docker-down

Validate API

1. Get Token for authenticate towards the API

Considering default user "admin", password "admin"

make get-token USER=admin PASS=admin

2. Seed Database

In order to really use the Evaluate method, we need to populate the database with mock patient and clinical data, including Patients, Clinical Procedures, Recommendations, and Patient Procedure Records

make seed-db

3. Evaluate Patient

make eval-patient PATIENT_ID=108

4. Retrieve Patient Recommendation List

make get-recom PATIENT_ID=108

API docs: http://localhost:8000/docs

RabbitMQ UI: http://localhost:15672 (guest/guest)

Available API Endpoints

Security (Auth)

  • POST /security/token > Issue access & refresh tokens (OAuth2 password; form fields: username, password)
  • POST /security/refresh > Exchange a valid refresh token for a new access token
  • POST /security/register > Create a new user (protected; requires authenticated caller)

Patients

  • POST /patient/ > Create a patient
  • PUT /patient/{patient_id} > Full replace/update a patient (path ID must match body ID)
  • GET /patient/{patient_id} > Retrieve a single patient (cached)
  • GET /patients > List patients (paginated; query: skip, limit; cached)
  • DELETE /patient/{patient_id} > Delete a patient

Procedures

  • POST /procedure > Create a procedure
  • GET /procedure/{procedure_id} > Retrieve a single procedure (cached)
  • GET /procedures > List procedures (paginated; query: skip, limit; cached)
  • PUT /procedure/{procedure_id} > Full replace/update a procedure (path ID must match body ID)
  • DELETE /procedure/{procedure_id} > Delete a procedure

Patient Procedures (N:M)

  • POST /patient_procedure > Link a patient to a procedure (with datetime/report)
  • GET /patient_procedures > List patient-procedure links (paginated; filters: patient_id, procedure_id; expand: procedures|patients|patient_ids; cached)
  • GET /patient_procedure/{patient_procedure_id} > Retrieve a single patient-procedure link
  • PUT /patient_procedure/{patient_procedure_id} > Full replace/update a patient-procedure link
  • DELETE /patient_procedure/{patient_procedure_id} > Delete a patient-procedure link

Recommendations

  • POST /recommendation > Create a recommendation definition (e.g., por-123)
  • GET /recommendations > List recommendations (paginated; query: skip, limit; cached)
  • GET /recommendation/{recommendation_id} > Retrieve a single recommendation (cached)
  • PUT /recommendation/{recommendation_id} > Full replace/update a recommendation
  • DELETE /recommendation/{recommendation_id} > Delete a recommendation

Patient Recommendations (N:M)

  • POST /patient_recommendation > Link a patient to a recommendation (with timestamp)
  • GET /patient_recommendations > List links (paginated; filters: patient_id, recommendation_id; expand: recommendations|patients; cached)
  • GET /patient_recommendation/{patient_recommendation_id} > Retrieve a single patient-recommendation link
  • PUT /patient_recommendation/{patient_recommendation_id} > Full replace/update a patient-recommendation link
  • DELETE /patient_recommendation/{patient_recommendation_id} > Delete a patient-recommendation link

Patient Evaluation (rule engine + events)

  • POST /evaluate/{patient_id} > Run rule-based evaluation for a patient; publish events; returns generated events or {"message":"Nothing to recommend","recommendations":[]}

Future Development

About

Clinical Event-Driven API

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors