Files
rack-planner/prisma/schema.prisma

136 lines
4.4 KiB
Plaintext

generator client {
provider = "prisma-client-js"
// linux-musl-openssl-3.0.x = Alpine Linux (Docker); native = local dev/build
binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
// NOTE: SQLite does not support Prisma enums.
// All enum-like fields are stored as String with validation enforced in the service layer.
// Valid values are documented in server/lib/constants.ts and client/src/types/index.ts
model Rack {
id String @id @default(cuid())
name String
totalU Int @default(42)
location String?
displayOrder Int @default(0)
modules Module[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Module {
id String @id @default(cuid())
rackId String
rack Rack @relation(fields: [rackId], references: [id], onDelete: Cascade)
name String
type String // ModuleType: SWITCH | AGGREGATE_SWITCH | MODEM | ROUTER | NAS | PDU | PATCH_PANEL | SERVER | FIREWALL | AP | BLANK | OTHER
uPosition Int
uSize Int @default(1)
manufacturer String?
model String?
ipAddress String?
notes String?
ports Port[]
serviceNodes ServiceNode[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Port {
id String @id @default(cuid())
moduleId String
module Module @relation(fields: [moduleId], references: [id], onDelete: Cascade)
portNumber Int
label String?
portType String @default("ETHERNET") // PortType: ETHERNET | SFP | SFP_PLUS | QSFP | CONSOLE | UPLINK
mode String @default("ACCESS") // VlanMode: ACCESS | TRUNK | HYBRID
nativeVlan Int?
vlans PortVlan[]
notes String?
// Connections — port can be source or target of a patch cable
sourceConnections Connection[] @relation("SourcePort")
targetConnections Connection[] @relation("TargetPort")
}
model Connection {
id String @id @default(cuid())
fromPortId String
fromPort Port @relation("SourcePort", fields: [fromPortId], references: [id], onDelete: Cascade)
toPortId String
toPort Port @relation("TargetPort", fields: [toPortId], references: [id], onDelete: Cascade)
color String? // Optional custom cable color
label String? // Optional cable label (e.g. "Cable #104")
createdAt DateTime @default(now())
@@unique([fromPortId, toPortId])
}
model Vlan {
id String @id @default(cuid())
vlanId Int @unique
name String
description String?
color String?
ports PortVlan[]
}
model PortVlan {
portId String
port Port @relation(fields: [portId], references: [id], onDelete: Cascade)
vlanId String
vlan Vlan @relation(fields: [vlanId], references: [id], onDelete: Cascade)
tagged Boolean @default(false)
@@id([portId, vlanId])
}
// --- Service Mapper ---
model ServiceMap {
id String @id @default(cuid())
name String
description String?
nodes ServiceNode[]
edges ServiceEdge[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model ServiceNode {
id String @id @default(cuid())
mapId String
map ServiceMap @relation(fields: [mapId], references: [id], onDelete: Cascade)
label String
nodeType String // NodeType: SERVICE | DATABASE | API | DEVICE | EXTERNAL | USER | VLAN | FIREWALL | LOAD_BALANCER | NOTE
positionX Float
positionY Float
metadata String?
color String?
icon String?
moduleId String?
module Module? @relation(fields: [moduleId], references: [id], onDelete: SetNull)
sourceEdges ServiceEdge[] @relation("EdgeSource")
targetEdges ServiceEdge[] @relation("EdgeTarget")
}
model ServiceEdge {
id String @id @default(cuid())
mapId String
map ServiceMap @relation(fields: [mapId], references: [id], onDelete: Cascade)
sourceId String
source ServiceNode @relation("EdgeSource", fields: [sourceId], references: [id], onDelete: Cascade)
targetId String
target ServiceNode @relation("EdgeTarget", fields: [targetId], references: [id], onDelete: Cascade)
label String?
edgeType String @default("smoothstep")
animated Boolean @default(false)
metadata String?
}