406 lines
14 KiB
SQL
406 lines
14 KiB
SQL
-- CreateEnum
|
|
CREATE TYPE "CourseStatus" AS ENUM ('DRAFT', 'PENDING_APPROVAL', 'APPROVED', 'REJECTED', 'ARCHIVED');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "LessonType" AS ENUM ('VIDEO', 'TEXT', 'PDF', 'QUIZ');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "ScorePolicy" AS ENUM ('HIGHEST', 'LATEST', 'AVERAGE');
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "roles" (
|
|
"id" SERIAL NOT NULL,
|
|
"code" VARCHAR(50) NOT NULL,
|
|
"name" JSONB NOT NULL,
|
|
"description" JSONB,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "roles_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "users" (
|
|
"id" SERIAL NOT NULL,
|
|
"username" VARCHAR(50) NOT NULL,
|
|
"email" VARCHAR(255) NOT NULL,
|
|
"password" VARCHAR(255) NOT NULL,
|
|
"role_id" INTEGER NOT NULL,
|
|
"is_active" BOOLEAN NOT NULL DEFAULT true,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "profiles" (
|
|
"id" SERIAL NOT NULL,
|
|
"user_id" INTEGER NOT NULL,
|
|
"first_name" VARCHAR(100),
|
|
"last_name" VARCHAR(100),
|
|
"phone" VARCHAR(20),
|
|
"avatar_url" VARCHAR(500),
|
|
"bio" JSONB,
|
|
"birth_date" TIMESTAMP(3),
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "profiles_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "categories" (
|
|
"id" SERIAL NOT NULL,
|
|
"code" VARCHAR(50) NOT NULL,
|
|
"name" JSONB NOT NULL,
|
|
"description" JSONB,
|
|
"icon_url" VARCHAR(500),
|
|
"is_active" BOOLEAN NOT NULL DEFAULT true,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "categories_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "courses" (
|
|
"id" SERIAL NOT NULL,
|
|
"title" JSONB NOT NULL,
|
|
"description" JSONB NOT NULL,
|
|
"thumbnail_url" VARCHAR(500),
|
|
"price" DECIMAL(10,2) NOT NULL DEFAULT 0,
|
|
"is_free" BOOLEAN NOT NULL DEFAULT false,
|
|
"have_certificate" BOOLEAN NOT NULL DEFAULT false,
|
|
"status" "CourseStatus" NOT NULL DEFAULT 'DRAFT',
|
|
"category_id" INTEGER NOT NULL,
|
|
"created_by" INTEGER NOT NULL,
|
|
"rejection_reason" TEXT,
|
|
"is_deleted" BOOLEAN NOT NULL DEFAULT false,
|
|
"deleted_at" TIMESTAMP(3),
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "courses_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "course_instructors" (
|
|
"id" SERIAL NOT NULL,
|
|
"course_id" INTEGER NOT NULL,
|
|
"user_id" INTEGER NOT NULL,
|
|
"is_primary" BOOLEAN NOT NULL DEFAULT false,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "course_instructors_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "chapters" (
|
|
"id" SERIAL NOT NULL,
|
|
"course_id" INTEGER NOT NULL,
|
|
"title" JSONB NOT NULL,
|
|
"description" JSONB,
|
|
"order" INTEGER NOT NULL,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "chapters_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "lessons" (
|
|
"id" SERIAL NOT NULL,
|
|
"chapter_id" INTEGER NOT NULL,
|
|
"title" JSONB NOT NULL,
|
|
"description" JSONB,
|
|
"type" "LessonType" NOT NULL,
|
|
"content" JSONB,
|
|
"video_url" VARCHAR(500),
|
|
"video_duration" INTEGER,
|
|
"order" INTEGER NOT NULL,
|
|
"is_preview" BOOLEAN NOT NULL DEFAULT false,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "lessons_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "lesson_prerequisites" (
|
|
"id" SERIAL NOT NULL,
|
|
"lesson_id" INTEGER NOT NULL,
|
|
"prerequisite_lesson_id" INTEGER NOT NULL,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "lesson_prerequisites_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "attachments" (
|
|
"id" SERIAL NOT NULL,
|
|
"lesson_id" INTEGER NOT NULL,
|
|
"filename" VARCHAR(255) NOT NULL,
|
|
"original_name" VARCHAR(255) NOT NULL,
|
|
"file_url" VARCHAR(500) NOT NULL,
|
|
"file_size" BIGINT NOT NULL,
|
|
"mime_type" VARCHAR(100) NOT NULL,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "attachments_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "quizzes" (
|
|
"id" SERIAL NOT NULL,
|
|
"lesson_id" INTEGER NOT NULL,
|
|
"title" JSONB NOT NULL,
|
|
"description" JSONB,
|
|
"passing_score" INTEGER NOT NULL DEFAULT 70,
|
|
"time_limit" INTEGER,
|
|
"max_attempts" INTEGER NOT NULL DEFAULT 3,
|
|
"cooldown_hours" INTEGER NOT NULL DEFAULT 24,
|
|
"score_policy" "ScorePolicy" NOT NULL DEFAULT 'HIGHEST',
|
|
"shuffle_questions" BOOLEAN NOT NULL DEFAULT true,
|
|
"shuffle_choices" BOOLEAN NOT NULL DEFAULT true,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "quizzes_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "quiz_questions" (
|
|
"id" SERIAL NOT NULL,
|
|
"quiz_id" INTEGER NOT NULL,
|
|
"question" JSONB NOT NULL,
|
|
"choices" JSONB NOT NULL,
|
|
"points" INTEGER NOT NULL DEFAULT 1,
|
|
"order" INTEGER NOT NULL,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "quiz_questions_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "quiz_attempts" (
|
|
"id" SERIAL NOT NULL,
|
|
"quiz_id" INTEGER NOT NULL,
|
|
"user_id" INTEGER NOT NULL,
|
|
"answers" JSONB NOT NULL,
|
|
"score" INTEGER NOT NULL,
|
|
"passed" BOOLEAN NOT NULL,
|
|
"time_spent" INTEGER,
|
|
"started_at" TIMESTAMP(3) NOT NULL,
|
|
"completed_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "quiz_attempts_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "enrollments" (
|
|
"id" SERIAL NOT NULL,
|
|
"user_id" INTEGER NOT NULL,
|
|
"course_id" INTEGER NOT NULL,
|
|
"enrolled_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"completed_at" TIMESTAMP(3),
|
|
"progress_percent" INTEGER NOT NULL DEFAULT 0,
|
|
"last_accessed_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "enrollments_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "lesson_progress" (
|
|
"id" SERIAL NOT NULL,
|
|
"user_id" INTEGER NOT NULL,
|
|
"lesson_id" INTEGER NOT NULL,
|
|
"is_completed" BOOLEAN NOT NULL DEFAULT false,
|
|
"video_progress" INTEGER NOT NULL DEFAULT 0,
|
|
"completed_at" TIMESTAMP(3),
|
|
"last_watched_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "lesson_progress_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "certificates" (
|
|
"id" SERIAL NOT NULL,
|
|
"user_id" INTEGER NOT NULL,
|
|
"course_id" INTEGER NOT NULL,
|
|
"certificate_url" VARCHAR(500) NOT NULL,
|
|
"issued_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "certificates_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "roles_code_key" ON "roles"("code");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "users_username_key" ON "users"("username");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "users_email_idx" ON "users"("email");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "users_role_id_idx" ON "users"("role_id");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "profiles_user_id_key" ON "profiles"("user_id");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "categories_code_key" ON "categories"("code");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "courses_category_id_idx" ON "courses"("category_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "courses_status_idx" ON "courses"("status");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "courses_created_by_idx" ON "courses"("created_by");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "courses_created_at_idx" ON "courses"("created_at");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "course_instructors_course_id_idx" ON "course_instructors"("course_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "course_instructors_user_id_idx" ON "course_instructors"("user_id");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "course_instructors_course_id_user_id_key" ON "course_instructors"("course_id", "user_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "chapters_course_id_idx" ON "chapters"("course_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "chapters_order_idx" ON "chapters"("order");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "lessons_chapter_id_idx" ON "lessons"("chapter_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "lessons_order_idx" ON "lessons"("order");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "lesson_prerequisites_lesson_id_idx" ON "lesson_prerequisites"("lesson_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "lesson_prerequisites_prerequisite_lesson_id_idx" ON "lesson_prerequisites"("prerequisite_lesson_id");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "lesson_prerequisites_lesson_id_prerequisite_lesson_id_key" ON "lesson_prerequisites"("lesson_id", "prerequisite_lesson_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "attachments_lesson_id_idx" ON "attachments"("lesson_id");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "quizzes_lesson_id_key" ON "quizzes"("lesson_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "quiz_questions_quiz_id_idx" ON "quiz_questions"("quiz_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "quiz_questions_order_idx" ON "quiz_questions"("order");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "quiz_attempts_quiz_id_idx" ON "quiz_attempts"("quiz_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "quiz_attempts_user_id_idx" ON "quiz_attempts"("user_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "quiz_attempts_completed_at_idx" ON "quiz_attempts"("completed_at");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "enrollments_user_id_idx" ON "enrollments"("user_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "enrollments_course_id_idx" ON "enrollments"("course_id");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "enrollments_user_id_course_id_key" ON "enrollments"("user_id", "course_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "lesson_progress_user_id_idx" ON "lesson_progress"("user_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "lesson_progress_lesson_id_idx" ON "lesson_progress"("lesson_id");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "lesson_progress_user_id_lesson_id_key" ON "lesson_progress"("user_id", "lesson_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "certificates_user_id_idx" ON "certificates"("user_id");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "certificates_user_id_course_id_key" ON "certificates"("user_id", "course_id");
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "users" ADD CONSTRAINT "users_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "roles"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "profiles" ADD CONSTRAINT "profiles_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "courses" ADD CONSTRAINT "courses_category_id_fkey" FOREIGN KEY ("category_id") REFERENCES "categories"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "courses" ADD CONSTRAINT "courses_created_by_fkey" FOREIGN KEY ("created_by") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "course_instructors" ADD CONSTRAINT "course_instructors_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "courses"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "course_instructors" ADD CONSTRAINT "course_instructors_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "chapters" ADD CONSTRAINT "chapters_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "courses"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "lessons" ADD CONSTRAINT "lessons_chapter_id_fkey" FOREIGN KEY ("chapter_id") REFERENCES "chapters"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "lesson_prerequisites" ADD CONSTRAINT "lesson_prerequisites_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "lessons"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "lesson_prerequisites" ADD CONSTRAINT "lesson_prerequisites_prerequisite_lesson_id_fkey" FOREIGN KEY ("prerequisite_lesson_id") REFERENCES "lessons"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "attachments" ADD CONSTRAINT "attachments_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "lessons"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "quizzes" ADD CONSTRAINT "quizzes_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "lessons"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "quiz_questions" ADD CONSTRAINT "quiz_questions_quiz_id_fkey" FOREIGN KEY ("quiz_id") REFERENCES "quizzes"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "quiz_attempts" ADD CONSTRAINT "quiz_attempts_quiz_id_fkey" FOREIGN KEY ("quiz_id") REFERENCES "quizzes"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "quiz_attempts" ADD CONSTRAINT "quiz_attempts_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "enrollments" ADD CONSTRAINT "enrollments_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "enrollments" ADD CONSTRAINT "enrollments_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "courses"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "lesson_progress" ADD CONSTRAINT "lesson_progress_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "lesson_progress" ADD CONSTRAINT "lesson_progress_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "lessons"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "certificates" ADD CONSTRAINT "certificates_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|