taleem-kernel 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/schema-check.js +21 -10
- package/bin/schema-update.js +1 -0
- package/package.json +3 -3
- package/prisma/dev.db +0 -0
- package/prisma/migrations/20260829212536_init/migration.sql +96 -0
- package/prisma/schema.prisma +48 -26
- package/readme.md +151 -371
- package/src/{ServerKernel.js → index.js} +2 -0
- package/src/modules/Communication.js +7 -51
- package/src/modules/Course.js +34 -41
- package/src/modules/Group.js +48 -0
- package/src/modules/Library.js +20 -8
- package/src/modules/Subscription.js +12 -61
- package/src/modules/Svg.js +3 -21
- package/prisma/content.db +0 -0
package/bin/schema-check.js
CHANGED
|
@@ -1,20 +1,31 @@
|
|
|
1
|
+
// /home/bilal-tariq/00--TALEEM/taleem-kernel/bin/schema-check.js
|
|
1
2
|
import fs from "fs";
|
|
2
3
|
import path from "path";
|
|
3
4
|
import { fileURLToPath } from "url";
|
|
4
5
|
|
|
5
|
-
const
|
|
6
|
-
path.
|
|
7
|
-
"
|
|
6
|
+
const kernelSchemaPath = path.resolve(
|
|
7
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
8
|
+
"../prisma/schema.prisma"
|
|
8
9
|
);
|
|
9
10
|
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const appSchemaPath = path.resolve(process.cwd(), "prisma/schema.prisma");
|
|
12
|
+
|
|
13
|
+
function normalize(schema) {
|
|
14
|
+
return schema
|
|
15
|
+
.split("\n")
|
|
16
|
+
.map(line => line.replace(/\/\/.*$/, "").trim())
|
|
17
|
+
.filter(line => line.length > 0)
|
|
18
|
+
.join("\n");
|
|
19
|
+
}
|
|
14
20
|
|
|
15
|
-
if (
|
|
16
|
-
console.error(
|
|
21
|
+
if (!fs.existsSync(appSchemaPath)) {
|
|
22
|
+
console.error(`❌ No schema.prisma found at ${appSchemaPath}.`);
|
|
23
|
+
console.error(`Run this command from the root of a Taleem application.`);
|
|
17
24
|
process.exit(1);
|
|
18
25
|
}
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
const kernelSchema = fs.readFileSync(kernelSchemaPath, "utf8");
|
|
28
|
+
const appSchema = fs.readFileSync(appSchemaPath, "utf8");
|
|
29
|
+
|
|
30
|
+
if (normalize(kernelSchema) !== normalize(appSchema)) {
|
|
31
|
+
console.error("❌ Taleem Prisma schema mismatch.");
|
package/bin/schema-update.js
CHANGED
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "taleem-kernel",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Taleem data and business-logic kernel. HTTP is only an adapter.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./src/
|
|
6
|
+
"main": "./src/index.js",
|
|
7
7
|
"exports": {
|
|
8
|
-
".": "./src/
|
|
8
|
+
".": "./src/index.js"
|
|
9
9
|
},
|
|
10
10
|
"bin": {
|
|
11
11
|
"taleem-kernel": "./bin/cli.js"
|
package/prisma/dev.db
CHANGED
|
Binary file
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Warnings:
|
|
3
|
+
|
|
4
|
+
- You are about to drop the column `items` on the `Group` table. All the data in the column will be lost.
|
|
5
|
+
|
|
6
|
+
*/
|
|
7
|
+
-- RedefineTables
|
|
8
|
+
PRAGMA defer_foreign_keys=ON;
|
|
9
|
+
PRAGMA foreign_keys=OFF;
|
|
10
|
+
CREATE TABLE "new_Communication" (
|
|
11
|
+
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
12
|
+
"userId" INTEGER NOT NULL,
|
|
13
|
+
"librarySlug" TEXT NOT NULL,
|
|
14
|
+
"type" TEXT NOT NULL,
|
|
15
|
+
"initiator" TEXT NOT NULL DEFAULT 'STUDENT',
|
|
16
|
+
"meta" TEXT,
|
|
17
|
+
"message" TEXT NOT NULL,
|
|
18
|
+
"authorResponse" TEXT,
|
|
19
|
+
"isPublic" BOOLEAN NOT NULL DEFAULT false,
|
|
20
|
+
"readAt" DATETIME,
|
|
21
|
+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
22
|
+
"updatedAt" DATETIME NOT NULL,
|
|
23
|
+
CONSTRAINT "Communication_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
|
24
|
+
CONSTRAINT "Communication_librarySlug_fkey" FOREIGN KEY ("librarySlug") REFERENCES "Library" ("slug") ON DELETE RESTRICT ON UPDATE CASCADE
|
|
25
|
+
);
|
|
26
|
+
INSERT INTO "new_Communication" ("authorResponse", "createdAt", "id", "isPublic", "librarySlug", "message", "meta", "readAt", "type", "updatedAt", "userId") SELECT "authorResponse", "createdAt", "id", "isPublic", "librarySlug", "message", "meta", "readAt", "type", "updatedAt", "userId" FROM "Communication";
|
|
27
|
+
DROP TABLE "Communication";
|
|
28
|
+
ALTER TABLE "new_Communication" RENAME TO "Communication";
|
|
29
|
+
CREATE INDEX "Communication_userId_idx" ON "Communication"("userId");
|
|
30
|
+
CREATE INDEX "Communication_librarySlug_idx" ON "Communication"("librarySlug");
|
|
31
|
+
CREATE TABLE "new_Course" (
|
|
32
|
+
"slug" TEXT NOT NULL PRIMARY KEY,
|
|
33
|
+
"title" TEXT NOT NULL,
|
|
34
|
+
"description" TEXT,
|
|
35
|
+
"thumbnail" TEXT,
|
|
36
|
+
"access" TEXT NOT NULL DEFAULT 'OPEN',
|
|
37
|
+
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
|
38
|
+
"price" INTEGER NOT NULL DEFAULT 0
|
|
39
|
+
);
|
|
40
|
+
INSERT INTO "new_Course" ("access", "description", "price", "slug", "thumbnail", "title") SELECT "access", "description", "price", "slug", "thumbnail", "title" FROM "Course";
|
|
41
|
+
DROP TABLE "Course";
|
|
42
|
+
ALTER TABLE "new_Course" RENAME TO "Course";
|
|
43
|
+
CREATE TABLE "new_Group" (
|
|
44
|
+
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
45
|
+
"courseSlug" TEXT NOT NULL,
|
|
46
|
+
"slug" TEXT NOT NULL,
|
|
47
|
+
"title" TEXT NOT NULL,
|
|
48
|
+
"thumbnail" TEXT,
|
|
49
|
+
"description" TEXT,
|
|
50
|
+
CONSTRAINT "Group_courseSlug_fkey" FOREIGN KEY ("courseSlug") REFERENCES "Course" ("slug") ON DELETE RESTRICT ON UPDATE CASCADE
|
|
51
|
+
);
|
|
52
|
+
INSERT INTO "new_Group" ("courseSlug", "id", "slug", "thumbnail", "title") SELECT "courseSlug", "id", "slug", "thumbnail", "title" FROM "Group";
|
|
53
|
+
DROP TABLE "Group";
|
|
54
|
+
ALTER TABLE "new_Group" RENAME TO "Group";
|
|
55
|
+
CREATE INDEX "Group_courseSlug_idx" ON "Group"("courseSlug");
|
|
56
|
+
CREATE UNIQUE INDEX "Group_courseSlug_slug_key" ON "Group"("courseSlug", "slug");
|
|
57
|
+
CREATE TABLE "new_Library" (
|
|
58
|
+
"slug" TEXT NOT NULL PRIMARY KEY,
|
|
59
|
+
"title" TEXT NOT NULL,
|
|
60
|
+
"description" TEXT,
|
|
61
|
+
"thumbnail" TEXT,
|
|
62
|
+
"type" TEXT NOT NULL,
|
|
63
|
+
"status" TEXT NOT NULL DEFAULT 'DRAFT',
|
|
64
|
+
"body" TEXT,
|
|
65
|
+
"courseSlug" TEXT NOT NULL,
|
|
66
|
+
"groupSlug" TEXT NOT NULL,
|
|
67
|
+
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
|
68
|
+
"allowCommunication" BOOLEAN NOT NULL DEFAULT true,
|
|
69
|
+
"meta" TEXT,
|
|
70
|
+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
71
|
+
"updatedAt" DATETIME NOT NULL,
|
|
72
|
+
CONSTRAINT "Library_courseSlug_groupSlug_fkey" FOREIGN KEY ("courseSlug", "groupSlug") REFERENCES "Group" ("courseSlug", "slug") ON DELETE RESTRICT ON UPDATE CASCADE
|
|
73
|
+
);
|
|
74
|
+
INSERT INTO "new_Library" ("allowCommunication", "body", "courseSlug", "createdAt", "description", "groupSlug", "meta", "slug", "sortOrder", "status", "thumbnail", "title", "type", "updatedAt") SELECT "allowCommunication", "body", "courseSlug", "createdAt", "description", "groupSlug", "meta", "slug", "sortOrder", "status", "thumbnail", "title", "type", "updatedAt" FROM "Library";
|
|
75
|
+
DROP TABLE "Library";
|
|
76
|
+
ALTER TABLE "new_Library" RENAME TO "Library";
|
|
77
|
+
CREATE INDEX "Library_courseSlug_idx" ON "Library"("courseSlug");
|
|
78
|
+
CREATE INDEX "Library_groupSlug_idx" ON "Library"("groupSlug");
|
|
79
|
+
CREATE TABLE "new_Subscription" (
|
|
80
|
+
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
81
|
+
"userId" INTEGER NOT NULL,
|
|
82
|
+
"courseSlug" TEXT NOT NULL,
|
|
83
|
+
"startsAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
84
|
+
"endsAt" DATETIME,
|
|
85
|
+
"amount" INTEGER,
|
|
86
|
+
"cancelledAt" DATETIME,
|
|
87
|
+
CONSTRAINT "Subscription_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
|
88
|
+
CONSTRAINT "Subscription_courseSlug_fkey" FOREIGN KEY ("courseSlug") REFERENCES "Course" ("slug") ON DELETE RESTRICT ON UPDATE CASCADE
|
|
89
|
+
);
|
|
90
|
+
INSERT INTO "new_Subscription" ("amount", "cancelledAt", "courseSlug", "endsAt", "id", "startsAt", "userId") SELECT "amount", "cancelledAt", "courseSlug", "endsAt", "id", "startsAt", "userId" FROM "Subscription";
|
|
91
|
+
DROP TABLE "Subscription";
|
|
92
|
+
ALTER TABLE "new_Subscription" RENAME TO "Subscription";
|
|
93
|
+
CREATE INDEX "Subscription_userId_idx" ON "Subscription"("userId");
|
|
94
|
+
CREATE INDEX "Subscription_courseSlug_idx" ON "Subscription"("courseSlug");
|
|
95
|
+
PRAGMA foreign_keys=ON;
|
|
96
|
+
PRAGMA defer_foreign_keys=OFF;
|
package/prisma/schema.prisma
CHANGED
|
@@ -6,6 +6,10 @@ datasource db {
|
|
|
6
6
|
provider = "sqlite"
|
|
7
7
|
url = env("DATABASE_URL")
|
|
8
8
|
}
|
|
9
|
+
enum CommunicationInitiator {
|
|
10
|
+
STUDENT
|
|
11
|
+
TEACHER
|
|
12
|
+
}
|
|
9
13
|
|
|
10
14
|
enum ContentType {
|
|
11
15
|
ARTICLE
|
|
@@ -30,27 +34,57 @@ enum AdminRole {
|
|
|
30
34
|
SUPER_ADMIN
|
|
31
35
|
}
|
|
32
36
|
|
|
37
|
+
model Course {
|
|
38
|
+
slug String @id
|
|
39
|
+
title String
|
|
40
|
+
description String?
|
|
41
|
+
thumbnail String?
|
|
42
|
+
access CourseAccess @default(OPEN)
|
|
43
|
+
isActive Boolean @default(true)
|
|
44
|
+
price Int @default(0)
|
|
45
|
+
|
|
46
|
+
groups Group[]
|
|
47
|
+
subscriptions Subscription[]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
33
51
|
model Group {
|
|
34
52
|
id Int @id @default(autoincrement())
|
|
35
53
|
courseSlug String
|
|
36
54
|
slug String
|
|
37
55
|
title String
|
|
38
56
|
thumbnail String?
|
|
39
|
-
|
|
57
|
+
description String?
|
|
58
|
+
course Course @relation(fields: [courseSlug], references: [slug], onDelete: Restrict)
|
|
59
|
+
library Library[]
|
|
40
60
|
|
|
41
61
|
@@unique([courseSlug, slug])
|
|
42
62
|
@@index([courseSlug])
|
|
43
63
|
}
|
|
44
64
|
|
|
45
|
-
model
|
|
46
|
-
slug
|
|
47
|
-
title
|
|
48
|
-
description
|
|
49
|
-
thumbnail
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
65
|
+
model Library {
|
|
66
|
+
slug String @id
|
|
67
|
+
title String
|
|
68
|
+
description String?
|
|
69
|
+
thumbnail String?
|
|
70
|
+
type ContentType
|
|
71
|
+
status LibraryStatus @default(DRAFT)
|
|
72
|
+
body String?
|
|
73
|
+
courseSlug String
|
|
74
|
+
groupSlug String
|
|
75
|
+
sortOrder Int @default(0)
|
|
76
|
+
allowCommunication Boolean @default(true)
|
|
77
|
+
meta String?
|
|
78
|
+
createdAt DateTime @default(now())
|
|
79
|
+
updatedAt DateTime @updatedAt
|
|
53
80
|
|
|
81
|
+
group Group @relation(fields: [courseSlug, groupSlug], references: [courseSlug, slug], onDelete: Restrict)
|
|
82
|
+
|
|
83
|
+
communications Communication[]
|
|
84
|
+
|
|
85
|
+
@@index([courseSlug])
|
|
86
|
+
@@index([groupSlug])
|
|
87
|
+
}
|
|
54
88
|
model User {
|
|
55
89
|
id Int @id @default(autoincrement())
|
|
56
90
|
email String @unique
|
|
@@ -74,22 +108,6 @@ model Admin {
|
|
|
74
108
|
updatedAt DateTime @updatedAt
|
|
75
109
|
}
|
|
76
110
|
|
|
77
|
-
model Library {
|
|
78
|
-
slug String @id
|
|
79
|
-
title String
|
|
80
|
-
description String?
|
|
81
|
-
thumbnail String?
|
|
82
|
-
type ContentType
|
|
83
|
-
status LibraryStatus @default(DRAFT)
|
|
84
|
-
body String?
|
|
85
|
-
courseSlug String
|
|
86
|
-
groupSlug String
|
|
87
|
-
sortOrder Int @default(0)
|
|
88
|
-
allowCommunication Boolean @default(true)
|
|
89
|
-
meta String?
|
|
90
|
-
createdAt DateTime @default(now())
|
|
91
|
-
updatedAt DateTime @updatedAt
|
|
92
|
-
}
|
|
93
111
|
|
|
94
112
|
model Subscription {
|
|
95
113
|
id Int @id @default(autoincrement())
|
|
@@ -98,9 +116,11 @@ model Subscription {
|
|
|
98
116
|
startsAt DateTime @default(now())
|
|
99
117
|
endsAt DateTime?
|
|
100
118
|
amount Int?
|
|
101
|
-
user User @relation(fields: [userId], references: [id])
|
|
102
119
|
cancelledAt DateTime?
|
|
103
120
|
|
|
121
|
+
user User @relation(fields: [userId], references: [id])
|
|
122
|
+
course Course @relation(fields: [courseSlug], references: [slug], onDelete: Restrict)
|
|
123
|
+
|
|
104
124
|
@@index([userId])
|
|
105
125
|
@@index([courseSlug])
|
|
106
126
|
}
|
|
@@ -110,6 +130,7 @@ model Communication {
|
|
|
110
130
|
userId Int
|
|
111
131
|
librarySlug String
|
|
112
132
|
type String
|
|
133
|
+
initiator CommunicationInitiator @default(STUDENT)
|
|
113
134
|
meta String?
|
|
114
135
|
message String
|
|
115
136
|
authorResponse String?
|
|
@@ -118,6 +139,7 @@ model Communication {
|
|
|
118
139
|
createdAt DateTime @default(now())
|
|
119
140
|
updatedAt DateTime @updatedAt
|
|
120
141
|
user User @relation(fields: [userId], references: [id])
|
|
142
|
+
library Library @relation(fields: [librarySlug], references: [slug], onDelete: Restrict)
|
|
121
143
|
|
|
122
144
|
@@index([userId])
|
|
123
145
|
@@index([librarySlug])
|