Round 19: Professional Notebooks, Digital Rewards, GDPR, Role-Based Dashboard, Deep Styling Polish

- Fixed attendance API 403: added TEACHER school membership check
- Fixed competitions API 403: cross-school access, null schoolId, public fallback
- Fixed GDPR export API 500: 16 Prisma field name mismatches
- Enhanced notebooks: page templates (Cornell, Mind Map, Venn, T-Chart, Weekly Planner),
  sticky notes, search, page duplication, sections/chapters, highlighter tool
- Added scratch pad with DrawingCanvas in assessments for hand-written solutions
- Role-based dashboard: TEACHER (competence radar, upcoming lessons),
  STUDENT (grades trend, competitions), PARENT (children grades, calendar),
  SCHOOL_ADMIN (system health, audit log, user management)
- Digital reward system: 16 demo rewards, points earning/redemption,
  categories (streaming, shopping, experiences, merchandise, privileges)
- GDPR compliance: consent management, data retention, cookie consent
- Deep styling polish: glassmorphism, gradient headers, animated sidebar,
  card hover effects, progress bar animations, timeline dots, FAB button
- 160+ new i18n keys (DE/EN)
This commit is contained in:
Mustafa Cetin committed 2026-07-29 16:23:18 +00:00
1 parent 86e4b504e4
commit 6d9b42ac37
43 files changed
+4569 -140

No files matched your search

+67
View File
@@ -76,6 +76,8 @@ model School {
newsletters Newsletter[]
competitions Competition[]
rewardClaims RewardClaim[]
rewards Reward[]
rewardPoints RewardPoints[]
subjectTopics SubjectTopic[]
district SchoolDistrict? @relation(fields: [districtId], references: [id])
districtId String?
@@ -128,6 +130,8 @@ model User {
competitionsCreated Competition[]
competitionParticipations CompetitionParticipant[]
competitionClaims RewardClaim[]
rewardRedemptions RewardRedemption[]
rewardPoints RewardPoints[]
studentAnswers StudentAnswer[]
}
@@ -1845,3 +1849,66 @@ model StudentAnswer {
@@index([studentId])
@@map("student_answers")
}
// ─── Digital Reward Catalog & Points System ──────────────────────────
model Reward {
id String @id @default(cuid())
schoolId String
title String
description String?
category String // streaming, shopping, experience, merchandise, privilege
pointsCost Int
image String?
stock Int?
isActive Boolean @default(true)
isDemo Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
school School @relation(fields: [schoolId], references: [id])
redemptions RewardRedemption[]
@@index([schoolId])
@@index([category])
@@map("rewards")
}
model RewardRedemption {
id String @id @default(cuid())
rewardId String
userId String
pointsSpent Int
status String @default("pending") // pending, approved, rejected, fulfilled
note String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
reward Reward @relation(fields: [rewardId], references: [id])
user User @relation(fields: [userId], references: [id])
@@index([rewardId])
@@index([userId])
@@index([status])
@@map("reward_redemptions")
}
model RewardPoints {
id String @id @default(cuid())
userId String
schoolId String
points Int @default(0)
source String // competition, grade, attendance, homework
sourceId String? // ID of the source entity
description String?
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id])
school School @relation(fields: [schoolId], references: [id])
@@index([userId])
@@index([schoolId])
@@index([source])
@@map("reward_points")
}