Files
dashboard-desaplus-noc/prisma/schema.prisma

625 lines
15 KiB
Plaintext

generator client {
provider = "prisma-client-js"
output = "../generated/prisma"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
name String?
emailVerified Boolean?
image String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
role String? @default("user")
accounts Account[]
sessions Session[]
apiKeys ApiKey[]
// Relations
discussions Discussion[]
events Event[]
complaints Complaint[] @relation("ComplaintReporter")
assignedComplaints Complaint[] @relation("ComplaintAssignee")
complaintUpdates ComplaintUpdate[]
serviceLetters ServiceLetter[]
innovationIdeas InnovationIdea[] @relation("IdeaReviewer")
healthRecords HealthRecord[]
populationDynamics PopulationDynamic[]
budgetTransactions BudgetTransaction[]
posyandus Posyandu[]
securityReports SecurityReport[]
@@map("user")
}
// --- KATEGORI 1: KINERJA DIVISI & AKTIVITAS ---
model Division {
id String @id @default(cuid())
externalId String? @unique // ID asli dari server NOC
villageId String? @default("desa1") // ID Desa dari sistem NOC
name String @unique
description String?
color String @default("#1E3A5F")
isActive Boolean @default(true)
externalActivityCount Int @default(0) // Total kegiatan dari sistem NOC (misal: 47)
lastSyncedAt DateTime? // Terakhir kali sinkronisasi dilakukan
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
activities Activity[]
documents Document[]
discussions Discussion[]
divisionMetrics DivisionMetric[]
@@map("division")
}
model Activity {
id String @id @default(cuid())
externalId String? @unique // ID asli dari server NOC
villageId String? @default("desa1")
title String
description String?
divisionId String
startDate DateTime?
endDate DateTime?
dueDate DateTime?
progress Int @default(0) // 0-100
status ActivityStatus @default(BERJALAN)
priority Priority @default(SEDANG)
assignedTo String? // JSON array of user IDs
completedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
division Division @relation(fields: [divisionId], references: [id], onDelete: Cascade)
@@index([divisionId])
@@index([status])
@@map("activity")
}
model Document {
id String @id @default(cuid())
externalId String? @unique // ID asli dari server NOC
villageId String? @default("desa1")
title String
category DocumentCategory
type String // "Gambar", "Dokumen", "PDF", etc
fileUrl String
fileSize Int? // in bytes
divisionId String?
uploadedBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
division Division? @relation(fields: [divisionId], references: [id], onDelete: SetNull)
@@index([category])
@@index([divisionId])
@@map("document")
}
model Discussion {
id String @id @default(cuid())
externalId String? @unique // ID asli dari server NOC
villageId String? @default("desa1")
message String
senderId String
parentId String? // For threaded discussions
divisionId String?
isResolved Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
sender User @relation(fields: [senderId], references: [id], onDelete: Cascade)
parent Discussion? @relation("DiscussionThread", fields: [parentId], references: [id], onDelete: SetNull)
replies Discussion[] @relation("DiscussionThread")
division Division? @relation(fields: [divisionId], references: [id], onDelete: SetNull)
@@index([divisionId])
@@index([createdAt])
@@map("discussion")
}
model Event {
id String @id @default(cuid())
externalId String? @unique // ID asli dari server NOC
villageId String? @default("desa1")
title String
description String?
eventType EventType
startDate DateTime
endDate DateTime?
location String?
isAllDay Boolean @default(false)
isRecurring Boolean @default(false)
createdBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
creator User @relation(fields: [createdBy], references: [id], onDelete: Cascade)
@@index([startDate])
@@index([eventType])
@@map("event")
}
model DivisionMetric {
id String @id @default(cuid())
divisionId String
period String // "2025-Q1", "2025-01"
activityCount Int @default(0)
completionRate Float @default(0)
avgProgress Float @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
division Division @relation(fields: [divisionId], references: [id], onDelete: Cascade)
@@unique([divisionId, period])
@@map("division_metric")
}
// --- KATEGORI 2: PENGADUAN & LAYANAN PUBLIK ---
model Complaint {
id String @id @default(cuid())
complaintNumber String @unique // Auto-generated: COMPLAINT-YYYYMMDD-XXX
title String
description String
category ComplaintCategory
status ComplaintStatus @default(BARU)
priority Priority @default(SEDANG)
reporterId String?
reporterPhone String?
reporterEmail String?
isAnonymous Boolean @default(false)
assignedTo String? // User ID
resolvedBy String? // User ID
resolvedAt DateTime?
location String?
imageUrl String[] // Array of image URLs
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
reporter User? @relation("ComplaintReporter", fields: [reporterId], references: [id], onDelete: SetNull)
assignee User? @relation("ComplaintAssignee", fields: [assignedTo], references: [id], onDelete: SetNull)
complaintUpdates ComplaintUpdate[]
@@index([status])
@@index([category])
@@index([createdAt])
@@map("complaint")
}
model ComplaintUpdate {
id String @id @default(cuid())
complaintId String
message String
status ComplaintStatus?
updatedBy String
createdAt DateTime @default(now())
complaint Complaint @relation(fields: [complaintId], references: [id], onDelete: Cascade)
updater User @relation(fields: [updatedBy], references: [id], onDelete: Cascade)
@@index([complaintId])
@@map("complaint_update")
}
model ServiceLetter {
id String @id @default(cuid())
letterNumber String @unique
letterType LetterType
applicantName String
applicantNik String
applicantAddress String
purpose String?
status ServiceStatus @default(BARU)
processedBy String?
completedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
processor User? @relation(fields: [processedBy], references: [id], onDelete: SetNull)
@@index([letterType])
@@index([status])
@@index([createdAt])
@@map("service_letter")
}
model InnovationIdea {
id String @id @default(cuid())
title String
description String
category String // "Teknologi", "Ekonomi", "Kesehatan", "Pendidikan"
submitterName String
submitterContact String?
status IdeaStatus @default(BARU)
reviewedBy String?
reviewedAt DateTime?
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
reviewer User? @relation("IdeaReviewer", fields: [reviewedBy], references: [id], onDelete: SetNull)
@@index([category])
@@index([status])
@@map("innovation_idea")
}
// --- KATEGORI 3: DEMOGRAFI & KEPENDUDUKAN ---
model Resident {
id String @id @default(cuid())
nik String @unique
kk String
name String
birthDate DateTime
birthPlace String
gender Gender
religion Religion
maritalStatus MaritalStatus @default(BELUM_KAWIN)
education EducationLevel?
occupation String?
banjarId String
rt String
rw String
address String
isHeadOfHousehold Boolean @default(false)
isPoor Boolean @default(false)
isStunting Boolean @default(false)
deathDate DateTime?
moveInDate DateTime?
moveOutDate DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
banjar Banjar @relation(fields: [banjarId], references: [id], onDelete: Cascade)
healthRecords HealthRecord[]
employmentRecords EmploymentRecord[]
@@index([banjarId])
@@index([religion])
@@index([occupation])
@@map("resident")
}
model Banjar {
id String @id @default(cuid())
name String @unique
code String @unique
description String?
totalPopulation Int @default(0)
totalKK Int @default(0)
totalPoor Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
residents Resident[]
umkms Umkm[]
@@map("banjar")
}
// --- KATEGORI 4: KEUANGAN & ANGGARAN ---
model Budget {
id String @id @default(cuid())
category String // "Belanja", "Pangan", "Pembiayaan", "Pendapatan"
amount Float @default(0)
percentage Float @default(0)
color String @default("#3B82F6")
fiscalYear Int @default(2025)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([category, fiscalYear])
@@map("budget")
}
// --- KATEGORI 5: METRIK DASHBOARD & SDGS ---
model SdgsScore {
id String @id @default(cuid())
title String @unique
score Float @default(0)
image String? // filename in public folder
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("sdgs_score")
}
model SatisfactionRating {
id String @id @default(cuid())
category String @unique // "Sangat Puas", "Puas", "Cukup", "Kurang"
value Int @default(0)
color String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("satisfaction_rating")
}
// --- STUBS FOR PHASE 2+ (To maintain relations) ---
model HealthRecord {
id String @id @default(cuid())
residentId String
resident Resident @relation(fields: [residentId], references: [id])
recordedBy String
recorder User @relation(fields: [recordedBy], references: [id])
type String // "Pemeriksaan", "Imunisasi", "Ibu Hamil"
notes String?
createdAt DateTime @default(now())
}
model EmploymentRecord {
id String @id @default(cuid())
residentId String
resident Resident @relation(fields: [residentId], references: [id])
companyName String
position String
startDate DateTime
endDate DateTime?
isActive Boolean @default(true)
createdAt DateTime @default(now())
}
model PopulationDynamic {
id String @id @default(cuid())
documentedBy String
documentor User @relation(fields: [documentedBy], references: [id])
type String // "KELAHIRAN", "KEMATIAN", "KEDATANGAN", "KEPERGIAN"
residentName String
eventDate DateTime
description String?
createdAt DateTime @default(now())
}
model BudgetTransaction {
id String @id @default(cuid())
createdBy String
creator User @relation(fields: [createdBy], references: [id])
transactionNumber String @unique
type String // "PENGELUARAN", "PENDAPATAN"
category String
amount Float
description String?
date DateTime
createdAt DateTime @default(now())
}
model Umkm {
id String @id @default(cuid())
banjarId String?
banjar Banjar? @relation(fields: [banjarId], references: [id])
name String
owner String
productType String?
description String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Posyandu {
id String @id @default(cuid())
coordinatorId String?
coordinator User? @relation(fields: [coordinatorId], references: [id])
name String
location String
schedule String
type String // "Ibu dan Anak", "Lansia", etc.
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model SecurityReport {
id String @id @default(cuid())
assignedTo String?
assignee User? @relation(fields: [assignedTo], references: [id])
reportNumber String @unique
title String
description String
location String?
reportedBy String
status String @default("BARU") // BARU, DIPROSES, SELESAI
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// --- ENUMS ---
enum ActivityStatus {
BERJALAN
SELESAI
TERTUNDA
DIBATALKAN
}
enum Priority {
RENDAH
SEDANG
TINGGI
DARURAT
}
enum DocumentCategory {
SURAT_KEPUTUSAN
DOKUMENTASI
LAPORAN_KEUANGAN
NOTULENSI_RAPAT
UMUM
}
enum EventType {
RAPAT
KEGIATAN
UPACARA
SOSIAL
BUDAYA
LAINNYA
}
enum ComplaintCategory {
KETERTIBAN_UMUM
PELAYANAN_KESEHATAN
INFRASTRUKTUR
ADMINISTRASI
KEAMANAN
LAINNYA
}
enum ComplaintStatus {
BARU
DIPROSES
SELESAI
DITOLAK
}
enum LetterType {
KTP
KK
DOMISILI
USAHA
KETERANGAN_TIDAK_MAMPU
SURAT_PENGANTAR
LAINNYA
}
enum ServiceStatus {
BARU
DIPROSES
SELESAI
DIAMBIL
}
enum IdeaStatus {
BARU
DIKAJI
DISETUJUI
DITOLAK
DIIMPLEMENTASI
}
enum Gender {
LAKI_LAKI
PEREMPUAN
}
enum Religion {
HINDU
ISLAM
KRISTEN
KATOLIK
BUDDHA
KONGHUCU
LAINNYA
}
enum MaritalStatus {
BELUM_KAWIN
KAWIN
CERAI_HIDUP
CERAI_MATI
}
enum EducationLevel {
TIDAK_SEKOLAH
SD
SMP
SMA
D3
S1
S2
S3
}
model Session {
id String @id @default(cuid())
userId String
expiresAt DateTime
token String @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
ipAddress String?
userAgent String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@map("session")
}
model Account {
id String @id @default(cuid())
userId String
accountId String
providerId String
accessToken String?
refreshToken String?
expiresAt DateTime?
password String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
idToken String?
accessTokenExpiresAt DateTime?
refreshTokenExpiresAt DateTime?
scope String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@map("account")
}
model Verification {
id String @id @default(cuid())
identifier String
value String
expiresAt DateTime
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([identifier])
@@map("verification")
}
model ApiKey {
id String @id @default(cuid())
name String
key String @unique
userId String
isActive Boolean @default(true)
expiresAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@map("api_key")
}