System Design

System Architecture & Modular Monolith Design

1. Monolith Architecture & Module Boundaries

The HMIS is designed as a Modular Monolith. This pattern balances the development simplicity of a single deployment unit with the strict domain isolation of microservices. It matches the on-premise constraints of a Level 4 hospital in Western Kenya by eliminating network overhead between services while preserving modular boundaries.

Rendering Chart

1.1 Strict Module Isolation Rules

To prevent the codebase from turning into an unmaintainable "spaghetti" architecture, the modular monolith enforces clear boundaries:

  • Database Separation: Modules communicate only through their public API contracts or domain events. Cross-module database joins are blocked at the code review level.
  • Independent Domain Entities: Every module owns its distinct database schemas inside PostgreSQL, organized via dedicated Django apps and database schemas.
  • Shared Kernel Limitations: Only universal constants, shared types, security encryption routines, and the global audit logging engine reside within the Shared Kernel.

2. In-Process Communication & Asynchronous Event Patterns

Communication between modules balances real-time consistency requirements against system availability.

2.1 Synchronous In-Process API Invocation

When a module requires immediate data validation from another module (e.g., the Clinical Module verifying a patient's active status before opening an admission record), it executes a direct, synchronous call via typed Python interfaces. This process avoids network latency and serialization overhead.

# Module boundary invocation blueprint
from typing import Dict
import uuid

class PatientModulePublicAPI:
    @staticmethod
    def verify_patient_active_status(patient_id: uuid.UUID) -> Dict[str, bool]:
        """
        Public synchronous API exposed by the Patient Module 
        for consumption by external domain scopes.
        """
        # Internal query execution remains isolated within the Patient app boundary
        from apps.patient.models import PatientRegistration
        try:
            patient = PatientRegistration.objects.get(id=patient_id)
            return {"is_active": patient.is_active, "is_deceased": patient.is_deceased}
        except PatientRegistration.DoesNotExist:
            return {"is_active": False, "is_deceased": False}

2.2 Asynchronous Event-Driven Loops via Huey & Redis

For non-blocking operations, cross-module updates, and third-party gateway integrations (e.g., pushing an approved billing claim to the SHA API), the architecture shifts to an asynchronous event pattern using Huey backed by Redis.

Rendering Chart

3. High Availability (HA) Local Infrastructure Design

Level 4 hospitals in Western Kenya frequently experience internet connectivity drops and power instability. The infrastructure is engineered to run reliably on local hardware.

3.1 Dual Physical Machine Active-Passive Node Cluster

The on-premise installation consists of two physical server towers configured as an Active-Passive high-availability cluster using Docker Compose and automated local replication.

Rendering Chart

3.2 Automated Failover Mechanics

  • Virtual IP (VIP) Allocation: A virtual IP is shared between the two nodes. Client machines connect only to this VIP.
  • Health Check Probing: A local heartbeat script monitors the primary node. If Node 1 experiences a hardware failure, the system redirects traffic to Node 2 automatically.
  • Database Promotion: The PostgreSQL instance on Node 2 exits read-only replication mode, promotes itself to primary, and assumes the operational database load within 60 seconds of a failure event.

Document Verification Block

Author: Ian Wataka - Backend Developer
Target Scope: Level 4 Hospital Production Infrastructure