EduAssess
A multi-tenant educational assessment platform designed for universities, corporate training, and certification bodies. Built to handle secure remote examinations across unreliable infrastructure — with anti-cheating enforcement, cross-platform lockdown, and offline-first resilience that keeps students' answers safe no matter what happens.
Why I Built It
Egyptian universities spend millions on platforms like Blackboard and ProctorU. These platforms are designed for stable Western infrastructure — always-on broadband, reliable webcams, modern hardware. That doesn't reflect reality for most institutions in the region.
EduAssess was built from day one to solve exam delivery under hostile conditions: intermittent internet, students on budget Android phones, institutions that need proctoring but can't afford $10/student licensing fees. Every architectural decision traces back to this constraint.
This is not a graduation project. It's a production system serving real users, with real billing, and real data isolation between institutions.
Architecture
text┌─────────────────────────────────────────────────────────────┐ │ NGINX REVERSE PROXY │ │ (SSL termination) │ ├─────────────┬─────────────────┬─────────────────────────────┤ │ Web Client │ Desktop Client │ Mobile Client │ │ (Browser) │ (Electron) │ (React Native) │ ├─────────────┴─────────────────┴─────────────────────────────┤ │ REST API v2 (PHP 8.3) │ │ ┌──────────────────────────┐ │ │ │ Authentication Layer │ │ │ │ (Session + TOTP 2FA) │ │ │ ├──────────────────────────┤ │ │ │ RBAC Authorization │ │ │ │ (SaaS → Org → Prof) │ │ │ ├──────────────────────────┤ │ │ │ Multi-Tenant Scoping │ │ │ │ (org_id isolation) │ │ │ └──────────────────────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ PostgreSQL 16 (JSONB + RLS) │ │ ┌──────────────────────────┐ │ │ │ organizations │ │ │ │ users (org_id scoped) │ │ │ │ exams & sessions │ │ │ │ proctoring_events │ │ │ └──────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘
Anti-Cheating Pipeline
The proctoring system operates as a state machine with multiple detection layers running simultaneously:
Browser Lockdown (Web)
- Intercepts
Alt-Tab,Ctrl+W,Ctrl+Tab,F11, right-click, and dev tools shortcuts - Monitors
document.visibilityState— any tab switch triggers a violation event - Blocks clipboard operations during active exam sessions
- Forces fullscreen mode and detects exits
Desktop Lockdown (Electron)
- OS-level keyboard hook blocks
Alt+F4,Winkey, and task manager shortcuts - Process monitoring kills unauthorized applications
- Kiosk mode prevents desktop access entirely
- Blocks external monitors and screen sharing
Webcam Monitoring
- TensorFlow.js face detection runs locally in the browser
- Flags: no face detected, multiple faces, face turned away
- Snapshots uploaded to
POST /proctoring/snapshotat configurable intervals - All violations logged with timestamps for instructor review
Violation Severity Engine
Level 1 (Warning): Tab switch, brief face absence
Level 2 (Alert): Multiple tab switches, screen resize, dev tools
Level 3 (Auto-submit): Process tampering, kiosk escape, sustained face absence
Each violation is logged to the proctoring_events table with a timestamp, severity level, and raw event data. Instructors see a real-time violation feed during live exams.
Offline-First Answer Syncing
This is the critical differentiator. In environments where internet drops mid-exam, students cannot lose their work.
Dual Persistence Pattern:
- Every answer keystroke writes to IndexedDB first (local, instant)
- A background sync worker attempts
PUT /session/{id}/answerevery few seconds - If the network fails, answers accumulate locally
- When connectivity returns, the sync worker replays all queued writes
- Server resolves conflicts by timestamp — latest answer wins
Heartbeat System:
- Client sends
POST /sync/heartbeatevery 30 seconds - Server responds with remote commands: "Force Submit", "Extend Time", "Send Warning"
- If heartbeat stops for >2 minutes, the proctor dashboard flags the student as "disconnected"
php<?php declare(strict_types=1); // Exam session state machine: pending → in_progress → submitted → graded $stmt = $pdo->prepare(" UPDATE exam_sessions SET status = 'submitted', submitted_at = NOW(), answers = :answers WHERE id = :session_id AND student_id = :student_id AND status = 'in_progress' "); $stmt->execute([ 'answers' => json_encode($answersFromIndexedDB), 'session_id' => $sessionId, 'student_id' => $currentUser->id, ]);
Multi-Tenant Data Isolation
Every database query is scoped by org_id. There is no way for Organization A to access Organization B's data — not through the API, not through the UI, not through SQL injection. The scoping is enforced at the query layer, not just the application layer.
4-Tier RBAC:
| Role | Scope | Capabilities |
|---|---|---|
| SaaS Owner | Global | Manage all organizations, billing, system config |
| Org Admin | Single organization | Manage professors, students, settings |
| Professor | Own courses | Create exams, view results, proctor sessions |
| Student | Own sessions | Take exams, view grades |
API v2
RESTful JSON API at /api/v2/* powering all client applications:
| Endpoint | Purpose |
|---|---|
POST /auth/login | Returns temp_token if 2FA enabled, or access_token |
POST /session/start | Validates device, locks the exam seat |
PUT /session/{id}/answer | Granular auto-save every few seconds |
POST /sync/heartbeat | "I am alive" signal; receives remote commands |
POST /proctoring/snapshot | Uploads webcam frame |
POST /proctoring/violation | Reports local heuristic events |
Technical Stack
| Layer | Technology | Why |
|---|---|---|
| Backend | PHP 8.3 | Fast SSR, zero hydration overhead, PDO prepared statements |
| Database | PostgreSQL 16 | Row-level security, JSONB for flexible exam schemas |
| Web Client | Vanilla JS + Tailwind | No framework overhead for exam-taking UI |
| Desktop | Electron | OS-level lockdown capabilities |
| Mobile | React Native (Expo) | Cross-platform student access |
| Auth | Session + TOTP 2FA | QR code setup, time-based codes |
| Billing | Dodo Payments | Subscription management, free tier to enterprise |
| Brevo SMTP + Gmail IMAP | Outbound notifications + admin inbox |
Deployment
Docker Compose on AWS EC2 (Ubuntu 22.04). PostgreSQL, PHP-FPM, and Nginx run in separate containers. Deployed via a PowerShell script that SSHs in, uploads a tarball, and restarts services. Nginx Proxy Manager handles SSL and reverse proxying.
Impact
- Serves real university users with production uptime
- Handles concurrent exam sessions across multiple institutions
- Reduces proctoring costs by ~90% compared to commercial platforms
- Works on budget hardware and unreliable connections where competitors fail
Co-founded with Khaled Essam (CFO).