Skip to main content
The SMS system is built on Django and uses a distinct multi-tenant architecture allowing a single application instance to serve multiple clients (schools) while ensuring strict data isolation.

Multi-Tenancy

We use django-tenants to implement multi-tenancy at the database schema level.
  • Public Schema: Contains shared global data like Client, Domain, and global settings. Access is made via the main domain (e.g., example.com).
  • Tenant Schemas: Each school gets its own schema (e.g., school_a, school_b). All specific data (students, classes, attendances) is stored inside the tenant schema, entirely separated from others. Access is routed via subdomains (e.g., school_a.example.com).
When making queries or performing operations programmatically, you must execute them within the context of a tenant schema using with tenant: or let the middleware handle it automatically based on the incoming request domain.

Request Flow

  1. Client Request: A request is dispatched to a URL (e.g., https://school.sms.local/api/core/students/).
  2. Tenant Middleware: Django intercepts the request, checks the hostname (school.sms.local), looks up the Domain in the public schema, and maps it to a unique Client tenant.
  3. Schema Routing: The connection schema search path is updated SET search_path TO school, public.
  4. View Processing: The request is routed to the view. Any database ORM queries transparently hit the school schema.

Key Subsystems

Clients Module

Handles the creation, modification, and management of Tenants and their Domains.

Core Module

The main business logic container for schools. Manages:
  • Academic Info: Sessions, Terms, Classes, and Forms.
  • Student Data: Bios, Admissions, Demographics.
  • Grades & Attendance: Subject assignments, tracking sheets.

Chatbot Module

A micro-architecture inside the main app that interfaces with WhatsApp API.
  • Listens to incoming webhooks.
  • Routes messages using a state-machine or LLM integration to answer student queries dynamically.
  • Uses Celery/Redis to process incoming messages asynchronously to ensure high availability.