Top-level layout
| Path | Role |
|---|---|
manage.py | Django entrypoint |
requirements.txt | Python dependencies |
.env.dev / .env | Environment-specific configuration (not committed with secrets) |
sms/ | Project package: URLs, settings, WSGI/ASGI, middleware, schema hooks, exception handlers, storage |
core/ | Tenant app: academic domain, admissions, exams, marks, reports, RBAC, audit, most REST viewsets |
clients/ | Shared app: tenants (Client), domains, system-level school CRUD |
authentication/ | Shared app: custom User, platform & school auth, JWT views |
chatbot/ | Tenant app: WhatsApp flows, webhooks, Celery tasks, chatbot-specific endpoints |
docs/ | Mintlify documentation (this site) and generated api-reference/openapi.json |
staticfiles/, media/ in dev).
Shared vs tenant apps
Configuration insms/settings.py splits apps into:
SHARED_APPS— Migrations and models in the public schema. Includesdjango_tenants,clients,authentication, admin, DRF, Spectacular, Celery beat, etc.TENANT_APPS—coreandchatbot. Each school schema gets its own copies of these tables.
URL routing
All API routes are wired insms/urls.py:
/api/v1/system/—system_routerfromcore/api_router.py(schools, platform users, roles, system auth)./api/v1/school/—school_routerplus nested routers for sessions, academic classes, exam sessions, exams, session setup, etc./api/v1/chatbot/—chatbot.urls.
core/api_router.py. Nested resources use rest_framework_nested (for example sessions → academic-classes → registration).
Schema and interactive docs:
/api/schema/— OpenAPI JSON (drf-spectacular)/api/docs/— Swagger UI/api/redoc/— ReDoc
Cross-cutting project modules (sms/)
| Module | Purpose |
|---|---|
sms/middleware.py | SmartTenantMiddleware — resolves public vs tenant schema from host, JWT, or X-Schema-Name |
sms/handler.py | global_exception_handler — consistent API errors; special handling for Swagger auth |
sms/schema_hooks.py | OpenAPI preprocessing/postprocessing (filter paths, tenant header, tag order) |
sms/schema_custom.py | Custom Spectacular schema class (ListRetrieveAutoSchema) |
sms/swagger_auth.py | Permission for who can open Swagger/ReDoc/schema |
sms/storage.py | Production static/media (e.g. hybrid + object storage) when enabled |
Core app internals (core/)
High-signal locations:
core/views.py— Large collection ofModelViewSets and related API viewscore/serializers.py— DRF serializers for school-facing resourcescore/models.py— Tenant models (sessions, admissions, exams, etc.)core/permissions.py—DynamicModelPermissions(HTTP method → Django model permissions)core/middleware.py—AuditMiddleware(runs after auth)core/backends.py—TenantPermissionBackendfor school-schema role permissions
Authentication app (authentication/)
- Custom
Usermodel (AUTH_USER_MODEL) - System vs school login viewsets registered on the routers in
core/api_router.py - Backends in
authentication/backends.py(e.g. identifier-based login) complement Django’s defaults
Clients app (clients/)
Clienttenant model andDomainmapping hostnames to tenantsClientViewSetexposed under/api/v1/system/schools/
Chatbot app (chatbot/)
- URLconf, views, tasks (Celery), and models for WhatsApp and automated replies
- Runs as a tenant app; views may resolve tenant context using host, JWT, phone numbers, or other chatbot-specific rules (see Architecture and the Chatbot module page)
Documentation assets
docs/docs.json— Mintlify navigation and theme;api.baseUrlis the default server for the Try it experience in the published API referencedocs/api-reference/openapi.json— Committed snapshot of the schema; regenerate from Django when endpoints change (see API Reference)
Related reading
- Architecture — request flow and multi-tenancy behaviour
- Technical decisions — why this structure and stack were chosen
- API Reference — auth, headers, and how to use the OpenAPI document