Skip to content
All work
SaaSlive

Mudarris

Offline-first multi-tenant tutoring SaaS — Flutter app, parent dashboard, billing, exam engine.

2024 Egypt Confidential (Egypt / MENA)

// Results

4
Client platforms
124
DI services registered
15
Business rules shipped
v16
SQLite schema version

A production-grade, offline-first SaaS platform for private tutors and tutoring centers in Egypt / MENA. Each tenant (a teacher or a center) runs a cross-platform Flutter app on their devices, their parents track progress through a web dashboard, and the platform owner runs the whole business from an admin console. Fully bilingual (Arabic / English, RTL-aware) end to end.


Table of Contents

  1. Elevator Pitch
  2. Architecture Overview
  3. Technology Stack
  4. Teacher App — Feature Deep-Dive
  5. In-Classroom Digital Exam Engine
  6. Synchronization Engine
  7. Parent Web Dashboard
  8. Landing Site, Billing & Owner Admin Console
  9. WhatsApp Messaging Microservice
  10. Backend — Supabase Platform
  11. Subscription Model & Plan Gating
  12. Billing Integration (Stripe → Paymob)
  13. Security & Multi-Tenancy
  14. Engineering Practices
  15. Resume / Portfolio Highlights

1. Elevator Pitch

Mudarris digitizes the full operation of a private tutoring business: students, class groups, staff, attendance, homework, monthly invoicing and payments, a question bank, and live digital exams delivered to students' phones over the classroom Wi-Fi — all working fully offline and syncing to the cloud (and peer-to-peer across devices) when a connection is available. Parents get a real-time web portal and WhatsApp updates. The platform owner sells it as a subscription SaaS with self-service signup, free trials, tiered plans, and a complete analytics + administration console.

The system is a Melos-managed monorepo comprising four applications, a shared Dart package, and a Supabase backend (Postgres + Edge Functions + scheduled cron jobs).


2. Architecture Overview

