A microservices-based application for managing patient data, authentication, billing, and analytics. The system uses an event-driven architecture with Kafka and synchronous communication via gRPC and REST.
The system is composed of five main components running in Docker containers:
- API Gateway (Spring Cloud Gateway): The single entry point for all external requests. It handles routing and validates JWT tokens via the Auth Service before forwarding requests.
- Auth Service: Manages user authentication and JWT token generation/validation.
- Patient Service: The core service for managing patient records. It publishes events to Kafka when patients are created and communicates with the Billing Service via gRPC.
- Billing Service: Handles billing accounts. It receives gRPC calls from the Patient Service to create accounts instantly upon patient registration.
- Analytics Service: Consumes
PatientEventmessages from Kafka to perform data analysis and logging.
- Kafka (KRaft mode): Handles asynchronous messaging between Patient and Analytics services.
- PostgreSQL: Dedicated database instances for Patient and Auth services.
- Language: Java 21
- Framework: Spring Boot 3.x (Web, Data JPA, Validation, Security)
- Communication:
- REST: External API access.
- gRPC: Internal synchronous communication (Patient -> Billing).
- Kafka: Internal asynchronous event streaming (Patient -> Analytics).
- Protobuf: Data serialization for gRPC and Kafka events.
- Database: PostgreSQL 15
- Containerization: Docker & Docker Compose
- Gateway: Spring Cloud Gateway with custom JWT Filter.
- Docker & Docker Compose
- Java 21 (optional, if running locally without Docker)
- Maven (optional, wrapper included)
- Postman (optional, for API testing)
git clone <repository-url>
cd patient-managementCreate a .env file in the root directory with the following content.
Note: The JWT secret must be at least 32 bytes (256 bits) long to meet security standards.
You can generate one with:openssl rand -hex 32
JWT_SECRET=your_very_long_secure_secret_key_heredocker compose up --buildWait for the health checks to pass. Kafka and PostgreSQL need time to initialize before dependent services can start.
A Postman collection is included in the repository for easy API testing.
- Open Postman.
- Click Import (top-left).
- Select the file:
Patient-Management.postman_collection.jsonfrom the project root. - The collection will appear in your sidebar with two folders:
- Auth-Service: Login and token validation requests.
- Patient-Service: CRUD operations for patients.
The collection uses a variable {{patient-id}} for patient-specific operations. After creating a patient, copy the returned ID and set it in the collection variables:
- Click on the collection name Patient-Management.
- Go to the Variables tab.
- Set the
patient-idvalue.
- Login: Run
Auth-Service > loginto get a JWT token. - Copy Token: Copy the token from the response.
- Set Authorization: For requests requiring authentication (e.g.,
get-patients), the Bearer token is already configured. Update it if expired. - Create/Update/Delete Patients: Use the requests in the
Patient-Servicefolder.
All requests should be sent through the API Gateway on port 4004.
Authenticate and receive a JWT token.
- Endpoint:
POST http://localhost:4004/auth/login - Body:
{ "email": "testuser@test.com", "password": "password123" } - Response: Copy the
tokenvalue from the JSON response.
This action triggers both a gRPC call to the Billing Service and a Kafka event to the Analytics Service.
- Endpoint:
POST http://localhost:4004/api/patients - Headers:
Authorization: Bearer <YOUR_TOKEN> Content-Type: application/json - Body:
{ "name": "John Doe", "email": "john.doe@example.com", "address": "123 Main St", "dateOfBirth": "1990-01-01", "registeredDate": "2024-06-15" }
- API Gateway validates the JWT token with the Auth Service.
- Patient Service saves the patient record to PostgreSQL.
- Patient Service calls the Billing Service via gRPC to create a billing account.
- Patient Service publishes a
PatientEventto the Kafkapatienttopic.
Check the logs of the Analytics Service to confirm it received the Kafka message.
docker compose logs -f analytics-serviceExpected Output:
Received patient event : [PatientId=..., Name=John Doe, Email=john.doe@example.com]
Retrieve a list of all registered patients.
- Endpoint:
GET http://localhost:4004/api/patients - Headers:
Authorization: Bearer <YOUR_TOKEN>
- Endpoint:
PUT http://localhost:4000/patients/{patient-id} - Body:
{ "name": "John Updated", "email": "john.updated@example.com", "address": "456 New St", "dateOfBirth": "1990-01-01" }
- Endpoint:
DELETE http://localhost:4000/patients/{patient-id}
patient-management/
βββ api-gateway/ # Spring Cloud Gateway & JWT Validation Filter
βββ auth-service/ # User Authentication & JWT Generation
βββ patient-service/ # Patient CRUD, Kafka Producer, gRPC Client
βββ billing-service/ # gRPC Server for Billing Account Creation
βββ analytics-service/ # Kafka Consumer for Patient Events
βββ api-requests/ # .http files for testing endpoints in VS Code
βββ Patient-Management.postman_collection.json # Postman Collection for API Testing
βββ docker-compose.yml # Container Orchestration
βββ .env # Environment Variables (Git Ignored)
βββ Readme.md # This file
| Problem | Solution |
|---|---|
Kafka: INVALID_REPLICATION_FACTOR |
Ensure KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 is set in docker-compose.yml for single-node setup. |
Kafka: CLUSTER_ID is required |
Add CLUSTER_ID=MkU3OEVBNTcwNTJENDM2Qk to the Kafka environment variables. |
Gateway: 401 Unauthorized |
Ensure your JWT token is valid and the header includes the Bearer prefix (with a space). |
Gateway: 404 Not Found |
Check that the route URIs in application.yml use http:// not https://. |
| gRPC: Connection Refused | Verify the Billing Service container is running and port 9001 is exposed. |
JWT: WeakKeyException |
Your JWT_SECRET in .env must be at least 32 characters (256 bits). |
To stop all running containers:
docker compose downTo stop and remove all data (including database volumes):
docker compose down -v