Home / Portfolio / Educore - E-Learning Kursverwaltungsplattform
Full Stack

Educore - E-Learning Kursverwaltungsplattform

March 2026 1 months Full Stack Developer & DevOps Engineer

Overview

Educore is a production-ready e-learning platform that enables educational institutions to manage courses and handle online enrollments efficiently. The platform provides a clean REST API, a responsive Bootstrap frontend, and fully automated deployment on Coolify with Traefik reverse proxy and automatic SSL certificates. Key capabilities include: - Course management with capacity tracking - Self-service participant enrollment - Token-based authentication - Automatic duplicate enrollment prevention - Real-time course availability updates - PostgreSQL database with row-level locking - Docker containerization with multi-service orchestration - Traefik reverse proxy with Let's Encrypt SSL - Complete API documentation via Swagger/OpenAPI

The Challenge

Educational institutions struggle with manual course registration processes that are error-prone, time-consuming, and lack real-time visibility into course capacities. Administrators waste hours managing spreadsheets and handling duplicate registrations. Participants face frustration when courses are overbooked or when they can't easily see available options. The main challenges include: - Manual enrollment processes leading to overbooking - No real-time visibility of course availability - Duplicate registrations wasting administrative time - Difficult for participants to discover and enroll in courses - Lack of integration between course catalogs and enrollment systems - No automated capacity management

The Solution

Educore solves these challenges by providing a complete digital platform for course management and enrollment. Administrators can easily create and manage courses through Django's admin interface. Participants can browse courses, check real-time availability, and self-enroll through an intuitive Bootstrap frontend. Technical Approach: 1. Django REST Framework for robust API development 2. PostgreSQL with row-level locking for concurrent enrollment handling 3. Token-based authentication for secure API access 4. Nginx serving static files with API proxying 5. Traefik reverse proxy with automatic SSL certificate generation 6. Docker multi-container orchestration on Coolify 7. Bootstrap 5 responsive frontend with vanilla JavaScript 8. Business logic validation at both view and model layers

Technical Implementation

Enrollment Business Logic with Double Validation

Implementation of course enrollment logic with capacity checking and duplicate prevention at both view and model layers for maximum data integrity.

PYTHON
class Anmeldung(models.Model):
    def clean(self):
        if self.status == 'angemeldet':
            self._prevent_duplicate_enrollment()
            self._check_course_capacity()
    
    def _check_course_capacity(self):
        if self.kurs.ist_voll:
            raise ValidationError(
                f"Der Kurs '{self.kurs.titel}' ist bereits ausgebucht "
                f"(max. {self.kurs.max_teilnehmer} Teilnehmer)."
            )

class AnmeldungCreateView(APIView):
    def post(self, request):
        teilnehmer, created = Teilnehmer.objects.get_or_create(
            email=data['email'],
            defaults={'vorname': data['vorname'], 'nachname': data['nachname']}
        )
        
        if Anmeldung.objects.filter(kurs=kurs, teilnehmer=teilnehmer, status='angemeldet').exists():
            return Response({'error': 'Bereits angemeldet'}, status=status.HTTP_409_CONFLICT)
        
        anmeldung = Anmeldung.objects.create(kurs=kurs, teilnehmer=teilnehmer)
        return Response(AnmeldungSerializer(anmeldung).data, status=status.HTTP_201_CREATED)

Course Capacity Property with Active Enrollment Counting

Dynamic course capacity calculation that only counts active (non-cancelled) enrollments for accurate availability tracking.

PYTHON
class Kurs(models.Model):
    @property
    def verfuegbare_plaetze(self):
        aktive_anmeldungen = self.anmeldungen.filter(status='angemeldet').count()
        return self.max_teilnehmer - aktive_anmeldungen
    
    @property
    def ist_voll(self):
        return self.verfuegbare_plaetze <= 0
    
    @property
    def anzahl_anmeldungen(self):
        return self.anmeldungen.filter(status='angemeldet').count()

Docker Compose Multi-Service Orchestration

Complete Docker Compose configuration for PostgreSQL, Django backend, and Nginx frontend with healthchecks and network isolation.

YAML
version: '3.8'
services:
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: ${DB_NAME:-educore}
      POSTGRES_USER: ${DB_USER:-educore_user}
      POSTGRES_PASSWORD: ${DB_PASSWORD:-educore_password}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-educore_user}"]
      interval: 10s
      timeout: 5s
      retries: 5

  backend:
    build: ./backend
    environment:
      - SECRET_KEY=${SECRET_KEY}
      - DEBUG=False
      - ALLOWED_HOSTS=${ALLOWED_HOSTS}
      - DB_HOST=postgres
    depends_on:
      postgres:
        condition: service_healthy
    expose:
      - "8100"

  frontend:
    build: ./frontend
    depends_on:
      - backend
    ports:
      - "80:80"

Frontend API Integration with Token Authentication

Vanilla JavaScript implementation of token-based authentication and API calls with localStorage persistence.

JAVASCRIPT
// api.js
async function apiRequest(endpoint, method = 'GET', token = null, data = null) {
    const headers = { 'Content-Type': 'application/json' };
    if (token) headers['Authorization'] = `Token ${token}`;
    
    const response = await fetch(endpoint, {
        method, headers,
        body: data ? JSON.stringify(data) : null
    });
    
    if (!response.ok) throw await response.json();
    return response.json();
}

// auth.js
async function login(username, password) {
    const response = await apiRequest('/api-token-auth/', 'POST', null, { username, password });
    localStorage.setItem('auth_token', response.token);
    return response;
}

function getToken() {
    return localStorage.getItem('auth_token');
}

Nginx Reverse Proxy Configuration

Nginx configuration for serving static files and proxying API requests to the Django backend.

server {
    listen 80;
    server_name educore.smarta.website;
    root /usr/share/nginx/html;
    index index.html;

    location /api/ {
        proxy_pass http://backend:8100/api/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /admin/ {
        proxy_pass http://backend:8000/admin/;
    }

    location /api-token-auth/ {
        proxy_pass http://backend:8000/api-token-auth/;
    }

    location / {
        try_files $uri $uri/ /index.html;
    }
}