// IPAM — Schéma Prisma // --------------------------------------------------------------------- // Prisma n'accepte PAS `env()` pour le champ `provider` (seulement pour `url`). // Le provider par défaut est donc `sqlite`. Pour basculer vers PostgreSQL : // npm run db:use-postgres // puis régénérer le client : `npm run db:generate` et migrer : `npm run db:migrate`. // Pour revenir à SQLite : `npm run db:use-sqlite`. // --------------------------------------------------------------------- generator client { provider = "prisma-client-js" // - native : dev local (macOS / Linux glibc) // - linux-musl-openssl-3.0.x : runtime Alpine x86_64 // - linux-musl-arm64-openssl-3.0.x : runtime Alpine arm64 (Raspberry Pi, Apple Silicon en Docker, etc.) binaryTargets = ["native", "linux-musl-openssl-3.0.x", "linux-musl-arm64-openssl-3.0.x"] } datasource db { provider = "sqlite" url = env("DATABASE_URL") } // ===================================================================== // Réseaux (subnets / VLAN) // ===================================================================== model Network { id String @id @default(cuid()) name String cidr String @unique // ex: "192.168.1.0/24" description String? vlanId Int? gateway String? dnsServers String? // CSV — compat SQLite (pas de array natif) color String? // Couleur d'affichage UI hosts Host[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([cidr]) } // ===================================================================== // Hôtes (une IP = un hôte) // ===================================================================== model Host { id String @id @default(cuid()) ipAddress String @unique // IPv4/IPv6 hostname String? macAddress String? description String? vendor String? // Issue du MAC (OUI) ou d'une fingerprint osGuess String? // OS détecté / renseigné // Valeurs : "UP" | "DOWN" | "UNKNOWN" (validation Zod côté app) status String @default("UNKNOWN") // Origine de la fiche : "MANUAL" | "DISCOVERED" | "IMPORTED" source String @default("MANUAL") // Relations networkId String? network Network? @relation(fields: [networkId], references: [id], onDelete: SetNull) ports Port[] applications HostApplication[] scanResults ScanResult[] lastSeenAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([ipAddress]) @@index([networkId]) @@index([status]) } // NOTE : les enums Prisma ne sont pas supportés par SQLite. On stocke // donc tous les statuts/types en `String` et on valide les valeurs // possibles côté app via Zod. Constantes documentées au-dessus de // chaque champ. // ===================================================================== // Ports ouverts sur un hôte // ===================================================================== model Port { id String @id @default(cuid()) number Int // Valeurs : "TCP" | "UDP" protocol String @default("TCP") serviceName String? // ex: "http", "ssh", renseigné ou deviné banner String? // Banner applicatif collecté // Valeurs : "OPEN" | "CLOSED" | "FILTERED" | "UNKNOWN" state String @default("OPEN") hostId String host Host @relation(fields: [hostId], references: [id], onDelete: Cascade) // Lien éventuel vers une application métier déclarée applicationId String? application Application? @relation(fields: [applicationId], references: [id], onDelete: SetNull) lastCheckedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([hostId, number, protocol]) @@index([hostId]) @@index([number]) } // Protocol : "TCP" | "UDP" — voir Port.protocol // PortState : "OPEN" | "CLOSED" | "FILTERED" | "UNKNOWN" — voir Port.state // ===================================================================== // Applications (Jellyfin, Home Assistant, Nextcloud, etc.) // ===================================================================== model Application { id String @id @default(cuid()) name String @unique description String? category String? // ex: "media", "monitoring", "storage" icon String? // URL ou clé d'icône url String? // URL principale d'accès hosts HostApplication[] ports Port[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } // Table de jointure Hôte <-> Application (N:N) model HostApplication { hostId String applicationId String host Host @relation(fields: [hostId], references: [id], onDelete: Cascade) application Application @relation(fields: [applicationId], references: [id], onDelete: Cascade) notes String? createdAt DateTime @default(now()) @@id([hostId, applicationId]) } // ===================================================================== // Découverte réseau — historique des scans // ===================================================================== model Scan { id String @id @default(cuid()) // Valeurs : "PING" | "PORT" | "ARP" | "MDNS" | "FULL" type String // Valeurs : "PENDING" | "RUNNING" | "COMPLETED" | "FAILED" | "CANCELLED" status String @default("PENDING") target String // CIDR, IP, ou hôte params String? // JSON (Zod validé côté app) startedAt DateTime? endedAt DateTime? hostsFound Int @default(0) portsFound Int @default(0) errorMessage String? results ScanResult[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([status]) @@index([type]) } // ScanType : "PING" | "PORT" | "ARP" | "MDNS" | "FULL" — voir Scan.type // ScanStatus : "PENDING" | "RUNNING" | "COMPLETED" | "FAILED" | "CANCELLED" — voir Scan.status // Résultat individuel d'un scan (rattaché à un hôte quand possible) model ScanResult { id String @id @default(cuid()) scanId String scan Scan @relation(fields: [scanId], references: [id], onDelete: Cascade) ipAddress String hostId String? host Host? @relation(fields: [hostId], references: [id], onDelete: SetNull) data String // JSON (ports trouvés, services mDNS, MAC, etc.) createdAt DateTime @default(now()) @@index([scanId]) @@index([ipAddress]) }