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, run them inside tenant context (e.g. with tenant:) or rely on the middleware to set the schema from the request.

Tenant resolution (middleware)

SmartTenantMiddleware resolves the active schema in this order:
  1. Global paths/api/v1/system/, /api/schema/, /api/docs/, /api/redoc/, /admin/, /static/, /media/, /api/chatbot/ stay on public (or let the app handle context). No tenant is set for system routes.
  2. JWT — If the request has a valid Bearer JWT, the user is loaded from the public schema; if the user has a client, that tenant’s schema is used. Ensures school users only access their own school’s data.
  3. X-Schema-Name — Superadmins can send this header to force a schema (e.g. for support or scripting).
  4. Domain — If no JWT/header, the hostname is looked up in Domain (public schema); the matching Client’s schema is used.
Result: system endpoints always run on public; school and chatbot endpoints run on the resolved tenant schema.

Request flow

  1. Client Request: A request is dispatched to a URL (e.g., https://school.sms.local/api/v1/school/admissions/).
  2. Tenant Middleware: Django intercepts the request, checks the hostname (or JWT / X-Schema-Name header), looks up the Domain in the public schema, and maps it to a unique Client tenant. Paths like /api/v1/system/, /api/schema/, /api/docs/, and /admin/ may stay on the public schema.
  3. Schema Routing: The connection schema search path is set (e.g. SET search_path TO tenant_schema, public).
  4. View Processing: The request is routed to the view. Any database ORM queries run in the tenant schema.

API layout

  • /api/v1/system/ — Platform administration (schools, platform users, roles, system auth). No tenant context.
  • /api/v1/school/ — Tenant-scoped operations: auth, users, admissions, sessions, exams, marks, reports, settings, notices, RBAC, audit, promotions, etc. Nested routes under sessions/, exam-sessions/, exams/ for class sessions, exam sessions, and marks.
  • /api/v1/chatbot/ — Chatbot webhooks and API; runs in tenant context when applicable.

Key Subsystems

Clients Module

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

Core Module

The main business logic container for schools. Manages:
  • Academic Info: Sessions, Terms, Classes, and Forms.
  • Student Data: Admissions, session registration, demographics.
  • Assessment: Exam sessions, exams, marks, report cards, teacher/head/class-teacher comments.
  • Settings: Session setup, promotions, general and report settings.

Chatbot Module

Integrates with the WhatsApp API.
  • Listens to incoming webhooks.
  • Routes messages using a state machine or LLM to answer student/parent queries (e.g. results, attendance).
  • Uses Celery/Redis for async processing and can generate batch report PDFs.