Skip to content

Commit

Permalink
chore(apps/analytics): add database tables for learning analytics pro…
Browse files Browse the repository at this point in the history
…gress and performance computations (#4389)
  • Loading branch information
sjschlapbach authored Dec 5, 2024
1 parent 4e11fa1 commit 5f402d7
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
-- CreateEnum
CREATE TYPE "PerformanceLevel" AS ENUM ('LOW', 'MEDIUM', 'HIGH');

-- CreateTable
CREATE TABLE "ParticipantPerformance" (
"id" SERIAL NOT NULL,
"firstErrorRate" REAL NOT NULL,
"firstPerformance" "PerformanceLevel" NOT NULL,
"lastErrorRate" REAL NOT NULL,
"lastPerformance" "PerformanceLevel" NOT NULL,
"totalErrorRate" REAL NOT NULL,
"totalPerformance" "PerformanceLevel" NOT NULL,
"participantId" UUID NOT NULL,
"courseId" UUID NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "ParticipantPerformance_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "InstancePerformance" (
"id" SERIAL NOT NULL,
"firstErrorRate" REAL,
"firstPartialRate" REAL,
"firstCorrectRate" REAL,
"lastErrorRate" REAL,
"lastPartialRate" REAL,
"lastCorrectRate" REAL,
"totalErrorRate" REAL NOT NULL,
"totalPartialRate" REAL NOT NULL,
"totalCorrectRate" REAL NOT NULL,
"instanceId" INTEGER NOT NULL,
"courseId" UUID NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "InstancePerformance_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "ActivityPerformance" (
"id" SERIAL NOT NULL,
"firstErrorRate" REAL,
"firstPartialRate" REAL,
"firstCorrectRate" REAL,
"lastErrorRate" REAL,
"lastPartialRate" REAL,
"lastCorrectRate" REAL,
"totalErrorRate" REAL NOT NULL,
"totalPartialRate" REAL NOT NULL,
"totalCorrectRate" REAL NOT NULL,
"practiceQuizId" UUID,
"microLearningId" UUID,
"courseId" UUID NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "ActivityPerformance_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "ActivityProgress" (
"id" SERIAL NOT NULL,
"totalCourseParticipants" INTEGER NOT NULL,
"startedCount" INTEGER NOT NULL,
"completedCount" INTEGER NOT NULL,
"repeatedCount" INTEGER,
"practiceQuizId" UUID,
"microLearningId" UUID,
"courseId" UUID NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "ActivityProgress_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "InstancePerformance_instanceId_key" ON "InstancePerformance"("instanceId");

-- CreateIndex
CREATE UNIQUE INDEX "ActivityPerformance_practiceQuizId_key" ON "ActivityPerformance"("practiceQuizId");

-- CreateIndex
CREATE UNIQUE INDEX "ActivityPerformance_microLearningId_key" ON "ActivityPerformance"("microLearningId");

-- CreateIndex
CREATE UNIQUE INDEX "ActivityProgress_practiceQuizId_key" ON "ActivityProgress"("practiceQuizId");

-- CreateIndex
CREATE UNIQUE INDEX "ActivityProgress_microLearningId_key" ON "ActivityProgress"("microLearningId");

-- AddForeignKey
ALTER TABLE "ParticipantPerformance" ADD CONSTRAINT "ParticipantPerformance_participantId_fkey" FOREIGN KEY ("participantId") REFERENCES "Participant"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "ParticipantPerformance" ADD CONSTRAINT "ParticipantPerformance_courseId_fkey" FOREIGN KEY ("courseId") REFERENCES "Course"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "InstancePerformance" ADD CONSTRAINT "InstancePerformance_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "ElementInstance"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "InstancePerformance" ADD CONSTRAINT "InstancePerformance_courseId_fkey" FOREIGN KEY ("courseId") REFERENCES "Course"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "ActivityPerformance" ADD CONSTRAINT "ActivityPerformance_practiceQuizId_fkey" FOREIGN KEY ("practiceQuizId") REFERENCES "PracticeQuiz"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "ActivityPerformance" ADD CONSTRAINT "ActivityPerformance_microLearningId_fkey" FOREIGN KEY ("microLearningId") REFERENCES "MicroLearning"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "ActivityPerformance" ADD CONSTRAINT "ActivityPerformance_courseId_fkey" FOREIGN KEY ("courseId") REFERENCES "Course"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "ActivityProgress" ADD CONSTRAINT "ActivityProgress_practiceQuizId_fkey" FOREIGN KEY ("practiceQuizId") REFERENCES "PracticeQuiz"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "ActivityProgress" ADD CONSTRAINT "ActivityProgress_microLearningId_fkey" FOREIGN KEY ("microLearningId") REFERENCES "MicroLearning"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "ActivityProgress" ADD CONSTRAINT "ActivityProgress_courseId_fkey" FOREIGN KEY ("courseId") REFERENCES "Course"("id") ON DELETE CASCADE ON UPDATE CASCADE;
102 changes: 102 additions & 0 deletions packages/prisma/src/prisma/schema/analytics.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ enum ActivityLevel {
HIGH
}

enum PerformanceLevel {
LOW
MEDIUM
HIGH
}

// All metrics are based on logged in participant activity only
model ParticipantAnalytics {
id Int @id @default(autoincrement())
Expand Down Expand Up @@ -162,6 +168,102 @@ model AggregatedCourseAnalytics {
updatedAt DateTime @updatedAt
}

model ParticipantPerformance {
id Int @id @default(autoincrement())
firstErrorRate Float @db.Real // fraction of first responses that were incorrect (in the corresponding course)
firstPerformance PerformanceLevel // performance level based on quantiles of first error rate distributions over all participants
lastErrorRate Float @db.Real // fraction of last responses that were incorrect
lastPerformance PerformanceLevel
totalErrorRate Float @db.Real // fraction of all responses that were incorrect
totalPerformance PerformanceLevel
participant Participant @relation(fields: [participantId], references: [id], onDelete: Cascade, onUpdate: Cascade)
participantId String @db.Uuid
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade, onUpdate: Cascade)
courseId String @db.Uuid
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

model InstancePerformance {
id Int @id @default(autoincrement())
firstErrorRate Float? @db.Real // fraction of wrong answers to this instance (first attempt, PQ only)
firstPartialRate Float? @db.Real // fraction of partially correct answers to this instance (first attempt, PQ only)
firstCorrectRate Float? @db.Real // fraction of correct answers to this instance (first attempt, PQ only)
lastErrorRate Float? @db.Real // ... (last attempt, PQ only)
lastPartialRate Float? @db.Real // ... (last attempt, PQ only)
lastCorrectRate Float? @db.Real // ... (last attempt, PQ only)
totalErrorRate Float @db.Real // ... (all attempts)
totalPartialRate Float @db.Real // ... (all attempts)
totalCorrectRate Float @db.Real // ... (all attempts)
instance ElementInstance @relation(fields: [instanceId], references: [id], onDelete: Cascade, onUpdate: Cascade)
instanceId Int @unique
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade, onUpdate: Cascade)
courseId String @db.Uuid
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

model ActivityPerformance {
id Int @id @default(autoincrement())
firstErrorRate Float? @db.Real // fraction of wrong answers to instances in this activity (first attempt, PQ only)
firstPartialRate Float? @db.Real // fraction of partially correct answers to instances in this activity (first attempt, PQ only)
firstCorrectRate Float? @db.Real // fraction of correct answers to instances in this activity (first attempt, PQ only)
lastErrorRate Float? @db.Real // ... (last attempt, PQ only)
lastPartialRate Float? @db.Real // ... (last attempt, PQ only)
lastCorrectRate Float? @db.Real // ... (last attempt, PQ only)
totalErrorRate Float @db.Real // ... (all attempts)
totalPartialRate Float @db.Real // ... (all attempts)
totalCorrectRate Float @db.Real // ... (all attempts)
practiceQuiz PracticeQuiz? @relation(fields: [practiceQuizId], references: [id], onDelete: Cascade, onUpdate: Cascade)
practiceQuizId String? @unique @db.Uuid
microLearning MicroLearning? @relation(fields: [microLearningId], references: [id], onDelete: Cascade, onUpdate: Cascade)
microLearningId String? @unique @db.Uuid
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade, onUpdate: Cascade)
courseId String @db.Uuid
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

model ActivityProgress {
id Int @id @default(autoincrement())
totalCourseParticipants Int
startedCount Int
completedCount Int
repeatedCount Int?
practiceQuiz PracticeQuiz? @relation(fields: [practiceQuizId], references: [id], onDelete: Cascade, onUpdate: Cascade)
practiceQuizId String? @unique @db.Uuid
microLearning MicroLearning? @relation(fields: [microLearningId], references: [id], onDelete: Cascade, onUpdate: Cascade)
microLearningId String? @unique @db.Uuid
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade, onUpdate: Cascade)
courseId String @db.Uuid
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

model CompetencyTree {
id Int @id @default(autoincrement())
Expand Down
4 changes: 4 additions & 0 deletions packages/prisma/src/prisma/schema/course.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ model Course {
aggregatedAnalytics AggregatedAnalytics[]
aggregatedCourseAnalytics AggregatedCourseAnalytics[]
participantCourseAnalytics ParticipantCourseAnalytics[]
participantPerformances ParticipantPerformance[]
instancePerformances InstancePerformance[]
activityPerformances ActivityPerformance[]
activityProgresses ActivityProgress[]
responses QuestionResponse[]
groupAssignmentPoolEntries GroupAssignmentPoolEntry[]
Expand Down
9 changes: 5 additions & 4 deletions packages/prisma/src/prisma/schema/element.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,11 @@ model ElementInstance {
/// [PrismaElementResults]
anonymousResults Json // contains the collection of gathered results by anonymous participants
responses QuestionResponse[]
detailResponses QuestionResponseDetail[]
feedbacks ElementFeedback[]
instanceStatistics InstanceStatistics?
responses QuestionResponse[]
detailResponses QuestionResponseDetail[]
feedbacks ElementFeedback[]
instanceStatistics InstanceStatistics?
instancePerformance InstancePerformance?
element Element @relation(fields: [elementId], references: [id], onDelete: Cascade, onUpdate: Cascade)
elementId Int
Expand Down
1 change: 1 addition & 0 deletions packages/prisma/src/prisma/schema/participant.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ model Participant {
titles Title[]
participantAnalytics ParticipantAnalytics[]
participantCourseAnalytics ParticipantCourseAnalytics[]
coursePerformances ParticipantPerformance[]
groupAssignmentPoolEntries GroupAssignmentPoolEntry[]
messages GroupMessage[]
Expand Down
4 changes: 4 additions & 0 deletions packages/prisma/src/prisma/schema/quiz.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ model PracticeQuiz {
responses QuestionResponse[]
responseDetails QuestionResponseDetail[]
performance ActivityPerformance?
progress ActivityProgress?
startedCount Int @default(0) // >= completedCount (at least one answer given to quiz)
completedCount Int @default(0) // >= repeatedCount (every instance answered at least once)
Expand Down Expand Up @@ -213,6 +215,8 @@ model MicroLearning {
responses QuestionResponse[]
responseDetails QuestionResponseDetail[]
performance ActivityPerformance?
progress ActivityProgress?
startedCount Int @default(0) // >= completedCount (at least one answer given to quiz)
completedCount Int @default(0) // (every instance answered at least once)
Expand Down

0 comments on commit 5f402d7

Please sign in to comment.