Data Models (ERD)
Data Models (ERD)
Overview
This document describes the entity-relationship diagram (ERD) and data models for the Learnille platform.
Database Schema
Core Entities
User Management
-- Users tableCREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email VARCHAR(255) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, first_name VARCHAR(100), last_name VARCHAR(100), avatar_url VARCHAR(500), bio TEXT, role VARCHAR(50) NOT NULL DEFAULT 'student', -- student, instructor, admin is_active BOOLEAN DEFAULT true, email_verified BOOLEAN DEFAULT false, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());
-- User profiles table (extended information)CREATE TABLE user_profiles ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE CASCADE, phone VARCHAR(20), location VARCHAR(255), website VARCHAR(255), social_links JSONB, preferences JSONB, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());Course Management
-- Categories tableCREATE TABLE categories ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(100) NOT NULL, slug VARCHAR(100) UNIQUE NOT NULL, description TEXT, parent_id UUID REFERENCES categories(id), is_active BOOLEAN DEFAULT true, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());
-- Courses tableCREATE TABLE courses ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), title VARCHAR(255) NOT NULL, slug VARCHAR(255) UNIQUE NOT NULL, description TEXT, short_description VARCHAR(500), thumbnail_url VARCHAR(500), instructor_id UUID REFERENCES users(id) ON DELETE CASCADE, category_id UUID REFERENCES categories(id), level VARCHAR(50) DEFAULT 'beginner', -- beginner, intermediate, advanced language VARCHAR(10) DEFAULT 'en', price DECIMAL(10,2) DEFAULT 0, currency VARCHAR(3) DEFAULT 'USD', is_published BOOLEAN DEFAULT false, is_featured BOOLEAN DEFAULT false, enrollment_count INTEGER DEFAULT 0, rating DECIMAL(3,2) DEFAULT 0, review_count INTEGER DEFAULT 0, duration_hours INTEGER, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());
-- Course sectionsCREATE TABLE course_sections ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), course_id UUID REFERENCES courses(id) ON DELETE CASCADE, title VARCHAR(255) NOT NULL, description TEXT, order_index INTEGER NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());
-- Course lessonsCREATE TABLE course_lessons ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), section_id UUID REFERENCES course_sections(id) ON DELETE CASCADE, title VARCHAR(255) NOT NULL, description TEXT, content_type VARCHAR(50) NOT NULL, -- video, text, quiz, assignment content_url VARCHAR(500), content_text TEXT, duration_minutes INTEGER, order_index INTEGER NOT NULL, is_preview BOOLEAN DEFAULT false, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());Enrollment and Progress
-- Enrollments tableCREATE TABLE enrollments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE CASCADE, course_id UUID REFERENCES courses(id) ON DELETE CASCADE, enrollment_date TIMESTAMP WITH TIME ZONE DEFAULT NOW(), completion_date TIMESTAMP WITH TIME ZONE, progress_percentage DECIMAL(5,2) DEFAULT 0, is_completed BOOLEAN DEFAULT false, certificate_issued BOOLEAN DEFAULT false, UNIQUE(user_id, course_id));
-- Lesson progressCREATE TABLE lesson_progress ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), enrollment_id UUID REFERENCES enrollments(id) ON DELETE CASCADE, lesson_id UUID REFERENCES course_lessons(id) ON DELETE CASCADE, is_completed BOOLEAN DEFAULT false, completed_at TIMESTAMP WITH TIME ZONE, time_spent_minutes INTEGER DEFAULT 0, last_accessed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(enrollment_id, lesson_id));Consultation System
-- Consultation typesCREATE TABLE consultation_types ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(100) NOT NULL, description TEXT, is_active BOOLEAN DEFAULT true);
-- Consultations tableCREATE TABLE consultations ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), title VARCHAR(255) NOT NULL, description TEXT, instructor_id UUID REFERENCES users(id) ON DELETE CASCADE, consultation_type_id UUID REFERENCES consultation_types(id), category_id UUID REFERENCES categories(id), thumbnail_url VARCHAR(500), price DECIMAL(10,2) DEFAULT 0, currency VARCHAR(3) DEFAULT 'USD', duration_minutes INTEGER, max_participants INTEGER DEFAULT 1, is_published BOOLEAN DEFAULT false, is_available BOOLEAN DEFAULT true, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());
-- Consultation bookingsCREATE TABLE consultation_bookings ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), consultation_id UUID REFERENCES consultations(id) ON DELETE CASCADE, student_id UUID REFERENCES users(id) ON DELETE CASCADE, scheduled_at TIMESTAMP WITH TIME ZONE NOT NULL, status VARCHAR(50) DEFAULT 'pending', -- pending, confirmed, completed, cancelled meeting_url VARCHAR(500), notes TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());Payment System
-- Payment methodsCREATE TABLE payment_methods ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE CASCADE, type VARCHAR(50) NOT NULL, -- card, paypal, bank_transfer provider VARCHAR(50) NOT NULL, -- stripe, paypal provider_payment_method_id VARCHAR(255), last_four VARCHAR(4), expiry_month INTEGER, expiry_year INTEGER, is_default BOOLEAN DEFAULT false, is_active BOOLEAN DEFAULT true, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());
-- Payments tableCREATE TABLE payments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE CASCADE, payment_method_id UUID REFERENCES payment_methods(id), amount DECIMAL(10,2) NOT NULL, currency VARCHAR(3) DEFAULT 'USD', status VARCHAR(50) DEFAULT 'pending', -- pending, processing, completed, failed, refunded provider VARCHAR(50) NOT NULL, provider_payment_id VARCHAR(255), description VARCHAR(255), metadata JSONB, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());
-- Invoices tableCREATE TABLE invoices ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE CASCADE, payment_id UUID REFERENCES payments(id), invoice_number VARCHAR(100) UNIQUE NOT NULL, amount DECIMAL(10,2) NOT NULL, currency VARCHAR(3) DEFAULT 'USD', status VARCHAR(50) DEFAULT 'unpaid', -- unpaid, paid, overdue, cancelled due_date DATE, paid_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());Reviews and Ratings
-- Reviews tableCREATE TABLE reviews ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE CASCADE, course_id UUID REFERENCES courses(id) ON DELETE CASCADE, rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5), title VARCHAR(255), comment TEXT, is_verified BOOLEAN DEFAULT false, -- verified purchase helpful_count INTEGER DEFAULT 0, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(user_id, course_id));
-- Review responses (instructor replies)CREATE TABLE review_responses ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), review_id UUID REFERENCES reviews(id) ON DELETE CASCADE, instructor_id UUID REFERENCES users(id) ON DELETE CASCADE, response TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());Entity Relationship Diagram
βββββββββββββββββββ ββββββββββββββββββββ users β β user_profiles ββββββββββββββββββββ ββββββββββββββββββββ id (PK) β1ββββ1β id (PK) ββ email β β user_id (FK) ββ password_hash β β phone ββ first_name β β location ββ last_name β β website ββ role β β social_links ββ is_active β β preferences ββββββββββββββββββββ βββββββββββββββββββ β β ββββββ΄βββββ β ββββββΌββββ βββββΌβββββcoursesβ βreviews ββββββββββ ββββββββββid (PK)β βid (PK) ββtitle β βuser_idββinstructorββcourse_idββcategoryβ βrating ββprice β βcommentββββββ¬ββββ βββββββββ β ββββββΌββββββenrollmentsββββββββββββββid (PK) ββuser_id ββcourse_id ββprogress ββcompleted ββββββ¬ββββββ β ββββββΌββββββββlesson_progressββββββββββββββββββid (PK) ββenrollment_id ββlesson_id ββcompleted ββtime_spent βββββββββββββββββKey Relationships
One-to-One Relationships
- User β User Profile
- Payment β Invoice
One-to-Many Relationships
- User β Courses (as instructor)
- User β Enrollments
- User β Reviews
- User β Payments
- User β Payment Methods
- Course β Course Sections
- Course Section β Course Lessons
- Course β Reviews
- Enrollment β Lesson Progress
- Consultation β Consultation Bookings
Many-to-Many Relationships
- Users β Courses (through Enrollments)
- Users β Consultations (through Bookings)
Indexes
-- Performance indexesCREATE INDEX idx_users_email ON users(email);CREATE INDEX idx_users_role ON users(role);CREATE INDEX idx_courses_instructor ON courses(instructor_id);CREATE INDEX idx_courses_category ON courses(category_id);CREATE INDEX idx_courses_published ON courses(is_published);CREATE INDEX idx_enrollments_user ON enrollments(user_id);CREATE INDEX idx_enrollments_course ON enrollments(course_id);CREATE INDEX idx_reviews_course ON reviews(course_id);CREATE INDEX idx_reviews_rating ON reviews(rating);CREATE INDEX idx_payments_user ON payments(user_id);CREATE INDEX idx_payments_status ON payments(status);Data Constraints
- Email uniqueness across users
- Course slug uniqueness
- Enrollment uniqueness per user-course pair
- Rating values between 1-5
- Positive price values
- Future dates for scheduled consultations
- Non-negative progress percentages
Data Migration Strategy
- Initial Schema: Create all tables with basic structure
- Seed Data: Populate reference data (categories, consultation types)
- Data Migration: Migrate existing data if applicable
- Index Creation: Add performance indexes after data loading
- Constraint Addition: Add foreign key constraints after data validation
Backup and Recovery
- Daily automated backups of PostgreSQL database
- Point-in-time recovery capability
- Cross-region backup replication
- Regular backup testing and validation