Files
MIS-Contro-Tower/prisma/schema.prisma
2026-01-09 00:01:04 +00:00

355 lines
10 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Org {
id String @id @default(uuid())
name String
slug String @unique
createdAt DateTime @default(now())
members OrgUser[]
sessions Session[]
machines Machine[]
heartbeats MachineHeartbeat[]
kpiSnapshots MachineKpiSnapshot[]
events MachineEvent[]
workOrders MachineWorkOrder[]
settings OrgSettings?
shifts OrgShift[]
machineSettings MachineSettings[]
settingsAudits SettingsAudit[]
invites OrgInvite[]
}
model User {
id String @id @default(uuid())
email String @unique
name String?
passwordHash String
isActive Boolean @default(true)
createdAt DateTime @default(now())
emailVerifiedAt DateTime? @map("email_verified_at")
emailVerificationToken String? @unique @map("email_verification_token")
emailVerificationExpiresAt DateTime? @map("email_verification_expires_at")
orgs OrgUser[]
sessions Session[]
sentInvites OrgInvite[] @relation("OrgInviteInviter")
}
model OrgUser {
id String @id @default(uuid())
orgId String
userId String
role String @default("MEMBER") // OWNER | ADMIN | MEMBER
createdAt DateTime @default(now())
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([orgId, userId])
@@index([userId])
@@index([orgId])
}
model OrgInvite {
id String @id @default(uuid())
orgId String @map("org_id")
email String
role String @default("MEMBER") // OWNER | ADMIN | MEMBER
token String @unique
invitedBy String? @map("invited_by")
createdAt DateTime @default(now()) @map("created_at")
expiresAt DateTime @map("expires_at")
acceptedAt DateTime? @map("accepted_at")
revokedAt DateTime? @map("revoked_at")
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
inviter User? @relation("OrgInviteInviter", fields: [invitedBy], references: [id], onDelete: SetNull)
@@index([orgId])
@@index([orgId, email])
@@index([expiresAt])
@@map("org_invites")
}
model Session {
id String @id @default(uuid()) // cookie value
orgId String
userId String
createdAt DateTime @default(now())
lastSeenAt DateTime @default(now())
expiresAt DateTime
revokedAt DateTime?
ip String?
userAgent String?
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@index([orgId])
@@index([expiresAt])
}
model Machine {
id String @id @default(uuid())
orgId String
name String
apiKey String? @unique
code String?
location String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tsDevice DateTime @default(now()) @map("ts")
tsServer DateTime @default(now()) @map("ts_server")
schemaVersion String? @map("schema_version")
seq BigInt? @map("seq")
pairingCode String? @unique @map("pairing_code")
pairingCodeExpiresAt DateTime? @map("pairing_code_expires_at")
pairingCodeUsedAt DateTime? @map("pairing_code_used_at")
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
heartbeats MachineHeartbeat[]
kpiSnapshots MachineKpiSnapshot[]
events MachineEvent[]
cycles MachineCycle[]
workOrders MachineWorkOrder[]
settings MachineSettings?
settingsAudits SettingsAudit[]
@@unique([orgId, name])
@@index([orgId])
}
model MachineHeartbeat {
id String @id @default(uuid())
orgId String
machineId String
ts DateTime @default(now())
tsServer DateTime @default(now()) @map("ts_server")
schemaVersion String? @map("schema_version")
seq BigInt? @map("seq")
status String
message String?
ip String?
fwVersion String?
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
machine Machine @relation(fields: [machineId], references: [id], onDelete: Cascade)
@@index([orgId, machineId, ts])
}
model MachineKpiSnapshot {
id String @id @default(uuid())
orgId String
machineId String
ts DateTime @default(now())
workOrderId String?
sku String?
target Int?
good Int?
scrap Int?
cycleCount Int?
goodParts Int?
scrapParts Int?
cavities Int?
cycleTime Float? // theoretical/target
actualCycle Float? // if you want (optional)
availability Float?
performance Float?
quality Float?
oee Float?
trackingEnabled Boolean?
productionStarted Boolean?
tsServer DateTime @default(now()) @map("ts_server")
schemaVersion String? @map("schema_version")
seq BigInt? @map("seq")
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
machine Machine @relation(fields: [machineId], references: [id], onDelete: Cascade)
@@index([orgId, machineId, ts])
}
model MachineEvent {
id String @id @default(uuid())
orgId String
machineId String
ts DateTime @default(now())
topic String // "anomaly-detected"
eventType String // "slow-cycle"
severity String // "critical"
requiresAck Boolean @default(false)
title String
description String?
tsServer DateTime @default(now()) @map("ts_server")
schemaVersion String? @map("schema_version")
seq BigInt? @map("seq")
// store the raw data blob so we don't lose fields
data Json?
workOrderId String?
sku String?
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
machine Machine @relation(fields: [machineId], references: [id], onDelete: Cascade)
@@index([orgId, machineId, ts])
@@index([orgId, machineId, eventType, ts])
}
model MachineCycle {
id String @id @default(uuid())
orgId String
machineId String
ts DateTime @default(now())
cycleCount Int?
actualCycleTime Float
theoreticalCycleTime Float?
workOrderId String?
sku String?
cavities Int?
goodDelta Int?
scrapDelta Int?
tsServer DateTime @default(now()) @map("ts_server")
schemaVersion String? @map("schema_version")
seq BigInt? @map("seq")
createdAt DateTime @default(now())
machine Machine @relation(fields: [machineId], references: [id])
@@index([orgId, machineId, ts])
@@index([orgId, machineId, cycleCount])
}
model MachineWorkOrder {
id String @id @default(uuid())
orgId String
machineId String
workOrderId String
sku String?
targetQty Int?
cycleTime Float?
status String @default("PENDING")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
machine Machine @relation(fields: [machineId], references: [id], onDelete: Cascade)
@@unique([machineId, workOrderId])
@@index([orgId, machineId])
@@index([orgId, workOrderId])
@@map("machine_work_orders")
}
model IngestLog {
id String @id @default(uuid())
orgId String?
machineId String?
endpoint String
schemaVersion String?
seq BigInt?
tsDevice DateTime?
tsServer DateTime @default(now())
ok Boolean
status Int
errorCode String?
errorMsg String?
body Json?
ip String?
userAgent String?
@@index([endpoint, tsServer])
@@index([machineId, tsServer])
@@index([machineId, seq])
}
model OrgSettings {
orgId String @id @map("org_id")
timezone String @default("UTC")
shiftChangeCompMin Int @default(10) @map("shift_change_comp_min")
lunchBreakMin Int @default(30) @map("lunch_break_min")
stoppageMultiplier Float @default(1.5) @map("stoppage_multiplier")
oeeAlertThresholdPct Float @default(90) @map("oee_alert_threshold_pct")
macroStoppageMultiplier Float @default(5) @map("macro_stoppage_multiplier")
performanceThresholdPct Float @default(85) @map("performance_threshold_pct")
qualitySpikeDeltaPct Float @default(5) @map("quality_spike_delta_pct")
alertsJson Json? @map("alerts_json")
defaultsJson Json? @map("defaults_json")
version Int @default(1)
updatedAt DateTime @updatedAt @map("updated_at")
updatedBy String? @map("updated_by")
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
@@map("org_settings")
}
model OrgShift {
id String @id @default(uuid())
orgId String @map("org_id")
name String
startTime String @map("start_time")
endTime String @map("end_time")
sortOrder Int @map("sort_order")
enabled Boolean @default(true)
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
@@index([orgId])
@@index([orgId, sortOrder])
@@map("org_shifts")
}
model MachineSettings {
machineId String @id @map("machine_id")
orgId String @map("org_id")
overridesJson Json? @map("overrides_json")
updatedAt DateTime @updatedAt @map("updated_at")
updatedBy String? @map("updated_by")
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
machine Machine @relation(fields: [machineId], references: [id], onDelete: Cascade)
@@index([orgId])
@@map("machine_settings")
}
model SettingsAudit {
id String @id @default(uuid())
orgId String @map("org_id")
machineId String? @map("machine_id")
actorId String? @map("actor_id")
source String
payloadJson Json @map("payload_json")
createdAt DateTime @default(now()) @map("created_at")
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
machine Machine? @relation(fields: [machineId], references: [id], onDelete: Cascade)
@@index([orgId, createdAt])
@@index([machineId, createdAt])
@@map("settings_audit")
}