mian commit

This commit is contained in:
2026-03-01 18:32:49 +00:00
parent c7e1203187
commit 3754ea4c28
135 changed files with 18211 additions and 0 deletions
+242
View File
@@ -0,0 +1,242 @@
-- Clean database
TRUNCATE TABLE "Admin", "Grade", "Class", "Subject", "Teacher", "TeacherSubject", "Lesson", "Parent", "Student", "Exam", "Assignment", "Result", "Attendance", "Event", "Announcement" CASCADE;
INSERT INTO "Admin" ("id", "username") VALUES
('admin1', 'admin1'),
('admin2', 'admin2');
INSERT INTO "Grade" ("id", "level") VALUES
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
(6, 6);
INSERT INTO "Teacher" ("id", "username", "name", "surname", "email", "phone", "address", "bloodType", "sex", "birthday") VALUES
('teacher1', 'teacher1', 'TName1', 'TSurname1', '[email protected]', '123-456-7891', 'Address1', 'A+', 'FEMALE', '1996-02-27T00:26:35.280Z'),
('teacher2', 'teacher2', 'TName2', 'TSurname2', '[email protected]', '123-456-7892', 'Address2', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'),
('teacher3', 'teacher3', 'TName3', 'TSurname3', '[email protected]', '123-456-7893', 'Address3', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z'),
('teacher4', 'teacher4', 'TName4', 'TSurname4', '[email protected]', '123-456-7894', 'Address4', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'),
('teacher5', 'teacher5', 'TName5', 'TSurname5', '[email protected]', '123-456-7895', 'Address5', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z'),
('teacher6', 'teacher6', 'TName6', 'TSurname6', '[email protected]', '123-456-7896', 'Address6', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'),
('teacher7', 'teacher7', 'TName7', 'TSurname7', '[email protected]', '123-456-7897', 'Address7', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z'),
('teacher8', 'teacher8', 'TName8', 'TSurname8', '[email protected]', '123-456-7898', 'Address8', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'),
('teacher9', 'teacher9', 'TName9', 'TSurname9', '[email protected]', '123-456-7899', 'Address9', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z'),
('teacher10', 'teacher10', 'TName10', 'TSurname10', '[email protected]', '123-456-78910', 'Address10', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'),
('teacher11', 'teacher11', 'TName11', 'TSurname11', '[email protected]', '123-456-78911', 'Address11', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z'),
('teacher12', 'teacher12', 'TName12', 'TSurname12', '[email protected]', '123-456-78912', 'Address12', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'),
('teacher13', 'teacher13', 'TName13', 'TSurname13', '[email protected]', '123-456-78913', 'Address13', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z'),
('teacher14', 'teacher14', 'TName14', 'TSurname14', '[email protected]', '123-456-78914', 'Address14', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'),
('teacher15', 'teacher15', 'TName15', 'TSurname15', '[email protected]', '123-456-78915', 'Address15', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z');
INSERT INTO "Class" ("id", "name", "gradeId", "capacity", "supervisorId") VALUES
(1, '1A', 1, 17, 'teacher12'),
(2, '2A', 2, 15, 'teacher13'),
(3, '3A', 3, 18, 'teacher14'),
(4, '4A', 4, 20, 'teacher15'),
(5, '5A', 5, 20, 'teacher10'),
(6, '6A', 6, 20, 'teacher11');
INSERT INTO "Subject" ("id", "name") VALUES
(1, 'Mathematics'),
(2, 'Science'),
(3, 'English'),
(4, 'History'),
(5, 'Geography'),
(6, 'Physics'),
(7, 'Chemistry'),
(8, 'Biology'),
(9, 'Computer Science'),
(10, 'Art');
INSERT INTO "TeacherSubject" ("subjectId", "teacherId", "isPrimary") VALUES
(2, 'teacher1', true),
(3, 'teacher2', true),
(4, 'teacher3', true),
(5, 'teacher4', true),
(6, 'teacher5', true),
(7, 'teacher6', true),
(8, 'teacher7', true),
(9, 'teacher8', true),
(10, 'teacher9', true),
(1, 'teacher10', true),
(2, 'teacher11', true),
(3, 'teacher12', true),
(4, 'teacher13', true),
(5, 'teacher14', true),
(6, 'teacher15', true);
INSERT INTO "Lesson" ("id", "name", "day", "startTime", "endTime", "subjectId", "classId", "teacherId") VALUES
(1, 'Lesson1', 'TUESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 2, 2, 'teacher2'),
(2, 'Lesson2', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 3, 3, 'teacher3'),
(3, 'Lesson3', 'TUESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 4, 4, 'teacher4'),
(4, 'Lesson4', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 5, 5, 'teacher5'),
(5, 'Lesson5', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 6, 6, 'teacher6'),
(6, 'Lesson6', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 7, 1, 'teacher7'),
(7, 'Lesson7', 'WEDNESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 8, 2, 'teacher8'),
(8, 'Lesson8', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 9, 3, 'teacher9'),
(9, 'Lesson9', 'FRIDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 10, 4, 'teacher10'),
(10, 'Lesson10', 'FRIDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 1, 5, 'teacher11'),
(11, 'Lesson11', 'TUESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 2, 6, 'teacher12'),
(12, 'Lesson12', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 3, 1, 'teacher13'),
(13, 'Lesson13', 'WEDNESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 4, 2, 'teacher14'),
(14, 'Lesson14', 'TUESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 5, 3, 'teacher15'),
(15, 'Lesson15', 'TUESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 6, 4, 'teacher1'),
(16, 'Lesson16', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 7, 5, 'teacher2'),
(17, 'Lesson17', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 8, 6, 'teacher3'),
(18, 'Lesson18', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 9, 1, 'teacher4'),
(19, 'Lesson19', 'FRIDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 10, 2, 'teacher5'),
(20, 'Lesson20', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 1, 3, 'teacher6'),
(21, 'Lesson21', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 2, 4, 'teacher7'),
(22, 'Lesson22', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 3, 5, 'teacher8'),
(23, 'Lesson23', 'WEDNESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 4, 6, 'teacher9'),
(24, 'Lesson24', 'FRIDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 5, 1, 'teacher10'),
(25, 'Lesson25', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 6, 2, 'teacher11'),
(26, 'Lesson26', 'FRIDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 7, 3, 'teacher12'),
(27, 'Lesson27', 'WEDNESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 8, 4, 'teacher13'),
(28, 'Lesson28', 'FRIDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 9, 5, 'teacher14'),
(29, 'Lesson29', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 10, 6, 'teacher15'),
(30, 'Lesson30', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 1, 1, 'teacher1');
INSERT INTO "Parent" ("id", "username", "name", "surname", "email", "phone", "address") VALUES
('parentId1', 'parentId1', 'PName 1', 'PSurname 1', '[email protected]', '123-456-7891', 'Address1'),
('parentId2', 'parentId2', 'PName 2', 'PSurname 2', '[email protected]', '123-456-7892', 'Address2'),
('parentId3', 'parentId3', 'PName 3', 'PSurname 3', '[email protected]', '123-456-7893', 'Address3'),
('parentId4', 'parentId4', 'PName 4', 'PSurname 4', '[email protected]', '123-456-7894', 'Address4'),
('parentId5', 'parentId5', 'PName 5', 'PSurname 5', '[email protected]', '123-456-7895', 'Address5'),
('parentId6', 'parentId6', 'PName 6', 'PSurname 6', '[email protected]', '123-456-7896', 'Address6'),
('parentId7', 'parentId7', 'PName 7', 'PSurname 7', '[email protected]', '123-456-7897', 'Address7'),
('parentId8', 'parentId8', 'PName 8', 'PSurname 8', '[email protected]', '123-456-7898', 'Address8'),
('parentId9', 'parentId9', 'PName 9', 'PSurname 9', '[email protected]', '123-456-7899', 'Address9'),
('parentId10', 'parentId10', 'PName 10', 'PSurname 10', '[email protected]', '123-456-78910', 'Address10'),
('parentId11', 'parentId11', 'PName 11', 'PSurname 11', '[email protected]', '123-456-78911', 'Address11'),
('parentId12', 'parentId12', 'PName 12', 'PSurname 12', '[email protected]', '123-456-78912', 'Address12'),
('parentId13', 'parentId13', 'PName 13', 'PSurname 13', '[email protected]', '123-456-78913', 'Address13'),
('parentId14', 'parentId14', 'PName 14', 'PSurname 14', '[email protected]', '123-456-78914', 'Address14'),
('parentId15', 'parentId15', 'PName 15', 'PSurname 15', '[email protected]', '123-456-78915', 'Address15'),
('parentId16', 'parentId16', 'PName 16', 'PSurname 16', '[email protected]', '123-456-78916', 'Address16'),
('parentId17', 'parentId17', 'PName 17', 'PSurname 17', '[email protected]', '123-456-78917', 'Address17'),
('parentId18', 'parentId18', 'PName 18', 'PSurname 18', '[email protected]', '123-456-78918', 'Address18'),
('parentId19', 'parentId19', 'PName 19', 'PSurname 19', '[email protected]', '123-456-78919', 'Address19'),
('parentId20', 'parentId20', 'PName 20', 'PSurname 20', '[email protected]', '123-456-78920', 'Address20'),
('parentId21', 'parentId21', 'PName 21', 'PSurname 21', '[email protected]', '123-456-78921', 'Address21'),
('parentId22', 'parentId22', 'PName 22', 'PSurname 22', '[email protected]', '123-456-78922', 'Address22'),
('parentId23', 'parentId23', 'PName 23', 'PSurname 23', '[email protected]', '123-456-78923', 'Address23'),
('parentId24', 'parentId24', 'PName 24', 'PSurname 24', '[email protected]', '123-456-78924', 'Address24'),
('parentId25', 'parentId25', 'PName 25', 'PSurname 25', '[email protected]', '123-456-78925', 'Address25');
INSERT INTO "Student" ("id", "username", "name", "surname", "email", "phone", "address", "bloodType", "sex", "parentId", "gradeId", "classId", "birthday") VALUES
('student1', 'student1', 'SName1', 'SSurname 1', '[email protected]', '987-654-3211', 'Address1', 'O-', 'FEMALE', 'parentId1', 2, 2, '2016-02-27T00:26:35.281Z'),
('student2', 'student2', 'SName2', 'SSurname 2', '[email protected]', '987-654-3212', 'Address2', 'O-', 'MALE', 'parentId1', 3, 3, '2016-02-27T00:26:35.281Z'),
('student3', 'student3', 'SName3', 'SSurname 3', '[email protected]', '987-654-3213', 'Address3', 'O-', 'FEMALE', 'parentId2', 4, 4, '2016-02-27T00:26:35.281Z'),
('student4', 'student4', 'SName4', 'SSurname 4', '[email protected]', '987-654-3214', 'Address4', 'O-', 'MALE', 'parentId2', 5, 5, '2016-02-27T00:26:35.281Z'),
('student5', 'student5', 'SName5', 'SSurname 5', '[email protected]', '987-654-3215', 'Address5', 'O-', 'FEMALE', 'parentId3', 6, 6, '2016-02-27T00:26:35.281Z'),
('student6', 'student6', 'SName6', 'SSurname 6', '[email protected]', '987-654-3216', 'Address6', 'O-', 'MALE', 'parentId3', 1, 1, '2016-02-27T00:26:35.281Z'),
('student7', 'student7', 'SName7', 'SSurname 7', '[email protected]', '987-654-3217', 'Address7', 'O-', 'FEMALE', 'parentId4', 2, 2, '2016-02-27T00:26:35.281Z'),
('student8', 'student8', 'SName8', 'SSurname 8', '[email protected]', '987-654-3218', 'Address8', 'O-', 'MALE', 'parentId4', 3, 3, '2016-02-27T00:26:35.281Z'),
('student9', 'student9', 'SName9', 'SSurname 9', '[email protected]', '987-654-3219', 'Address9', 'O-', 'FEMALE', 'parentId5', 4, 4, '2016-02-27T00:26:35.281Z'),
('student10', 'student10', 'SName10', 'SSurname 10', '[email protected]', '987-654-32110', 'Address10', 'O-', 'MALE', 'parentId5', 5, 5, '2016-02-27T00:26:35.281Z'),
('student11', 'student11', 'SName11', 'SSurname 11', '[email protected]', '987-654-32111', 'Address11', 'O-', 'FEMALE', 'parentId6', 6, 6, '2016-02-27T00:26:35.281Z'),
('student12', 'student12', 'SName12', 'SSurname 12', '[email protected]', '987-654-32112', 'Address12', 'O-', 'MALE', 'parentId6', 1, 1, '2016-02-27T00:26:35.281Z'),
('student13', 'student13', 'SName13', 'SSurname 13', '[email protected]', '987-654-32113', 'Address13', 'O-', 'FEMALE', 'parentId7', 2, 2, '2016-02-27T00:26:35.281Z'),
('student14', 'student14', 'SName14', 'SSurname 14', '[email protected]', '987-654-32114', 'Address14', 'O-', 'MALE', 'parentId7', 3, 3, '2016-02-27T00:26:35.281Z'),
('student15', 'student15', 'SName15', 'SSurname 15', '[email protected]', '987-654-32115', 'Address15', 'O-', 'FEMALE', 'parentId8', 4, 4, '2016-02-27T00:26:35.281Z'),
('student16', 'student16', 'SName16', 'SSurname 16', '[email protected]', '987-654-32116', 'Address16', 'O-', 'MALE', 'parentId8', 5, 5, '2016-02-27T00:26:35.281Z'),
('student17', 'student17', 'SName17', 'SSurname 17', '[email protected]', '987-654-32117', 'Address17', 'O-', 'FEMALE', 'parentId9', 6, 6, '2016-02-27T00:26:35.281Z'),
('student18', 'student18', 'SName18', 'SSurname 18', '[email protected]', '987-654-32118', 'Address18', 'O-', 'MALE', 'parentId9', 1, 1, '2016-02-27T00:26:35.281Z'),
('student19', 'student19', 'SName19', 'SSurname 19', '[email protected]', '987-654-32119', 'Address19', 'O-', 'FEMALE', 'parentId10', 2, 2, '2016-02-27T00:26:35.281Z'),
('student20', 'student20', 'SName20', 'SSurname 20', '[email protected]', '987-654-32120', 'Address20', 'O-', 'MALE', 'parentId10', 3, 3, '2016-02-27T00:26:35.281Z'),
('student21', 'student21', 'SName21', 'SSurname 21', '[email protected]', '987-654-32121', 'Address21', 'O-', 'FEMALE', 'parentId11', 4, 4, '2016-02-27T00:26:35.281Z'),
('student22', 'student22', 'SName22', 'SSurname 22', '[email protected]', '987-654-32122', 'Address22', 'O-', 'MALE', 'parentId11', 5, 5, '2016-02-27T00:26:35.281Z'),
('student23', 'student23', 'SName23', 'SSurname 23', '[email protected]', '987-654-32123', 'Address23', 'O-', 'FEMALE', 'parentId12', 6, 6, '2016-02-27T00:26:35.281Z'),
('student24', 'student24', 'SName24', 'SSurname 24', '[email protected]', '987-654-32124', 'Address24', 'O-', 'MALE', 'parentId12', 1, 1, '2016-02-27T00:26:35.281Z'),
('student25', 'student25', 'SName25', 'SSurname 25', '[email protected]', '987-654-32125', 'Address25', 'O-', 'FEMALE', 'parentId13', 2, 2, '2016-02-27T00:26:35.281Z'),
('student26', 'student26', 'SName26', 'SSurname 26', '[email protected]', '987-654-32126', 'Address26', 'O-', 'MALE', 'parentId13', 3, 3, '2016-02-27T00:26:35.281Z'),
('student27', 'student27', 'SName27', 'SSurname 27', '[email protected]', '987-654-32127', 'Address27', 'O-', 'FEMALE', 'parentId14', 4, 4, '2016-02-27T00:26:35.281Z'),
('student28', 'student28', 'SName28', 'SSurname 28', '[email protected]', '987-654-32128', 'Address28', 'O-', 'MALE', 'parentId14', 5, 5, '2016-02-27T00:26:35.281Z'),
('student29', 'student29', 'SName29', 'SSurname 29', '[email protected]', '987-654-32129', 'Address29', 'O-', 'FEMALE', 'parentId15', 6, 6, '2016-02-27T00:26:35.281Z'),
('student30', 'student30', 'SName30', 'SSurname 30', '[email protected]', '987-654-32130', 'Address30', 'O-', 'MALE', 'parentId15', 1, 1, '2016-02-27T00:26:35.281Z'),
('student31', 'student31', 'SName31', 'SSurname 31', '[email protected]', '987-654-32131', 'Address31', 'O-', 'FEMALE', 'parentId16', 2, 2, '2016-02-27T00:26:35.281Z'),
('student32', 'student32', 'SName32', 'SSurname 32', '[email protected]', '987-654-32132', 'Address32', 'O-', 'MALE', 'parentId16', 3, 3, '2016-02-27T00:26:35.281Z'),
('student33', 'student33', 'SName33', 'SSurname 33', '[email protected]', '987-654-32133', 'Address33', 'O-', 'FEMALE', 'parentId17', 4, 4, '2016-02-27T00:26:35.281Z'),
('student34', 'student34', 'SName34', 'SSurname 34', '[email protected]', '987-654-32134', 'Address34', 'O-', 'MALE', 'parentId17', 5, 5, '2016-02-27T00:26:35.281Z'),
('student35', 'student35', 'SName35', 'SSurname 35', '[email protected]', '987-654-32135', 'Address35', 'O-', 'FEMALE', 'parentId18', 6, 6, '2016-02-27T00:26:35.281Z'),
('student36', 'student36', 'SName36', 'SSurname 36', '[email protected]', '987-654-32136', 'Address36', 'O-', 'MALE', 'parentId18', 1, 1, '2016-02-27T00:26:35.281Z'),
('student37', 'student37', 'SName37', 'SSurname 37', '[email protected]', '987-654-32137', 'Address37', 'O-', 'FEMALE', 'parentId19', 2, 2, '2016-02-27T00:26:35.281Z'),
('student38', 'student38', 'SName38', 'SSurname 38', '[email protected]', '987-654-32138', 'Address38', 'O-', 'MALE', 'parentId19', 3, 3, '2016-02-27T00:26:35.281Z'),
('student39', 'student39', 'SName39', 'SSurname 39', '[email protected]', '987-654-32139', 'Address39', 'O-', 'FEMALE', 'parentId20', 4, 4, '2016-02-27T00:26:35.281Z'),
('student40', 'student40', 'SName40', 'SSurname 40', '[email protected]', '987-654-32140', 'Address40', 'O-', 'MALE', 'parentId20', 5, 5, '2016-02-27T00:26:35.281Z'),
('student41', 'student41', 'SName41', 'SSurname 41', '[email protected]', '987-654-32141', 'Address41', 'O-', 'FEMALE', 'parentId21', 6, 6, '2016-02-27T00:26:35.281Z'),
('student42', 'student42', 'SName42', 'SSurname 42', '[email protected]', '987-654-32142', 'Address42', 'O-', 'MALE', 'parentId21', 1, 1, '2016-02-27T00:26:35.281Z'),
('student43', 'student43', 'SName43', 'SSurname 43', '[email protected]', '987-654-32143', 'Address43', 'O-', 'FEMALE', 'parentId22', 2, 2, '2016-02-27T00:26:35.281Z'),
('student44', 'student44', 'SName44', 'SSurname 44', '[email protected]', '987-654-32144', 'Address44', 'O-', 'MALE', 'parentId22', 3, 3, '2016-02-27T00:26:35.281Z'),
('student45', 'student45', 'SName45', 'SSurname 45', '[email protected]', '987-654-32145', 'Address45', 'O-', 'FEMALE', 'parentId23', 4, 4, '2016-02-27T00:26:35.281Z'),
('student46', 'student46', 'SName46', 'SSurname 46', '[email protected]', '987-654-32146', 'Address46', 'O-', 'MALE', 'parentId23', 5, 5, '2016-02-27T00:26:35.281Z'),
('student47', 'student47', 'SName47', 'SSurname 47', '[email protected]', '987-654-32147', 'Address47', 'O-', 'FEMALE', 'parentId24', 6, 6, '2016-02-27T00:26:35.281Z'),
('student48', 'student48', 'SName48', 'SSurname 48', '[email protected]', '987-654-32148', 'Address48', 'O-', 'MALE', 'parentId24', 1, 1, '2016-02-27T00:26:35.281Z'),
('student49', 'student49', 'SName49', 'SSurname 49', '[email protected]', '987-654-32149', 'Address49', 'O-', 'FEMALE', 'parentId25', 2, 2, '2016-02-27T00:26:35.281Z'),
('student50', 'student50', 'SName50', 'SSurname 50', '[email protected]', '987-654-32150', 'Address50', 'O-', 'MALE', 'parentId25', 3, 3, '2016-02-27T00:26:35.281Z');
INSERT INTO "Exam" ("id", "title", "startTime", "endTime", "lessonId") VALUES
(1, 'Exam 1', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 2),
(2, 'Exam 2', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 3),
(3, 'Exam 3', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 4),
(4, 'Exam 4', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 5),
(5, 'Exam 5', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 6),
(6, 'Exam 6', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 7),
(7, 'Exam 7', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 8),
(8, 'Exam 8', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 9),
(9, 'Exam 9', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 10),
(10, 'Exam 10', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 11);
INSERT INTO "Assignment" ("id", "title", "startDate", "dueDate", "lessonId") VALUES
(1, 'Assignment 1', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 2),
(2, 'Assignment 2', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 3),
(3, 'Assignment 3', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 4),
(4, 'Assignment 4', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 5),
(5, 'Assignment 5', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 6),
(6, 'Assignment 6', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 7),
(7, 'Assignment 7', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 8),
(8, 'Assignment 8', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 9),
(9, 'Assignment 9', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 10),
(10, 'Assignment 10', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 11);
INSERT INTO "Result" ("id", "score", "studentId", "examId", "assignmentId") VALUES
(1, 90, 'student1', 1, NULL),
(2, 90, 'student2', 2, NULL),
(3, 90, 'student3', 3, NULL),
(4, 90, 'student4', 4, NULL),
(5, 90, 'student5', 5, NULL),
(6, 90, 'student6', NULL, 1),
(7, 90, 'student7', NULL, 2),
(8, 90, 'student8', NULL, 3),
(9, 90, 'student9', NULL, 4),
(10, 90, 'student10', NULL, 5);
INSERT INTO "Attendance" ("id", "date", "present", "studentId", "lessonId") VALUES
(1, '2026-02-27T00:26:35.281Z', TRUE, 'student1', 2),
(2, '2026-02-27T00:26:35.281Z', TRUE, 'student2', 3),
(3, '2026-02-27T00:26:35.281Z', TRUE, 'student3', 4),
(4, '2026-02-27T00:26:35.281Z', TRUE, 'student4', 5),
(5, '2026-02-27T00:26:35.281Z', TRUE, 'student5', 6),
(6, '2026-02-27T00:26:35.281Z', TRUE, 'student6', 7),
(7, '2026-02-27T00:26:35.281Z', TRUE, 'student7', 8),
(8, '2026-02-27T00:26:35.281Z', TRUE, 'student8', 9),
(9, '2026-02-27T00:26:35.281Z', TRUE, 'student9', 10),
(10, '2026-02-27T00:26:35.281Z', TRUE, 'student10', 11);
INSERT INTO "Event" ("id", "title", "description", "startTime", "endTime", "classId") VALUES
(1, 'Event 1', 'Description for Event 1', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 2),
(2, 'Event 2', 'Description for Event 2', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 3),
(3, 'Event 3', 'Description for Event 3', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 4),
(4, 'Event 4', 'Description for Event 4', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 5),
(5, 'Event 5', 'Description for Event 5', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 1);
INSERT INTO "Announcement" ("id", "title", "description", "date", "classId") VALUES
(1, 'Announcement 1', 'Description for Announcement 1', '2026-02-27T00:26:35.281Z', 2),
(2, 'Announcement 2', 'Description for Announcement 2', '2026-02-27T00:26:35.281Z', 3),
(3, 'Announcement 3', 'Description for Announcement 3', '2026-02-27T00:26:35.281Z', 4),
(4, 'Announcement 4', 'Description for Announcement 4', '2026-02-27T00:26:35.281Z', 5),
(5, 'Announcement 5', 'Description for Announcement 5', '2026-02-27T00:26:35.281Z', 1);
+8
View File
@@ -0,0 +1,8 @@
# Supabase
.branches
.temp
# dotenvx
.env.keys
.env.local
.env.*.local
+384
View File
@@ -0,0 +1,384 @@
# For detailed configuration reference documentation, visit:
# https://supabase.com/docs/guides/local-development/cli/config
# A string used to distinguish different Supabase projects on the same host. Defaults to the
# working directory name when running `supabase init`.
project_id = "full-stack-school"
[api]
enabled = true
# Port to use for the API URL.
port = 54321
# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API
# endpoints. `public` and `graphql_public` schemas are included by default.
schemas = ["public", "graphql_public"]
# Extra schemas to add to the search_path of every request.
extra_search_path = ["public", "extensions"]
# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size
# for accidental or malicious requests.
max_rows = 1000
[api.tls]
# Enable HTTPS endpoints locally using a self-signed certificate.
enabled = false
# Paths to self-signed certificate pair.
# cert_path = "../certs/my-cert.pem"
# key_path = "../certs/my-key.pem"
[db]
# Port to use for the local database URL.
port = 54322
# Port used by db diff command to initialize the shadow database.
shadow_port = 54320
# Maximum amount of time to wait for health check when starting the local database.
health_timeout = "2m"
# The database major version to use. This has to be the same as your remote database's. Run `SHOW
# server_version;` on the remote database to check.
major_version = 17
[db.pooler]
enabled = false
# Port to use for the local connection pooler.
port = 54329
# Specifies when a server connection can be reused by other clients.
# Configure one of the supported pooler modes: `transaction`, `session`.
pool_mode = "transaction"
# How many server connections to allow per user/database pair.
default_pool_size = 20
# Maximum number of client connections allowed.
max_client_conn = 100
# [db.vault]
# secret_key = "env(SECRET_VALUE)"
[db.migrations]
# If disabled, migrations will be skipped during a db push or reset.
enabled = true
# Specifies an ordered list of schema files that describe your database.
# Supports glob patterns relative to supabase directory: "./schemas/*.sql"
schema_paths = ["./migrations/*.sql"]
[db.seed]
# If enabled, seeds the database after migrations during a db reset.
enabled = true
# Specifies an ordered list of seed files to load during db reset.
# Supports glob patterns relative to supabase directory: "./seeds/*.sql"
sql_paths = [""]
[db.network_restrictions]
# Enable management of network restrictions.
enabled = false
# List of IPv4 CIDR blocks allowed to connect to the database.
# Defaults to allow all IPv4 connections. Set empty array to block all IPs.
allowed_cidrs = ["0.0.0.0/0"]
# List of IPv6 CIDR blocks allowed to connect to the database.
# Defaults to allow all IPv6 connections. Set empty array to block all IPs.
allowed_cidrs_v6 = ["::/0"]
[realtime]
enabled = true
# Bind realtime via either IPv4 or IPv6. (default: IPv4)
# ip_version = "IPv6"
# The maximum length in bytes of HTTP request headers. (default: 4096)
# max_header_length = 4096
[studio]
enabled = true
# Port to use for Supabase Studio.
port = 54323
# External URL of the API server that frontend connects to.
api_url = "http://127.0.0.1"
# OpenAI API Key to use for Supabase AI in the Supabase Studio.
openai_api_key = "env(OPENAI_API_KEY)"
# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they
# are monitored, and you can view the emails that would have been sent from the web interface.
[inbucket]
enabled = true
# Port to use for the email testing server web interface.
port = 54324
# Uncomment to expose additional ports for testing user applications that send emails.
# smtp_port = 54325
# pop3_port = 54326
# admin_email = "[email protected]"
# sender_name = "Admin"
[storage]
enabled = true
# The maximum file size allowed (e.g. "5MB", "500KB").
file_size_limit = "50MiB"
# Uncomment to configure local storage buckets
# [storage.buckets.images]
# public = false
# file_size_limit = "50MiB"
# allowed_mime_types = ["image/png", "image/jpeg"]
# objects_path = "./images"
# Allow connections via S3 compatible clients
[storage.s3_protocol]
enabled = true
# Image transformation API is available to Supabase Pro plan.
# [storage.image_transformation]
# enabled = true
# Store analytical data in S3 for running ETL jobs over Iceberg Catalog
# This feature is only available on the hosted platform.
[storage.analytics]
enabled = false
max_namespaces = 5
max_tables = 10
max_catalogs = 2
# Analytics Buckets is available to Supabase Pro plan.
# [storage.analytics.buckets.my-warehouse]
# Store vector embeddings in S3 for large and durable datasets
# This feature is only available on the hosted platform.
[storage.vector]
enabled = false
max_buckets = 10
max_indexes = 5
# Vector Buckets is available to Supabase Pro plan.
# [storage.vector.buckets.documents-openai]
[auth]
enabled = true
# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
# in emails.
site_url = "http://127.0.0.1:3000"
# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
additional_redirect_urls = ["https://127.0.0.1:3000"]
# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week).
jwt_expiry = 3600
# JWT issuer URL. If not set, defaults to the local API URL (http://127.0.0.1:<port>/auth/v1).
# jwt_issuer = ""
# Path to JWT signing key. DO NOT commit your signing keys file to git.
# signing_keys_path = "./signing_keys.json"
# If disabled, the refresh token will never expire.
enable_refresh_token_rotation = true
# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds.
# Requires enable_refresh_token_rotation = true.
refresh_token_reuse_interval = 10
# Allow/disallow new user signups to your project.
enable_signup = true
# Allow/disallow anonymous sign-ins to your project.
enable_anonymous_sign_ins = false
# Allow/disallow testing manual linking of accounts
enable_manual_linking = false
# Passwords shorter than this value will be rejected as weak. Minimum 6, recommended 8 or more.
minimum_password_length = 6
# Passwords that do not meet the following requirements will be rejected as weak. Supported values
# are: `letters_digits`, `lower_upper_letters_digits`, `lower_upper_letters_digits_symbols`
password_requirements = ""
[auth.rate_limit]
# Number of emails that can be sent per hour. Requires auth.email.smtp to be enabled.
email_sent = 2
# Number of SMS messages that can be sent per hour. Requires auth.sms to be enabled.
sms_sent = 30
# Number of anonymous sign-ins that can be made per hour per IP address. Requires enable_anonymous_sign_ins = true.
anonymous_users = 30
# Number of sessions that can be refreshed in a 5 minute interval per IP address.
token_refresh = 150
# Number of sign up and sign-in requests that can be made in a 5 minute interval per IP address (excludes anonymous users).
sign_in_sign_ups = 30
# Number of OTP / Magic link verifications that can be made in a 5 minute interval per IP address.
token_verifications = 30
# Number of Web3 logins that can be made in a 5 minute interval per IP address.
web3 = 30
# Configure one of the supported captcha providers: `hcaptcha`, `turnstile`.
# [auth.captcha]
# enabled = true
# provider = "hcaptcha"
# secret = ""
[auth.email]
# Allow/disallow new user signups via email to your project.
enable_signup = true
# If enabled, a user will be required to confirm any email change on both the old, and new email
# addresses. If disabled, only the new email is required to confirm.
double_confirm_changes = true
# If enabled, users need to confirm their email address before signing in.
enable_confirmations = false
# If enabled, users will need to reauthenticate or have logged in recently to change their password.
secure_password_change = false
# Controls the minimum amount of time that must pass before sending another signup confirmation or password reset email.
max_frequency = "1s"
# Number of characters used in the email OTP.
otp_length = 6
# Number of seconds before the email OTP expires (defaults to 1 hour).
otp_expiry = 3600
# Use a production-ready SMTP server
# [auth.email.smtp]
# enabled = true
# host = "smtp.sendgrid.net"
# port = 587
# user = "apikey"
# pass = "env(SENDGRID_API_KEY)"
# admin_email = "[email protected]"
# sender_name = "Admin"
# Uncomment to customize email template
# [auth.email.template.invite]
# subject = "You have been invited"
# content_path = "./supabase/templates/invite.html"
# Uncomment to customize notification email template
# [auth.email.notification.password_changed]
# enabled = true
# subject = "Your password has been changed"
# content_path = "./templates/password_changed_notification.html"
[auth.sms]
# Allow/disallow new user signups via SMS to your project.
enable_signup = false
# If enabled, users need to confirm their phone number before signing in.
enable_confirmations = false
# Template for sending OTP to users
template = "Your code is {{ .Code }}"
# Controls the minimum amount of time that must pass before sending another sms otp.
max_frequency = "5s"
# Use pre-defined map of phone number to OTP for testing.
# [auth.sms.test_otp]
# 4152127777 = "123456"
# Configure logged in session timeouts.
# [auth.sessions]
# Force log out after the specified duration.
# timebox = "24h"
# Force log out if the user has been inactive longer than the specified duration.
# inactivity_timeout = "8h"
# This hook runs before a new user is created and allows developers to reject the request based on the incoming user object.
# [auth.hook.before_user_created]
# enabled = true
# uri = "pg-functions://postgres/auth/before-user-created-hook"
# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used.
# [auth.hook.custom_access_token]
# enabled = true
# uri = "pg-functions://<database>/<schema>/<hook_name>"
# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`.
[auth.sms.twilio]
enabled = false
account_sid = ""
message_service_sid = ""
# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead:
auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)"
# Multi-factor-authentication is available to Supabase Pro plan.
[auth.mfa]
# Control how many MFA factors can be enrolled at once per user.
max_enrolled_factors = 10
# Control MFA via App Authenticator (TOTP)
[auth.mfa.totp]
enroll_enabled = false
verify_enabled = false
# Configure MFA via Phone Messaging
[auth.mfa.phone]
enroll_enabled = false
verify_enabled = false
otp_length = 6
template = "Your code is {{ .Code }}"
max_frequency = "5s"
# Configure MFA via WebAuthn
# [auth.mfa.web_authn]
# enroll_enabled = true
# verify_enabled = true
# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`,
# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`,
# `twitter`, `x`, `slack`, `spotify`, `workos`, `zoom`.
[auth.external.apple]
enabled = false
client_id = ""
# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead:
secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)"
# Overrides the default auth redirectUrl.
redirect_uri = ""
# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure,
# or any other third-party OIDC providers.
url = ""
# If enabled, the nonce check will be skipped. Required for local sign in with Google auth.
skip_nonce_check = false
# If enabled, it will allow the user to successfully authenticate when the provider does not return an email address.
email_optional = false
# Allow Solana wallet holders to sign in to your project via the Sign in with Solana (SIWS, EIP-4361) standard.
# You can configure "web3" rate limit in the [auth.rate_limit] section and set up [auth.captcha] if self-hosting.
[auth.web3.solana]
enabled = false
# Use Firebase Auth as a third-party provider alongside Supabase Auth.
[auth.third_party.firebase]
enabled = false
# project_id = "my-firebase-project"
# Use Auth0 as a third-party provider alongside Supabase Auth.
[auth.third_party.auth0]
enabled = false
# tenant = "my-auth0-tenant"
# tenant_region = "us"
# Use AWS Cognito (Amplify) as a third-party provider alongside Supabase Auth.
[auth.third_party.aws_cognito]
enabled = false
# user_pool_id = "my-user-pool-id"
# user_pool_region = "us-east-1"
# Use Clerk as a third-party provider alongside Supabase Auth.
[auth.third_party.clerk]
enabled = false
# Obtain from https://clerk.com/setup/supabase
# domain = "example.clerk.accounts.dev"
# OAuth server configuration
[auth.oauth_server]
# Enable OAuth server functionality
enabled = false
# Path for OAuth consent flow UI
authorization_url_path = "/oauth/consent"
# Allow dynamic client registration
allow_dynamic_registration = false
[edge_runtime]
enabled = true
# Supported request policies: `oneshot`, `per_worker`.
# `per_worker` (default) — enables hot reload during local development.
# `oneshot` — fallback mode if hot reload causes issues (e.g. in large repos or with symlinks).
policy = "per_worker"
# Port to attach the Chrome inspector for debugging edge functions.
inspector_port = 8083
# The Deno major version to use.
deno_version = 2
# [edge_runtime.secrets]
# secret_key = "env(SECRET_VALUE)"
[analytics]
enabled = true
port = 54327
# Configure one of the supported backends: `postgres`, `bigquery`.
backend = "postgres"
# Experimental features may be deprecated any time
[experimental]
# Configures Postgres storage engine to use OrioleDB (S3)
orioledb_version = ""
# Configures S3 bucket URL, eg. <bucket_name>.s3-<region>.amazonaws.com
s3_host = "env(S3_HOST)"
# Configures S3 bucket region, eg. us-east-1
s3_region = "env(S3_REGION)"
# Configures AWS_ACCESS_KEY_ID for S3 bucket
s3_access_key = "env(S3_ACCESS_KEY)"
# Configures AWS_SECRET_ACCESS_KEY for S3 bucket
s3_secret_key = "env(S3_SECRET_KEY)"
+283
View File
@@ -0,0 +1,283 @@
-- CreateEnum
CREATE TYPE "UserSex" AS ENUM ('MALE', 'FEMALE');
-- CreateEnum
CREATE TYPE "Day" AS ENUM ('MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY');
-- CreateTable
CREATE TABLE "Admin" (
"id" TEXT NOT NULL,
"username" TEXT NOT NULL,
CONSTRAINT "Admin_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Student" (
"id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"name" TEXT NOT NULL,
"surname" TEXT NOT NULL,
"email" TEXT,
"phone" TEXT,
"address" TEXT NOT NULL,
"img" TEXT,
"bloodType" TEXT NOT NULL,
"sex" "UserSex" NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"parentId" TEXT NOT NULL,
"classId" INTEGER NOT NULL,
"gradeId" INTEGER NOT NULL,
"birthday" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Student_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Teacher" (
"id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"name" TEXT NOT NULL,
"surname" TEXT NOT NULL,
"email" TEXT,
"phone" TEXT,
"address" TEXT NOT NULL,
"img" TEXT,
"bloodType" TEXT NOT NULL,
"sex" "UserSex" NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"birthday" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Teacher_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Parent" (
"id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"name" TEXT NOT NULL,
"surname" TEXT NOT NULL,
"email" TEXT,
"phone" TEXT NOT NULL,
"address" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "Parent_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Grade" (
"id" SERIAL NOT NULL,
"level" INTEGER NOT NULL,
CONSTRAINT "Grade_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Class" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
"capacity" INTEGER NOT NULL,
"supervisorId" TEXT,
"gradeId" INTEGER NOT NULL,
CONSTRAINT "Class_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Subject" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
CONSTRAINT "Subject_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Lesson" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
"day" "Day" NOT NULL,
"startTime" TIMESTAMP(3) NOT NULL,
"endTime" TIMESTAMP(3) NOT NULL,
"subjectId" INTEGER NOT NULL,
"classId" INTEGER NOT NULL,
"teacherId" TEXT NOT NULL,
CONSTRAINT "Lesson_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Exam" (
"id" SERIAL NOT NULL,
"title" TEXT NOT NULL,
"startTime" TIMESTAMP(3) NOT NULL,
"endTime" TIMESTAMP(3) NOT NULL,
"lessonId" INTEGER NOT NULL,
CONSTRAINT "Exam_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Assignment" (
"id" SERIAL NOT NULL,
"title" TEXT NOT NULL,
"startDate" TIMESTAMP(3) NOT NULL,
"dueDate" TIMESTAMP(3) NOT NULL,
"lessonId" INTEGER NOT NULL,
CONSTRAINT "Assignment_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Result" (
"id" SERIAL NOT NULL,
"score" INTEGER NOT NULL,
"examId" INTEGER,
"assignmentId" INTEGER,
"studentId" TEXT NOT NULL,
CONSTRAINT "Result_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Attendance" (
"id" SERIAL NOT NULL,
"date" TIMESTAMP(3) NOT NULL,
"present" BOOLEAN NOT NULL,
"studentId" TEXT NOT NULL,
"lessonId" INTEGER NOT NULL,
CONSTRAINT "Attendance_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Event" (
"id" SERIAL NOT NULL,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"startTime" TIMESTAMP(3) NOT NULL,
"endTime" TIMESTAMP(3) NOT NULL,
"classId" INTEGER,
CONSTRAINT "Event_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Announcement" (
"id" SERIAL NOT NULL,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"date" TIMESTAMP(3) NOT NULL,
"classId" INTEGER,
CONSTRAINT "Announcement_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "_SubjectToTeacher" (
"A" INTEGER NOT NULL,
"B" TEXT NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "Admin_username_key" ON "Admin"("username");
-- CreateIndex
CREATE UNIQUE INDEX "Student_username_key" ON "Student"("username");
-- CreateIndex
CREATE UNIQUE INDEX "Student_email_key" ON "Student"("email");
-- CreateIndex
CREATE UNIQUE INDEX "Student_phone_key" ON "Student"("phone");
-- CreateIndex
CREATE UNIQUE INDEX "Teacher_username_key" ON "Teacher"("username");
-- CreateIndex
CREATE UNIQUE INDEX "Teacher_email_key" ON "Teacher"("email");
-- CreateIndex
CREATE UNIQUE INDEX "Teacher_phone_key" ON "Teacher"("phone");
-- CreateIndex
CREATE UNIQUE INDEX "Parent_username_key" ON "Parent"("username");
-- CreateIndex
CREATE UNIQUE INDEX "Parent_email_key" ON "Parent"("email");
-- CreateIndex
CREATE UNIQUE INDEX "Parent_phone_key" ON "Parent"("phone");
-- CreateIndex
CREATE UNIQUE INDEX "Grade_level_key" ON "Grade"("level");
-- CreateIndex
CREATE UNIQUE INDEX "Class_name_key" ON "Class"("name");
-- CreateIndex
CREATE UNIQUE INDEX "Subject_name_key" ON "Subject"("name");
-- CreateIndex
CREATE UNIQUE INDEX "_SubjectToTeacher_AB_unique" ON "_SubjectToTeacher"("A", "B");
-- CreateIndex
CREATE INDEX "_SubjectToTeacher_B_index" ON "_SubjectToTeacher"("B");
-- AddForeignKey
ALTER TABLE "Student" ADD CONSTRAINT "Student_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "Parent"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Student" ADD CONSTRAINT "Student_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Student" ADD CONSTRAINT "Student_gradeId_fkey" FOREIGN KEY ("gradeId") REFERENCES "Grade"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Class" ADD CONSTRAINT "Class_supervisorId_fkey" FOREIGN KEY ("supervisorId") REFERENCES "Teacher"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Class" ADD CONSTRAINT "Class_gradeId_fkey" FOREIGN KEY ("gradeId") REFERENCES "Grade"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Lesson" ADD CONSTRAINT "Lesson_subjectId_fkey" FOREIGN KEY ("subjectId") REFERENCES "Subject"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Lesson" ADD CONSTRAINT "Lesson_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Lesson" ADD CONSTRAINT "Lesson_teacherId_fkey" FOREIGN KEY ("teacherId") REFERENCES "Teacher"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Exam" ADD CONSTRAINT "Exam_lessonId_fkey" FOREIGN KEY ("lessonId") REFERENCES "Lesson"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_lessonId_fkey" FOREIGN KEY ("lessonId") REFERENCES "Lesson"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Result" ADD CONSTRAINT "Result_examId_fkey" FOREIGN KEY ("examId") REFERENCES "Exam"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Result" ADD CONSTRAINT "Result_assignmentId_fkey" FOREIGN KEY ("assignmentId") REFERENCES "Assignment"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Result" ADD CONSTRAINT "Result_studentId_fkey" FOREIGN KEY ("studentId") REFERENCES "Student"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Attendance" ADD CONSTRAINT "Attendance_studentId_fkey" FOREIGN KEY ("studentId") REFERENCES "Student"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Attendance" ADD CONSTRAINT "Attendance_lessonId_fkey" FOREIGN KEY ("lessonId") REFERENCES "Lesson"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Event" ADD CONSTRAINT "Event_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Announcement" ADD CONSTRAINT "Announcement_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_SubjectToTeacher" ADD CONSTRAINT "_SubjectToTeacher_A_fkey" FOREIGN KEY ("A") REFERENCES "Subject"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_SubjectToTeacher" ADD CONSTRAINT "_SubjectToTeacher_B_fkey" FOREIGN KEY ("B") REFERENCES "Teacher"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,32 @@
-- Create roles that Clerk passes in the JWT `role` claim
-- PostgREST attempts to assume these roles when making requests.
-- We create them and grant them the standard authenticated role permissions.
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'admin') THEN
CREATE ROLE admin NOLOGIN;
GRANT authenticated TO admin;
END IF;
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'teacher') THEN
CREATE ROLE teacher NOLOGIN;
GRANT authenticated TO teacher;
END IF;
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'student') THEN
CREATE ROLE student NOLOGIN;
GRANT authenticated TO student;
END IF;
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'parent') THEN
CREATE ROLE parent NOLOGIN;
GRANT authenticated TO parent;
END IF;
END $$;
-- Grant the roles to the authenticator role so PostgREST can switch to them
GRANT admin TO authenticator;
GRANT teacher TO authenticator;
GRANT student TO authenticator;
GRANT parent TO authenticator;
@@ -0,0 +1,201 @@
-- 1. Enable RLS on all tables
DO $$ BEGIN
ALTER TABLE "Admin" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Student" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Teacher" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Parent" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Grade" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Class" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Subject" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Lesson" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Exam" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Assignment" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Result" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Attendance" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Event" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Announcement" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "_SubjectToTeacher" ENABLE ROW LEVEL SECURITY;
EXCEPTION
WHEN undefined_table THEN
NULL;
END $$;
-- 2. Utility helper functions connecting to Clerk JWT
CREATE OR REPLACE FUNCTION requesting_user_id()
RETURNS text
LANGUAGE sql STABLE
AS $$
SELECT NULLIF(current_setting('request.jwt.claims', true)::json->>'sub', '')::text;
$$;
CREATE OR REPLACE FUNCTION requesting_user_role()
RETURNS text
LANGUAGE sql STABLE
AS $$
SELECT current_setting('request.jwt.claims', true)::json->>'role';
$$;
CREATE OR REPLACE FUNCTION is_admin() RETURNS boolean LANGUAGE sql STABLE AS $$
SELECT requesting_user_role() = 'admin';
$$;
-- 3. Bypass-RLS Helper Functions for finding accessible IDs
-- We use SECURITY DEFINER SET search_path = public to execute these queries as the database owner,
-- which prevents infinite recursion errors (stack depth limit exceeded) when querying tables that have RLS enabled.
-- Transaction-local variables like `request.jwt.claims` perfectly persist through SECURITY DEFINER calls.
CREATE OR REPLACE FUNCTION auth_user_classes() RETURNS SETOF integer LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student'
UNION
SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent'
UNION
SELECT "classId" FROM "Lesson" WHERE "teacherId" = requesting_user_id() AND requesting_user_role() = 'teacher'
UNION
SELECT id FROM "Class" WHERE "supervisorId" = requesting_user_id() AND requesting_user_role() = 'teacher';
END;
$$;
CREATE OR REPLACE FUNCTION auth_user_students() RETURNS SETOF text LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT id FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student'
UNION
SELECT id FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent'
UNION
SELECT id FROM "Student" WHERE "classId" IN (
SELECT "classId" FROM "Lesson" WHERE "teacherId" = requesting_user_id()
) AND requesting_user_role() = 'teacher';
END;
$$;
CREATE OR REPLACE FUNCTION auth_user_lessons() RETURNS SETOF integer LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT id FROM "Lesson" WHERE "teacherId" = requesting_user_id() AND requesting_user_role() = 'teacher'
UNION
SELECT id FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student'
)
UNION
SELECT id FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent'
);
END;
$$;
CREATE OR REPLACE FUNCTION auth_user_subjects() RETURNS SETOF integer LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT "A" FROM "_SubjectToTeacher" WHERE "B" = requesting_user_id() AND requesting_user_role() = 'teacher'
UNION
SELECT "subjectId" FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student'
)
UNION
SELECT "subjectId" FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent'
);
END;
$$;
CREATE OR REPLACE FUNCTION auth_user_teachers() RETURNS SETOF text LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT id FROM "Teacher" WHERE id = requesting_user_id() AND requesting_user_role() = 'teacher'
UNION
SELECT "teacherId" FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student'
)
UNION
SELECT "teacherId" FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent'
);
END;
$$;
CREATE OR REPLACE FUNCTION auth_user_parents() RETURNS SETOF text LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT id FROM "Parent" WHERE id = requesting_user_id() AND requesting_user_role() = 'parent'
UNION
SELECT "parentId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student';
END;
$$;
-- 4. Define Table Policies using Helpers
CREATE POLICY "Admin has full access" ON "Admin" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Student" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Teacher" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Parent" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Grade" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Class" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Subject" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Lesson" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Exam" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Assignment" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Result" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Attendance" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Event" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Announcement" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "_SubjectToTeacher" FOR ALL USING (is_admin());
CREATE POLICY "Anyone can view grades" ON "Grade" FOR SELECT TO authenticated USING (true);
CREATE POLICY "Anyone can view subject-teacher" ON "_SubjectToTeacher" FOR SELECT TO authenticated USING (true);
CREATE POLICY "Users can view permitted students" ON "Student" FOR SELECT USING (
is_admin() OR id IN (SELECT auth_user_students())
);
CREATE POLICY "Users can view permitted teachers" ON "Teacher" FOR SELECT USING (
is_admin() OR id IN (SELECT auth_user_teachers())
);
CREATE POLICY "Users can view permitted parents" ON "Parent" FOR SELECT USING (
is_admin() OR id IN (SELECT auth_user_parents())
);
CREATE POLICY "Users can view permitted subjects" ON "Subject" FOR SELECT USING (
is_admin() OR id IN (SELECT auth_user_subjects())
);
CREATE POLICY "Users can view permitted classes" ON "Class" FOR SELECT USING (
is_admin() OR id IN (SELECT auth_user_classes())
);
CREATE POLICY "Users can view permitted lessons" ON "Lesson" FOR SELECT USING (
is_admin() OR id IN (SELECT auth_user_lessons())
);
CREATE POLICY "Users can view permitted exams" ON "Exam" FOR SELECT USING (
is_admin() OR "lessonId" IN (SELECT auth_user_lessons())
);
CREATE POLICY "Users can view permitted assignments" ON "Assignment" FOR SELECT USING (
is_admin() OR "lessonId" IN (SELECT auth_user_lessons())
);
CREATE POLICY "Users can view permitted results" ON "Result" FOR SELECT USING (
is_admin() OR "studentId" IN (SELECT auth_user_students()) OR (
requesting_user_role() = 'teacher' AND (
"examId" IN (SELECT id FROM "Exam" WHERE "lessonId" IN (SELECT auth_user_lessons())) OR
"assignmentId" IN (SELECT id FROM "Assignment" WHERE "lessonId" IN (SELECT auth_user_lessons()))
)
)
);
CREATE POLICY "Users can view permitted attendance" ON "Attendance" FOR SELECT USING (
is_admin() OR "studentId" IN (SELECT auth_user_students())
);
CREATE POLICY "Users can view permitted events" ON "Event" FOR SELECT USING (
is_admin() OR "classId" IS NULL OR "classId" IN (SELECT auth_user_classes())
);
CREATE POLICY "Users can view permitted announcements" ON "Announcement" FOR SELECT USING (
is_admin() OR "classId" IS NULL OR "classId" IN (SELECT auth_user_classes())
);
@@ -0,0 +1,41 @@
-- Migration: Drop implicit _SubjectToTeacher and replace with explicit TeacherSubject
-- 1. Create the new explicit mapping table
CREATE TABLE "TeacherSubject" (
"id" SERIAL PRIMARY KEY,
"teacherId" TEXT NOT NULL REFERENCES "Teacher"("id") ON DELETE CASCADE,
"subjectId" INTEGER NOT NULL REFERENCES "Subject"("id") ON DELETE CASCADE,
"isPrimary" BOOLEAN DEFAULT false,
"assignedAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 2. Migrate existing data (Optional, but good practice if not resetting)
INSERT INTO "TeacherSubject" ("teacherId", "subjectId")
SELECT "B", "A" FROM "_SubjectToTeacher";
-- 3. Drop the old implicit mapping table
DROP TABLE "_SubjectToTeacher";
-- 4. Enable RLS on the new table
ALTER TABLE "TeacherSubject" ENABLE ROW LEVEL SECURITY;
-- 5. Define RLS Policies for the new table
CREATE POLICY "Admins have full access" ON "TeacherSubject" FOR ALL USING (is_admin());
CREATE POLICY "Anyone can view teacher-subjects" ON "TeacherSubject" FOR SELECT TO authenticated USING (true);
-- 6. Update the auth_user_subjects RLS Helper Function to use explicitly named mapping table
CREATE OR REPLACE FUNCTION auth_user_subjects() RETURNS SETOF integer LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT "subjectId" FROM "TeacherSubject" WHERE "teacherId" = requesting_user_id() AND requesting_user_role() = 'teacher'
UNION
SELECT "subjectId" FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student'
)
UNION
SELECT "subjectId" FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent'
);
END;
$$;