SaaSYopiq repozitoriya

Campusio — multi-tenant education SaaS

Multi-tenant Django SaaS for education centres: every centre on its own subdomain with a public site, row-level data scopes per role, real-time chat, encrypted lesson video and paper exams marked from a photo.

Umumiy ko‘rinish

Campusio runs an education business end to end, from a single tutor to a multi-subject centre: courses, groups and enrolment, attendance, homework, tests and printed exams, tuition payments, payroll and accounting, certificates, and a public marketing site for each centre. Live at campusio.uz.

Mening hissam

  • Sole engineer: architecture, backend, frontend and deployment — 205 commits, 65 written architecture decision records.
  • Designed the tenancy layer: middleware resolves the tenant from the request host and scopes the request through a ContextVar; every read endpoint carries a permission code and a role-based data scope.
  • Built 20 Django apps behind DRF — academics, assessments, attendance, payments, payroll, accounting, certificates, chat, materials, subscriptions and more.
  • Lesson video packaged into AES-128 encrypted HLS by Celery workers on RabbitMQ, stored in MinIO split into public and private buckets, uploaded straight to the bucket.
  • Chat over Django Channels: REST for writing, WebSocket for delivery and live read receipts, with a signed handshake ticket.
  • A separate analytics service over gRPC for aggregates and scikit-learn risk scoring; the dashboard degrades instead of failing when it is down.
  • Paper exams: per-student question papers and QR-coded answer sheets, photographed back in and marked; certificates with public verification, rendered with WeasyPrint.
  • Removed per-row queries from list endpoints; 1,295 test functions across 74 test modules.
  • Production Docker Compose behind Caddy, CI that builds and smoke-tests the images, and 3-hourly database and media backups to Telegram over MTProto.

Arxitektura

  • Next.js 16 dashboard and tenant sites (MUI, Radix, TanStack Query), calling the API through a same-origin Next.js proxy.
  • Django 5.2 + DRF on Daphne; PostgreSQL; Redis for cache and the Channels layer.
  • RabbitMQ → Celery workers for video packaging, PDFs and ranking snapshots.
  • MinIO object storage; a gRPC analytics service reading PostgreSQL aggregates.

Asosiy texnik qarorlar

  • Modular monolith, not microservices — analytics is the one documented exception (D-001, D-048).
  • Shared database and schema with a tenant_id column; the hostname is the only authority on tenant identity, and another tenant's object answers 404, not 403 (D-002, D-003, D-010).
  • Tenant scope in a ContextVar, not thread-locals, so it cannot leak between async tasks (D-009).
  • Database constraints preferred over locks; invoices are mutable claims, payments append-only facts (D-013, D-019).
  • JWT pair in httpOnly cookies with double-submit CSRF (D-023).
Barcha loyihalar