// 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" } 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é status HostStatus @default(UNKNOWN) // Origine de la fiche : saisie manuelle ou découverte source HostSource @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]) } enum HostStatus { UP DOWN UNKNOWN } enum HostSource { MANUAL DISCOVERED IMPORTED } // ===================================================================== // Ports ouverts sur un hôte // ===================================================================== model Port { id String @id @default(cuid()) number Int protocol Protocol @default(TCP) serviceName String? // ex: "http", "ssh", renseigné ou deviné banner String? // Banner applicatif collecté state PortState @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]) } enum Protocol { TCP UDP } enum PortState { OPEN CLOSED FILTERED UNKNOWN } // ===================================================================== // 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()) type ScanType status ScanStatus @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]) } enum ScanType { PING PORT ARP MDNS FULL } enum ScanStatus { PENDING RUNNING COMPLETED FAILED CANCELLED } // 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]) }