Monorepo layout (Melos — packages apps/* + packages/*):

ComponentPathStackRole
Teacher appapps/tutoring_appFlutter (Android / iOS / macOS / Windows)Offline-first management app for the tutor/center
Parent dashboardapps/parent_dashboardNext.js (App Router)Web portal for parents to track their children
Landing + Admin + Billingapps/landingNext.js (App Router)Marketing site, tenant signup, billing, owner admin panel
WhatsApp serviceapps/whatsapp_serviceNode.js + Express + BaileysRelay that sends WhatsApp messages to parents
Backendsupabase/Supabase (Postgres + Edge Functions + pg_cron)Cloud database, sync APIs, billing, scheduled jobs
Shared modelspackages/shared_modelsDartShared enums/entities across the Dart apps
                          ┌──────────────────────────────┐
                          │      Supabase Backend         │
                          │  Postgres + RLS (tenant_id)   │
                          │  Edge Functions (Deno)        │
                          │  pg_cron scheduled jobs        │
                          └──────────────────────────────┘
                            ▲         ▲          ▲       ▲
              sync-token /  │         │          │       │  service
              cloud-sync    │         │          │       │  webhooks
        ┌───────────────────┘         │          │       └────────────────┐
        │                             │          │                        │
┌───────────────┐          ┌──────────────────┐ │              ┌───────────────────┐
│ Teacher App   │          │ Parent Dashboard │ │              │ Landing + Admin   │
│ Flutter       │          │ Next.js (web)    │ │              │ Next.js (web)     │
│ Android/iOS/  │          │ phone login,     │ │              │ marketing, signup,│
│ macOS/Windows │          │ web push (VAPID) │ │              │ billing, /admin   │
│ offline SQLite│          └──────────────────┘ │              └───────────────────┘
└───────────────┘                                │
    │      │                                      │
    │      │ LAN sync (WebSocket 8082 / UDP 8083) │
    │      └──────────► other teacher devices     │
    │                                              │
    │ embedded HTTP exam server (port 8080)        │
    └──────────► students' browsers on classroom LAN
                                                   │
                          ┌────────────────────────┘
                          ▼
                ┌────────────────────────┐
                │ WhatsApp Service        │
                │ Node + Express + Baileys│
                │ (Fly.io / Docker)       │
                └────────────────────────┘

Design principles

  • Offline-first: the teacher app is fully functional with no network; all writes are buffered locally and reconciled on reconnect.
  • Tenant isolation: every business row carries a tenant_id; Postgres Row Level Security enforces isolation from the JWT.
  • Least privilege on device: the Supabase service-role key never ships in the app — clients authenticate cloud sync with a scoped, revocable sync token.
  • Clean Architecture + BLoC on the client; framework-agnostic domain logic with Either<Failure, Success> error modeling.

3. Technology Stack

Teacher App — Flutter (Dart >=3.5, Flutter >=3.24)

ConcernTechnology
State managementflutter_bloc 8.x, bloc, equatable
Dependency injectionget_it 7.x + injectable (codegen)
Routinggo_router 14.x (StatefulShellRoute nav stacks)
Local databasesqflite / sqflite_common_ffi + sqlcipher_flutter_libs (encryption staged)
Cloud clientsupabase_flutter 2.x, http, connectivity_plus
Embedded exam servershelf, shelf_router, shelf_web_socket
LAN syncweb_socket_channel + raw UDP sockets
QRqr_flutter (generate), mobile_scanner (scan)
Chartsfl_chart, flutter_staggered_grid_view
Crypto / authcrypto, encrypt, local_auth (biometrics)
Documentspdf + printing, excel, archive, xml
Media / filesimage, image_picker, image_cropper, file_picker, share_plus, video_player
Systemshared_preferences, permission_handler, url_launcher, package_info_plus, flutter_local_notifications, flutter_foreground_task
i18nflutter_localizations + intl + .arb files
Testingflutter_test, integration_test, mocktail, bloc_test

Parent Dashboard — Next.js 14.2 (App Router)

  • React 18 + TypeScript 5, Tailwind CSS 3.4
  • @supabase/supabase-js + @supabase/ssr (auth + Realtime)
  • recharts (charts), date-fns, lucide-react, clsx, tailwind-merge
  • Web Push (VAPID) via service workers
  • E2E testing with Playwright

Landing + Admin — Next.js 14.2 (App Router)

  • React 18 + TypeScript 5, Tailwind CSS 3.4
  • framer-motion (animation), recharts, lucide-react
  • @supabase/supabase-js + @supabase/ssr
  • Billing: Stripe (legacy) → Paymob (Intention API, HMAC verification)
  • Unit testing with Vitest

WhatsApp Service — Node.js (ES modules)

  • @whiskeysockets/baileys 6.7 (WhatsApp Web protocol)
  • express 4.21, cors, qrcode, pino (logging)
  • Deployed on Fly.io via Docker; PM2 process management

Backend — Supabase

  • Postgres with Row Level Security
  • Edge Functions (Deno / TypeScript)
  • pg_cron scheduled jobs
  • Supabase Auth (parent + admin + tenant accounts)
  • Supabase Realtime (parent dashboard live updates)

Shared

  • packages/shared_models — Dart package shared by the Flutter apps:
    • 15 enums: StudentStage, DiscountType, StudentStatus, GroupStatus, EmployeeRole, Permission, InvoiceStatus, PaymentMethod, ExamStatus, AttendanceStatus, HomeworkStatus, DifficultyLevel, AcademicTerm, SyncOperation, WhatsAppMessageType.
    • 4 models: ScheduleSlot, ExamQuestion, StudentAnswer, TabSwitchEvent.
  • Monorepo orchestration with Melos (bootstrap, analyze, test, build:runner, format)

4. Teacher App — Feature Deep-Dive

A cross-platform (Android / iOS / macOS / Windows) Clean-Architecture Flutter app. ~18 feature modules, each with data / domain / presentation layers and dedicated BLoCs.

Authentication & Access Control

  • PIN login (4–6 digits, SHA-256 hashed with an app salt).
  • Biometric unlock (fingerprint / Face ID) via local_auth, toggleable.
  • Brute-force protection: 5-attempt lockout with a 30-minute cooldown.
  • Multi-user device: a local-only Admin plus named employees, each with their own PIN and role-based permissions.
  • Session persistence across restarts.

Students

  • Full CRUD, search by name / phone / academic stage, soft-delete (history preserved).
  • Duplicate detection on entry.
  • Bulk import from Excel.
  • QR sticker codes (STU-XXXX) for fast attendance/identification.
  • Parent-account linking by phone.

Groups (Classes)

  • Class groups with subject, academic stage, grade year, and weekly schedule slots.
  • Dual pricing model: monthly fee and per-session fee; online vs in-person.
  • Archive/active states; soft-delete.
  • QR sticker-sheet PDF export for a whole group.

Employees / Staff

  • Staff CRUD with name, phone, email, role.
  • Per-employee PIN and granular permission set controlling which modules they can use.

Invoices

  • Automatic monthly invoice generation (configurable day of month, default the 15th).
  • Pricing formula (monthlyFee / 4.33) × sessionCount with sibling discounts for families.
  • Statuses: pending / paid / partially paid / overdue (with a configurable grace period).
  • PDF invoice export.

Payments

  • Record payments by method (cash / bank transfer / online), capture payer and date.
  • Revenue reporting.

Question Bank

  • Question CRUD with multiple-choice options, per-question marks, question + explanation images (base64), and term tagging.
  • Rich filtering: subject / stage / grade / chapter / term / difficulty, with pagination.
  • Excel import/export.
  • Intentionally local-only (excluded from cloud sync) to avoid bulk question leakage and sync overhead.

Attendance

  • Mark present / absent / late / excused per session; per-student reports; cloud-synced.

Homework

  • Assign per group with due dates; bulk-mark completion; statuses assigned / submitted / graded / overdue; date-range filtering.

Dashboard / Analytics

  • Metric tiles (students, groups, employees, upcoming exams, pending invoices, monthly revenue, attendance rate).
  • Charts via fl_chart (revenue trend, stage distribution, attendance).
  • "Safe mode" to hide sensitive financial/student data on shared screens.

WhatsApp Automation (client)

  • Rule-based parent messaging: attendance alerts, invoice reminders, homework notices, custom broadcasts.
  • Controls: enable per rule, quiet hours, cooldown, auto-send vs review queue, group/student scoping.
  • Template variables ([StudentName], [GroupName], [DueDate], …) with a styled template editor.
  • Local send queue with SHA-1 event deduplication, flushed every minute when the relay is online.
  • Per-send logging; feature-gated by plan with a monthly send limit.

Backup & Export

  • Timestamped local SQLite backups; full Excel export of all business data (multi-sheet); restore from file. Feature-gated.

Tenant & Subscription

  • Connect a device to a tenant via a connection code; founding-deploy build-time single-tenant mode.
  • Live subscription status, trial banner with days remaining, and automatic sync-token refresh on 401/403.

Parents & Pending Registrations

  • Create/link parent portal accounts (auto-generates credentials), onboarding queue processed during sync.
  • Review students who self-registered online and enroll them.

Settings

  • Theme (light / dark / system), language (AR/EN), business-rule preferences (default subject, enabled stages), exam-login branding (name, slogan, logo, color), dashboard safe mode, parent-dashboard URL.

5. In-Classroom Digital Exam Engine

The standout feature: the teacher app embeds a full HTTP + WebSocket server (shelf, ~3,700 LOC) on port 8080, turning the teacher's device into an exam host that students join from their own phone browsers over the classroom Wi-Fi — no internet required.

Exam authoring

  • Digital and paper exams; manual or smart/randomized question selection; per-student question counts; term filtering; backward-navigation toggle; per-student wrong-answer review whitelist; grade override with automatic re-grade.

Student delivery endpoints

  • Login (scan QR or enter ID + PIN), exam page (HTML5), /api/exam-data (questions + remaining time, answers withheld), question images, real-time answer save, submit + auto-scoring, heartbeat, status.

Live teacher control (admin endpoints + WebSocket monitor)

  • Pause / resume the exam, extend time (globally or per student), block / unblock a student, force-submit, allow re-entry, live results dump.

Anti-cheat

  • Per-student question and option shuffling (original indices preserved for grading).
  • Session tokens bound to the student's IP to prevent hijacking.
  • Tab-switch detection & counting, screenshot-attempt tracking, per-student watermark (ID + timestamp).
  • Heartbeat watchdog auto-blocks a student whose connection drops for >15 s.

Delivery quality

  • Gzip-compressed responses, CORS, teacher branding on the login page, AR/EN student UI, configurable pass threshold (default 50%). A foreground service keeps the server alive when the app is backgrounded.

6. Synchronization Engine

Two independent, complementary sync layers.

Cloud Sync (Supabase Edge Functions)

  • Write path (cloud-sync) and incremental read path (cloud-sync-read, since cursor).
  • Authenticated per-tenant with x-tenant-id + x-sync-token headers; server-side plan-limit enforcement and per-tenant rate limiting (~60 req/min).
  • Driven by a local change_tracker table that stamps every mutation with device + tenant ID.
  • Staggered cadence: core tables every 5 min, attendance/homework every 10 min, question bank every 30 min.
  • Last-write-wins with a smart merge for exam questions; WhatsApp logs and payments excluded.
  • 401/403 transparently triggers tenant re-authentication / token refresh.

LAN Sync (peer-to-peer)

  • WebSocket sync server on port 8082 + UDP broadcast discovery on port 8083.
  • Shared-secret pairing between devices; periodic 30 s sync; full database export/import merge; coordinated workspace reset.
  • Lets a center's devices stay consistent even with no internet — feature-gated to higher plans.

7. Parent Web Dashboard

Next.js web portal (Supabase Auth + Realtime), fully Arabic RTL.

  • Phone-number login normalized to an internal email (201XXXXXXXXX@tutoring.local), tolerant of Arabic/Persian numerals; forced first-login password change.
  • Multi-child support — parents see only their own children (RLS-isolated); persistent student selector.
  • Overview: latest invoice + status, latest exam result, current-month attendance %, recent activity feed.
  • Payments: invoices by student/year — gross, discount, net, method, status; totals paid vs remaining.
  • Exams: results list + score-trend chart, stats (count, average, highest, #rank-1), color-coded performance, per-exam score/time/rank.
  • Attendance: monthly calendar with present/late/absent + summary.
  • Homework: assignments calendar.
  • Web Push (VAPID): service-worker push subscription with mobile permission prompt, notification bell, and preferences; auto-cleanup of stale subscriptions server-side.
  • Realtime: Supabase channels auto-refresh on invoice changes.

8. Landing Site, Billing & Owner Admin Console

A single Next.js app serving three audiences.

Public Marketing Site (AR/EN)

Home (hero, stats, feature cards, how-it-works, pricing, testimonials, FAQ, CTA), features, pricing, terms, privacy. All copy, branding, SEO metadata, social links, analytics IDs, and download URLs are editable from the admin CMS (site_settings table) — no redeploy needed.

Tenant Self-Service

  • Signup creates a Supabase auth user → invokes the tenant-signup Edge Function → provisions the tenant + a 14-day trial → returns a time-limited connection code (TM-XXXX, 72 h) used to link the desktop/mobile app.
  • Welcome page with the connection code and platform download links; dashboard with subscription status.
  • Subscribe / manage / cancel via the billing provider (see §12).

Owner Admin Console (/admin, auth-protected)

SectionCapabilities
DashboardKPI cards (total tenants, active subscriptions, MRR, new signups) + monthly-signups area chart
TenantsSearch; table with usage; detail page (subscription, usage metrics, billing-events history) with actions: extend trial (+14 d), suspend, activate
SubscriptionsFilter by lifecycle (active / trialing / past_due / canceled)
Plans editorInline-edit prices (monthly/yearly EGP), limits (students/groups/employees/questions/WhatsApp) and feature toggles (cloud sync, parent dashboard, WhatsApp, LAN sync, backup, reports)
RevenueMRR, churn trend, monthly revenue line chart, plan-distribution pie
Settings (CMS)Contact, branding (AR/EN), SEO, hero & CTA copy, social, analytics, app download URLs, password change

9. WhatsApp Messaging Microservice

A standalone Node service that sends WhatsApp messages to parents on the platform's behalf.

  • Stack: Express + @whiskeysockets/baileys (WhatsApp Web), qrcode, pino.
  • Endpoints: /health, /status, /qr (base64 PNG pairing code surfaced inside the Flutter app), /send (single, 24 h dedupe, optional scheduled notBefore), /send-bulk (batch + per-recipient results), /disconnect.
  • Auth: x-api-key with constant-time comparison; the service refuses to boot without a token.
  • Reliability: FIFO send queue with jittered delays (anti-throttling), max-queue cap (HTTP 429 when full), in-memory deduplication, auto-reconnect, and a persistent auth-state volume.
  • Deployment: Docker + Fly.io (fly.toml) / PM2.
  • Consumers: the daily-parent-summary and send-parent-notification Edge Functions.

10. Backend — Supabase Platform

Edge Functions (Deno)

FunctionPurpose
tenant-signupProvision tenant + 14-day trial, generate connection code, auto-confirm email
cloud-syncWrite sync (insert/update/delete) with server-side plan-limit enforcement + rate limiting
cloud-sync-readIncremental read sync with a since cursor across core tables
create-checkout(Stripe, legacy) create checkout session
create-portal-session(Stripe, legacy) customer billing portal
stripe-webhook(Stripe, legacy) idempotent event handling → billing_events
check-trial-expiryCron — downgrade expired trials to free
daily-parent-summaryCron (Cairo midnight) — attendance/exam/invoice summaries via WhatsApp + in-app
send-parent-notificationCreate in-app parent notification (by parent_id or phone)
dispatch-parent-web-pushDeliver VAPID web push; prune stale (404/410) subscriptions
upsert-parent-accountCreate/link parent auth account, normalize Egyptian phone numbers, optional credential send
reset-parent-passwordIssue temp password, set must_change_password, bump credentials_version

Scheduled Jobs (pg_cron)

  • Trial-expiry downgrade.
  • Daily parent summaries (Cairo timezone).

Data Model Highlights

  • Tenant isolation: tenant_id on every business table; RLS via get_current_tenant_id() derived from the JWT; Edge Functions perform privileged service-role writes.
  • SaaS tables: tenants, subscriptions, plans, billing_events, usage_metrics, admin_users, site_settings.
  • Billing (Paymob): payment_cards (saved card tokens for auto-renew), payment_transactions (charge ledger: initial + renewal, order/transaction IDs, status).
  • Academic (tenant-scoped): students, groups, employees, invoices, exam_results, attendance, homework, question_bank.
  • Parent stack: parents (phone-normalized, auth_uid, notification flag), parent_notifications (6 types), parent_push_subscriptions (VAPID keys), whatsapp_log.

11. Subscription Model & Plan Gating

Plans are stored in the plans table and gated twice — client-side at the point of creation and server-side inside cloud-sync — so limits can't be bypassed by tampering with the app.

PlanEGP/moStudentsGroupsEmployeesQuestionsWhatsApp/moCloud syncParent dashWhatsAppLAN syncBackupReports
Free030301000basic
Basic199150103500100full
Pro399full

New tenants start on a 14-day trial. Subscription lifecycle: trialing → active → past_due → canceled / expired, with automatic downgrade-to-free on trial expiry via cron.


12. Billing Integration (Stripe → Paymob)

The platform is migrating its payment provider from Stripe to Paymob (chosen for the Egyptian market: card auto-renew plus wallet / InstaPay flows, with WhatsApp payment reminders).

  • Paymob (new): live DB schema (payment_cards, payment_transactions, payment_provider, payment_method, auto_renew), a client library implementing the Intention API, EGP→piasters conversion, and HMAC webhook verification. Saved card tokens enable automatic renewal.
  • Stripe (legacy): checkout, customer portal, and webhook handling still present during the transition.
  • The architecture cleanly abstracts the provider behind the subscriptions / billing_events tables, so the cutover is contained.

13. Security & Multi-Tenancy

  • Row Level Security on all tenant data, keyed off the JWT — no cross-tenant leakage.
  • No service-role key on device — the app uses a scoped, revocable sync token; a 401/403 forces re-auth.
  • PIN hashing (SHA-256 + salt), biometric gate, and 5-attempt lockout.
  • Exam integrity — IP-bound session tokens, tab-switch/screenshot detection, watermarking, heartbeat watchdog.
  • Idempotent billing webhooks (dedupe via provider event ID) and a full billing_events audit log.
  • Non-blocking root/jailbreak detection at startup.
  • WhatsApp relay protected by constant-time API-key comparison; SQLCipher-ready local storage.

14. Engineering Practices

  • Clean Architecture (data / domain / presentation) with the BLoC pattern and Either<Failure, Success> error handling.
  • Dependency injection via get_it + injectable codegen (~124 registered services).
  • Monorepo managed with Melos (unified bootstrap, analyze, test, format, build_runner).
  • Versioned SQLite migrations (schema v16) run automatically at startup.
  • Testing: Flutter unit + widget + integration tests (mocktail, bloc_test); Playwright E2E for the parent dashboard; Vitest unit tests for the landing app.
  • 15 business rules (BL-01 … BL-15) implemented and documented.
  • Internationalization with .arb files and a JSON i18n layer on the web; RTL-aware everywhere.

15. Resume / Portfolio Highlights

Concise bullets you can drop straight into a portfolio or CV.

  • Built a multi-tenant SaaS serving four client surfaces (cross-platform Flutter app, two Next.js web apps, a Node microservice) from a single Supabase backend, with Postgres Row Level Security for tenant isolation.
  • Engineered an offline-first mobile/desktop app with versioned local SQLite, a change-tracking sync engine, and dual synchronization — cloud (Supabase Edge Functions) and peer-to-peer LAN (WebSocket + UDP discovery).
  • Designed and implemented an in-classroom digital exam engine: an embedded HTTP/WebSocket server delivering randomized, watermarked exams to students' phones over local Wi-Fi, with live teacher controls and anti-cheat (IP-bound sessions, tab-switch detection, heartbeat watchdog).
  • Delivered a subscription billing system with tiered plans, free trials, server-enforced feature/usage gating, and a payment-provider migration from Stripe to Paymob (Intention API + HMAC verification + saved-card auto-renew).
  • Created a parent engagement layer: a real-time web dashboard with Web Push (VAPID) and an automated WhatsApp notification pipeline (Baileys) with deduplication, queueing, and scheduled daily summaries via pg_cron.
  • Shipped a complete owner admin console — tenant management, plan editor, MRR/churn/revenue analytics, and a content-managed marketing site.
  • Full Arabic/English RTL localization across every application.

Stack at a glance: Flutter · Dart · BLoC · Next.js · React · TypeScript · Tailwind · Supabase (Postgres, Edge Functions/Deno, RLS, Realtime, pg_cron) · Node.js · Express · Baileys · Stripe / Paymob · Web Push (VAPID) · SQLite/SQLCipher · Playwright · Vitest · Melos · Docker · Fly.io.

// Gallery

WhatsApp