Entity Relationship Diagram

This document describes the EduNest LMS entity-relationship model. It focuses on the core LMS and commerce entities and the foreign keys you can verify directly in src/lib/lms-schema.ts and src/lib/vendor-schema.ts. All keys are SERIAL integers; relationships are enforced with PostgreSQL REFERENCES constraints.

Mermaid ERD

MERMAID
erDiagram
    customers ||--o| instructors : "is (account_type='instructor')"
    customers ||--o{ enrollments : "enrolls"
    customers ||--o{ transactions : "pays"
    customers ||--o{ wishlist : "saves"
    customers ||--o{ course_reviews : "writes"
    customers ||--o{ quiz_attempts : "attempts"
    customers ||--o{ conversations : "chats (learner)"

    instructors ||--o{ courses : "authors"
    instructors ||--o{ bundles : "authors"
    instructors ||--o{ instructor_earnings : "earns"
    instructors ||--o{ payouts : "withdraws"
    instructors ||--o{ conversations : "chats (instructor)"

    course_categories ||--o{ courses : "classifies"
    course_categories ||--o{ course_categories : "parent_of"

    courses ||--o{ sections : "has"
    sections ||--o{ lessons : "has"
    courses ||--o{ lessons : "has (course_id)"
    courses ||--o{ enrollments : "grants"
    courses ||--o{ course_reviews : "receives"
    courses ||--o{ quizzes : "includes"
    courses ||--o{ surveys : "includes"
    courses ||--o{ wishlist : "wished"

    bundles ||--o{ bundle_courses : "groups"
    courses ||--o{ bundle_courses : "in"

    enrollments ||--o{ lesson_progress : "tracks"
    lessons ||--o{ lesson_progress : "progress_for"

    quizzes ||--o{ quiz_questions : "has"
    quizzes ||--o{ quiz_attempts : "attempted_as"

    surveys ||--o{ survey_questions : "has"
    surveys ||--o{ survey_responses : "collects"

    todo_tasks ||--o{ todo_task_items : "has"

    transactions ||--o{ instructor_earnings : "splits"
    instructor_earnings }o--|| payouts : "paid_via"

    conversations ||--o{ messages : "contains"

    pricing_plans ||--o{ plan_change_requests : "from/to"

    blog_categories ||--o{ blogs : "classifies"

    customers {
        int id PK
        string slug UK
        string email
        string password_hash
        string account_type "student|instructor"
    }
    instructors {
        int id PK
        int customer_id FK "UNIQUE"
        string status "pending|approved|rejected|suspended"
        numeric revenue_share_pct
    }
    courses {
        int id PK
        string slug UK
        int instructor_id FK
        int category_id FK
        int price_cents
        string status "draft|pending|published|rejected|archived"
    }
    sections {
        int id PK
        int course_id FK
        int sort_order
    }
    lessons {
        int id PK
        int section_id FK
        int course_id FK
        string type
        string drip_type
    }
    bundles {
        int id PK
        string slug UK
        int instructor_id FK
        int price_cents
    }
    bundle_courses {
        int bundle_id FK
        int course_id FK
    }
    enrollments {
        int id PK
        int customer_id FK
        int course_id FK
        string source
        numeric progress_pct
    }
    lesson_progress {
        int id PK
        int enrollment_id FK
        int lesson_id FK
        boolean is_completed
    }
    transactions {
        int id PK
        int customer_id FK
        int amount_cents
        string status "pending|paid|failed|refunded"
    }
    instructor_earnings {
        int id PK
        int instructor_id FK
        int transaction_id FK
        int course_id FK
        int net_cents
        string status "pending|available|paid"
    }
    payouts {
        int id PK
        int instructor_id FK
        int amount_cents
        string status "requested|approved|paid|rejected"
    }
    coupons {
        int id PK
        string code UK
        string applies_to "ALL|PRODUCTS|CATEGORIES|COURSES"
    }
    course_reviews {
        int id PK
        int course_id FK
        int customer_id FK
        int rating
    }
    conversations {
        int id PK
        int learner_id FK
        int instructor_id FK
    }
    messages {
        int id PK
        int conversation_id FK
        string sender_role "learner|instructor"
    }
    blogs {
        int id PK
        string slug UK
        int category_id FK
    }

Entities

Entity Key fields Role
customers id, slug (UQ), account_type Learner or instructor account; central identity for the portal
instructors id, customer_id (UQ FK) Instructor profile (1:1 with a customer); approval + payout settings
course_categories id, slug (UQ), parent_id Self-nesting course taxonomy
courses id, slug (UQ), instructor_id, category_id A sellable course
sections id, course_id Ordered grouping of lessons
lessons id, section_id, course_id A learning item (video, text, quiz link, …)
bundles / bundle_courses id, slug (UQ) / PK (bundle_id, course_id) A package of courses
enrollments id, UQ (customer_id, course_id) Grants a learner access to a course
lesson_progress id, UQ (enrollment_id, lesson_id) Per-lesson completion + last position
transactions id, customer_id A course/bundle purchase (the order record)
instructor_earnings id, instructor_id, transaction_id Revenue-share ledger entry per sale
payouts id, instructor_id Instructor withdrawal request
coupons id, code (UQ) Discount code, scoped via applies_to + course_ids
course_reviews id, UQ (course_id, customer_id) Learner rating/review
quizzes / quiz_questions / quiz_attempts quiz_id, customer_id Assessment + a learner's attempts
surveys / survey_questions / survey_responses survey_id, customer_id Feedback collection
conversations / messages learner_id, instructor_id / conversation_id Learner↔instructor chat

Relationships

Relationship From → To Type Foreign key
Customer → Instructor profile customersinstructors one-to-one instructors.customer_id (UNIQUE)
Instructor → Courses instructorscourses one-to-many courses.instructor_id
Category → Courses course_categoriescourses one-to-many courses.category_id
Category → Subcategory course_categoriescourse_categories one-to-many (self) course_categories.parent_id
Course → Sections coursessections one-to-many sections.course_id
Section → Lessons sectionslessons one-to-many lessons.section_id
Course → Lessons courseslessons one-to-many lessons.course_id
Bundle ↔ Courses bundle_courses many-to-many bundle_id, course_id (composite PK)
Customer ↔ Course (access) enrollments many-to-many customer_id, course_id (UNIQUE pair)
Enrollment → Lesson progress enrollmentslesson_progress one-to-many lesson_progress.enrollment_id
Customer → Transactions customerstransactions one-to-many transactions.customer_id
Transaction → Earnings transactionsinstructor_earnings one-to-many instructor_earnings.transaction_id
Instructor → Earnings instructorsinstructor_earnings one-to-many instructor_earnings.instructor_id
Instructor → Payouts instructorspayouts one-to-many payouts.instructor_id
Quiz → Questions / Attempts quizzesquiz_questions / quiz_attempts one-to-many quiz_id
Survey → Questions / Responses surveyssurvey_questions / survey_responses one-to-many survey_id
Course → Reviews coursescourse_reviews one-to-many course_reviews.course_id (UQ with customer)
Conversation → Messages conversationsmessages one-to-many messages.conversation_id
Learner/Instructor → Conversation customers/instructorsconversations one-to-many (two roles) conversations.learner_id, conversations.instructor_id
Plan → Change requests pricing_plansplan_change_requests one-to-many (from/to) from_plan_id, to_plan_id
Blog category → Blogs blog_categoriesblogs one-to-many blogs.category_id

Add-on entities (certificates, exams, assignments, forums, organizations, affiliate, wallet, …) follow the same patterns and hang off customers / courses; see their src/product/addons/<id>/schema.ts files.


© CreativeCape Solutions · creative-cape.com · support@creative-cape.com