feat: full site build — Project/Melody schema (Option A), admin CRUD, public sections, uploads, email+SMTP, internal analytics, legal pages, docs

This commit is contained in:
2026-08-05 20:53:40 +02:00
parent d87f3033c6
commit c26f41511f
122 changed files with 15068 additions and 41 deletions
+127
View File
@@ -0,0 +1,127 @@
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum ProjectType {
PORTFOLIO
APP
WEBSITE
DESIGN
}
enum CategoryKind {
PROJECT
MELODY
}
enum PublishStatus {
DRAFT
PUBLISHED
ARCHIVED
}
enum AnalyticsEventType {
PAGE_VIEW
PROJECT_OPEN
MELODY_PLAY
PROJECT_LINK_CLICK
CONTACT_SUBMITTED
}
model Category {
id String @id @default(cuid())
kind CategoryKind
slug String @unique
nameAr String
nameEn String
order Int @default(0)
projects Project[]
melodies Melody[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Project {
id String @id @default(cuid())
type ProjectType
slug String @unique
titleAr String
titleEn String
summaryAr String?
summaryEn String?
descAr String?
descEn String?
coverImage String?
images String[]
technologies String[]
externalUrl String?
repoUrl String?
platform String?
appStoreUrl String?
testflightUrl String?
appVersion String?
supportUrl String?
appPrivacyUrl String?
status PublishStatus @default(DRAFT)
isFeatured Boolean @default(false)
sortOrder Int @default(0)
publishedAt DateTime?
categoryId String?
category Category? @relation(fields: [categoryId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([type, status])
}
model Melody {
id String @id @default(cuid())
slug String @unique
titleAr String
titleEn String
descAr String?
descEn String?
audioFile String
coverImage String?
durationSec Int?
isDownloadable Boolean @default(false)
status PublishStatus @default(DRAFT)
isFeatured Boolean @default(false)
sortOrder Int @default(0)
categoryId String
category Category @relation(fields: [categoryId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model ContactMessage {
id String @id @default(cuid())
name String
email String
message String
createdAt DateTime @default(now())
}
model AnalyticsEvent {
id String @id @default(cuid())
type AnalyticsEventType
path String?
projectId String?
melodyId String?
createdAt DateTime @default(now())
@@index([type, createdAt])
@@index([createdAt])
}
model User {
id String @id @default(cuid())
email String @unique
password String
createdAt DateTime @default(now())
}