Qodrateman: A Full-Stack E-Learning Platform with AI Quiz Generation.

python dev.to

I'm Karim Khamis, a full-stack developer and AI/ML researcher based in Cairo, Egypt. This is the full story of how I built Qodrateman — a production e-learning platform now live at qodrateman.com.

This isn't a tutorial project. It's a real platform serving real students across 12+ courses, with instructor and learner workflows, JWT authentication, role-based access control, and an AI feature that reduces quiz creation time from 20 minutes to under 30 seconds.


What is Qodrateman?

Qodrateman is a full-stack e-learning platform built for the Arabic-speaking market. It provides:

  • Structured courses with instructor and learner role separation
  • JWT authentication with Role-Based Access Control (RBAC)
  • AI-assisted quiz generation — instructors describe a topic and receive a complete quiz in under 30 seconds
  • Full content management for 12+ courses
  • Deployed on Vercel (frontend) and Render (backend) with zero downtime

The Stack and Why I Chose It

Frontend: React + TypeScript + Tailwind CSS

React was the right call for a platform where UI state is complex — which course is active, which lesson is playing, what the user's progress is. TypeScript caught dozens of bugs before they reached production. Tailwind made responsive design fast without writing custom CSS.

Backend: Django REST Framework

DRF is the best choice I know for building REST APIs quickly without sacrificing quality. The combination of serializers, viewsets, and the built-in admin panel gave me a fully functional backend in a fraction of the time it would take to build from scratch.

Database: PostgreSQL

The data in an e-learning platform is deeply relational — users, courses, lessons, enrollments, quiz attempts. PostgreSQL handles this cleanly. SQLite is fine for development but never for production.

Authentication: JWT with djangorestframework-simplejwt

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
}
Enter fullscreen mode Exit fullscreen mode

JWT tokens keep the frontend and backend fully decoupled. The access token lives in memory (not localStorage — that's a security risk). The refresh token handles silent re-authentication.

Deployment: Vercel + Render

Vercel for the React frontend — zero config, instant deploys on every push. Render for the Django backend — free tier works for early-stage, scales easily. Total deployment setup time: under 2 hours.


The Feature I'm Most Proud Of: AI Quiz Generation

The biggest pain point instructors told me about was quiz creation. Writing good multiple-choice questions is time-consuming — it took instructors around 20 minutes per quiz.

I built an AI-assisted quiz generation feature that solves this completely.

How it works:

  1. Instructor describes the topic and difficulty level
  2. The system sends a structured prompt to the AI API
  3. The API returns a complete quiz with questions, options, and correct answers in JSON format
  4. The platform parses the response and saves it directly to the database
  5. The instructor reviews and publishes in one click

Result: quiz creation time dropped from ~20 minutes to under 30 seconds.

The key to making this reliable was the structured prompt:

def generate_quiz_prompt(topic, num_questions, difficulty):
    return f"""
    Generate a quiz about: {topic}
    Number of questions: {num_questions}
    Difficulty: {difficulty}

    Respond ONLY with valid JSON in this exact format:
    {{
        "questions": [
            {{
                "question": "question text",
                "options": ["A", "B", "C", "D"],
                "correct_answer": "A",
                "explanation": "why this is correct"
            }}
        ]
    }}
    Do not include any text outside the JSON.
    """
Enter fullscreen mode Exit fullscreen mode

Forcing JSON output and validating the response before saving was the most important engineering decision here. Early versions would occasionally return malformed responses — strict output format constraints fixed this completely.


Role-Based Access Control

Qodrateman has two distinct user types — instructors and learners — with completely different capabilities.

# models.py
class UserProfile(models.Model):
    ROLES = [
        ('instructor', 'Instructor'),
        ('learner', 'Learner'),
    ]
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    role = models.CharField(max_length=20, choices=ROLES)

# permissions.py
class IsInstructor(BasePermission):
    def has_permission(self, request, view):
        return (
            request.user.is_authenticated and
            request.user.userprofile.role == 'instructor'
        )
Enter fullscreen mode Exit fullscreen mode

This permission class then protects every instructor-only endpoint — course creation, quiz generation, student progress visibility. Learners can only read published content and submit their own quiz attempts.


What Broke and How I Fixed It

Problem 1: N+1 query problem in course listings

The course listing API was slow. Every course card needed the instructor name, lesson count, and enrollment count — three separate database queries per course. With 12+ courses, that's 36+ queries per page load.

Fix: Django's select_related and annotate:

courses = Course.objects.select_related('instructor').annotate(
    lesson_count=Count('lessons'),
    enrollment_count=Count('enrollments')
)
Enter fullscreen mode Exit fullscreen mode

One query. Page load time dropped by 70%.

Problem 2: AI responses were inconsistent

Early AI quiz generation would sometimes return extra text around the JSON, making json.loads() fail.

Fix: Wrap parsing in a try/except and strip everything before the first { and after the last }:

def parse_ai_response(response_text):
    try:
        start = response_text.index('{')
        end = response_text.rindex('}') + 1
        return json.loads(response_text[start:end])
    except (ValueError, json.JSONDecodeError):
        raise ValidationError("AI response could not be parsed")
Enter fullscreen mode Exit fullscreen mode

Problem 3: Render backend cold starts

Render's free tier spins down inactive services. The first request after inactivity takes 30+ seconds — terrible UX.

Fix: A simple ping endpoint that a Vercel cron job hits every 14 minutes to keep the service warm. Cost: zero. Result: no more cold starts for active users.


Key Metrics

  • 12+ courses live on the platform
  • Quiz generation time: from ~20 minutes to under 30 seconds
  • 500+ authenticated users supported with JWT auth and RBAC
  • Zero downtime since launch on Vercel + Render
  • Zero post-launch rollbacks

What I Would Do Differently

  1. Add React Query from day one. Managing server state with raw useEffect and useState gets messy fast. React Query handles caching, refetching, and loading states much more cleanly.

  2. Plan the permission model before writing any code. I refactored RBAC twice because I hadn't thought through all the edge cases — can instructors see other instructors' content? Can learners see unenrolled course previews? Draw this out first.

  3. Use Docker locally from the start. "Works on my machine" is a real problem. Docker Compose for local development makes deployment much smoother.


My Other Projects

If you're interested in AI/ML work, I'm also building Letra — a custom-trained OCR mobile app for iOS and Android using TensorFlow, Keras, PaddleOCR, and OpenCV. Currently at 98% English accuracy on 800+ labeled samples, deployed to TestFlight and Google Play Beta. Arabic OCR is in active iteration targeting 85%+ accuracy.


Conclusion

Qodrateman taught me that the hardest part of building a real product isn't the code — it's the decisions you make before you write any code. Schema design, permission models, deployment architecture. Get these right first and the code almost writes itself.

If you're building something similar or have questions about the Django + React stack, drop a comment. I'm happy to help.


About the author:
Karim Khamis is a full-stack developer and AI/ML researcher based in Cairo, Egypt. He holds a B.Sc. in Software Engineering from Ain Shams University and is pursuing an M.Sc. at AASTMT researching OCR and multilingual document processing. He has delivered 30+ client projects with a 100% on-time delivery rate and is available for freelance and full-time roles worldwide.

🌐 Portfolio: karimkhamis.com
🚀 Qodrateman: qodrateman.com
🐙 GitHub: github.com/karim-99-99
💼 LinkedIn: linkedin.com/in/kareem-khamis
📧 Email: kareemkhamis2030@gmail.com

Read Full Tutorial open_in_new
arrow_back Back to Tutorials