1206 lines
33 KiB
Plaintext
1206 lines
33 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
enum Role {
|
|
SUPER_ADMIN
|
|
TENANT_ADMIN
|
|
OPERATOR
|
|
VIEWER
|
|
}
|
|
|
|
enum TenantStatus {
|
|
ACTIVE
|
|
SUSPENDED
|
|
TRIAL
|
|
CANCELLED
|
|
}
|
|
|
|
enum VmStatus {
|
|
RUNNING
|
|
STOPPED
|
|
PAUSED
|
|
MIGRATING
|
|
ERROR
|
|
}
|
|
|
|
enum VmType {
|
|
QEMU
|
|
LXC
|
|
}
|
|
|
|
enum NodeStatus {
|
|
ONLINE
|
|
OFFLINE
|
|
MAINTENANCE
|
|
}
|
|
|
|
enum Currency {
|
|
NGN
|
|
USD
|
|
GHS
|
|
KES
|
|
ZAR
|
|
}
|
|
|
|
enum PaymentProvider {
|
|
PAYSTACK
|
|
FLUTTERWAVE
|
|
MANUAL
|
|
}
|
|
|
|
enum InvoiceStatus {
|
|
DRAFT
|
|
PENDING
|
|
PAID
|
|
OVERDUE
|
|
CANCELLED
|
|
REFUNDED
|
|
}
|
|
|
|
enum BackupStatus {
|
|
PENDING
|
|
RUNNING
|
|
COMPLETED
|
|
FAILED
|
|
EXPIRED
|
|
}
|
|
|
|
enum BackupType {
|
|
FULL
|
|
INCREMENTAL
|
|
SNAPSHOT
|
|
}
|
|
|
|
enum BackupSchedule {
|
|
MANUAL
|
|
DAILY
|
|
WEEKLY
|
|
MONTHLY
|
|
}
|
|
|
|
enum BackupSource {
|
|
LOCAL
|
|
PBS
|
|
REMOTE
|
|
}
|
|
|
|
enum BackupRestoreMode {
|
|
FULL_VM
|
|
FILES
|
|
SINGLE_FILE
|
|
}
|
|
|
|
enum BackupRestoreStatus {
|
|
PENDING
|
|
RUNNING
|
|
COMPLETED
|
|
FAILED
|
|
}
|
|
|
|
enum SnapshotFrequency {
|
|
HOURLY
|
|
DAILY
|
|
WEEKLY
|
|
}
|
|
|
|
enum Severity {
|
|
INFO
|
|
WARNING
|
|
ERROR
|
|
CRITICAL
|
|
}
|
|
|
|
enum SecurityStatus {
|
|
OPEN
|
|
INVESTIGATING
|
|
RESOLVED
|
|
FALSE_POSITIVE
|
|
}
|
|
|
|
enum Direction {
|
|
INBOUND
|
|
OUTBOUND
|
|
BOTH
|
|
}
|
|
|
|
enum FirewallAction {
|
|
ALLOW
|
|
DENY
|
|
RATE_LIMIT
|
|
LOG
|
|
}
|
|
|
|
enum Protocol {
|
|
TCP
|
|
UDP
|
|
ICMP
|
|
ANY
|
|
}
|
|
|
|
enum AppliesTo {
|
|
ALL_NODES
|
|
ALL_VMS
|
|
SPECIFIC_NODE
|
|
SPECIFIC_VM
|
|
}
|
|
|
|
enum ResourceType {
|
|
VM
|
|
TENANT
|
|
USER
|
|
BACKUP
|
|
INVOICE
|
|
NODE
|
|
NETWORK
|
|
SYSTEM
|
|
SECURITY
|
|
BILLING
|
|
}
|
|
|
|
enum SettingType {
|
|
PROXMOX
|
|
PAYMENT
|
|
EMAIL
|
|
SECURITY
|
|
NETWORK
|
|
GENERAL
|
|
}
|
|
|
|
enum OperationTaskStatus {
|
|
QUEUED
|
|
RUNNING
|
|
SUCCESS
|
|
FAILED
|
|
RETRYING
|
|
CANCELED
|
|
}
|
|
|
|
enum OperationTaskType {
|
|
VM_POWER
|
|
VM_MIGRATION
|
|
VM_REINSTALL
|
|
VM_NETWORK
|
|
VM_CONFIG
|
|
VM_BACKUP
|
|
VM_SNAPSHOT
|
|
VM_CREATE
|
|
VM_DELETE
|
|
SYSTEM_SYNC
|
|
}
|
|
|
|
enum PowerScheduleAction {
|
|
START
|
|
STOP
|
|
RESTART
|
|
SHUTDOWN
|
|
}
|
|
|
|
enum TemplateType {
|
|
APPLICATION
|
|
KVM_TEMPLATE
|
|
LXC_TEMPLATE
|
|
ISO_IMAGE
|
|
ARCHIVE
|
|
}
|
|
|
|
enum ProductType {
|
|
VPS
|
|
CLOUD
|
|
}
|
|
|
|
enum ServiceLifecycleStatus {
|
|
ACTIVE
|
|
SUSPENDED
|
|
TERMINATED
|
|
}
|
|
|
|
enum IpVersion {
|
|
IPV4
|
|
IPV6
|
|
}
|
|
|
|
enum IpScope {
|
|
PUBLIC
|
|
PRIVATE
|
|
}
|
|
|
|
enum IpAddressStatus {
|
|
AVAILABLE
|
|
ASSIGNED
|
|
RESERVED
|
|
RETIRED
|
|
}
|
|
|
|
enum IpAssignmentType {
|
|
PRIMARY
|
|
ADDITIONAL
|
|
FLOATING
|
|
}
|
|
|
|
enum PrivateNetworkType {
|
|
BRIDGE
|
|
VLAN
|
|
SDN_ZONE
|
|
VNET
|
|
}
|
|
|
|
enum PrivateNetworkAttachmentStatus {
|
|
ATTACHED
|
|
DETACHED
|
|
}
|
|
|
|
enum IpAllocationStrategy {
|
|
FIRST_AVAILABLE
|
|
BEST_FIT
|
|
}
|
|
|
|
enum HealthCheckTargetType {
|
|
NODE
|
|
VM
|
|
CLUSTER
|
|
}
|
|
|
|
enum HealthCheckType {
|
|
CONNECTIVITY
|
|
RESOURCE_THRESHOLD
|
|
SERVICE_PORT
|
|
}
|
|
|
|
enum HealthCheckStatus {
|
|
PASS
|
|
WARNING
|
|
FAIL
|
|
}
|
|
|
|
enum MonitoringAlertStatus {
|
|
OPEN
|
|
ACKNOWLEDGED
|
|
RESOLVED
|
|
}
|
|
|
|
enum AlertChannel {
|
|
EMAIL
|
|
WEBHOOK
|
|
IN_APP
|
|
}
|
|
|
|
enum AlertDispatchStatus {
|
|
QUEUED
|
|
SENT
|
|
FAILED
|
|
SKIPPED
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
password_hash String
|
|
full_name String?
|
|
role Role @default(VIEWER)
|
|
tenant_id String?
|
|
is_active Boolean @default(true)
|
|
last_login_at DateTime?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
tenant Tenant? @relation(fields: [tenant_id], references: [id], onDelete: SetNull)
|
|
|
|
@@index([tenant_id])
|
|
}
|
|
|
|
model Tenant {
|
|
id String @id @default(cuid())
|
|
name String
|
|
slug String @unique
|
|
status TenantStatus @default(ACTIVE)
|
|
plan String @default("starter")
|
|
owner_email String
|
|
member_emails Json @default("[]")
|
|
vm_limit Int @default(5)
|
|
cpu_limit Int @default(16)
|
|
ram_limit_mb Int @default(32768)
|
|
disk_limit_gb Int @default(500)
|
|
balance Decimal @default(0) @db.Decimal(14, 2)
|
|
currency Currency @default(NGN)
|
|
payment_provider PaymentProvider @default(PAYSTACK)
|
|
notes String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
users User[]
|
|
virtual_machines VirtualMachine[]
|
|
invoices Invoice[]
|
|
usage_records UsageRecord[]
|
|
provisioned_services ProvisionedService[]
|
|
backups Backup[]
|
|
backup_policies BackupPolicy[]
|
|
assigned_ip_addresses IpAddressPool[] @relation("AssignedIpTenant")
|
|
ip_assignments IpAssignment[]
|
|
private_network_attachments PrivateNetworkAttachment[]
|
|
ip_quota TenantIpQuota?
|
|
reserved_ip_ranges IpReservedRange[]
|
|
ip_pool_policies IpPoolPolicy[]
|
|
health_checks ServerHealthCheck[]
|
|
monitoring_alert_rules MonitoringAlertRule[]
|
|
monitoring_alert_events MonitoringAlertEvent[]
|
|
|
|
@@index([status])
|
|
@@index([owner_email])
|
|
}
|
|
|
|
model ProxmoxNode {
|
|
id String @id @default(cuid())
|
|
name String
|
|
hostname String @unique
|
|
status NodeStatus @default(OFFLINE)
|
|
cpu_cores Int @default(8)
|
|
cpu_usage Float @default(0)
|
|
ram_total_mb Int @default(32768)
|
|
ram_used_mb Int @default(0)
|
|
disk_total_gb Int @default(500)
|
|
disk_used_gb Int @default(0)
|
|
vm_count Int @default(0)
|
|
uptime_seconds Int @default(0)
|
|
pve_version String?
|
|
is_connected Boolean @default(false)
|
|
last_sync_at DateTime?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
virtual_machines VirtualMachine[]
|
|
placement_policies NodePlacementPolicy[]
|
|
vmid_ranges VmIdRange[]
|
|
health_checks ServerHealthCheck[]
|
|
monitoring_alert_rules MonitoringAlertRule[]
|
|
monitoring_alert_events MonitoringAlertEvent[]
|
|
|
|
@@index([status])
|
|
}
|
|
|
|
model BillingPlan {
|
|
id String @id @default(cuid())
|
|
name String
|
|
slug String @unique
|
|
description String?
|
|
price_monthly Decimal @db.Decimal(12, 2)
|
|
price_hourly Decimal @db.Decimal(12, 4)
|
|
currency Currency @default(NGN)
|
|
cpu_cores Int
|
|
ram_mb Int
|
|
disk_gb Int
|
|
bandwidth_gb Int?
|
|
is_active Boolean @default(true)
|
|
features Json @default("[]")
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
virtual_machines VirtualMachine[]
|
|
usage_records UsageRecord[]
|
|
backup_policies BackupPolicy[]
|
|
|
|
@@index([is_active])
|
|
}
|
|
|
|
model VirtualMachine {
|
|
id String @id @default(cuid())
|
|
name String
|
|
vmid Int
|
|
status VmStatus @default(STOPPED)
|
|
type VmType @default(QEMU)
|
|
node String
|
|
node_id String?
|
|
tenant_id String
|
|
billing_plan_id String?
|
|
os_template String?
|
|
cpu_cores Int @default(2)
|
|
ram_mb Int @default(2048)
|
|
disk_gb Int @default(40)
|
|
ip_address String?
|
|
cpu_usage Float @default(0)
|
|
ram_usage Float @default(0)
|
|
disk_usage Float @default(0)
|
|
network_in Float @default(0)
|
|
network_out Float @default(0)
|
|
uptime_seconds Int @default(0)
|
|
started_at DateTime?
|
|
last_backup_at DateTime?
|
|
proxmox_upid String?
|
|
last_sync_at DateTime?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenant_id], references: [id], onDelete: Cascade)
|
|
node_ref ProxmoxNode? @relation(fields: [node_id], references: [id], onDelete: SetNull)
|
|
billing_plan BillingPlan? @relation(fields: [billing_plan_id], references: [id], onDelete: SetNull)
|
|
usage_records UsageRecord[]
|
|
backups Backup[]
|
|
operation_tasks OperationTask[]
|
|
power_schedules PowerSchedule[]
|
|
provisioned_service ProvisionedService?
|
|
snapshot_jobs SnapshotJob[]
|
|
backup_restores_source BackupRestoreTask[] @relation("BackupRestoreSourceVm")
|
|
backup_restores_target BackupRestoreTask[] @relation("BackupRestoreTargetVm")
|
|
assigned_ip_addresses IpAddressPool[] @relation("AssignedIpVm")
|
|
ip_assignments IpAssignment[]
|
|
private_network_attachments PrivateNetworkAttachment[]
|
|
health_checks ServerHealthCheck[]
|
|
monitoring_alert_rules MonitoringAlertRule[]
|
|
monitoring_alert_events MonitoringAlertEvent[]
|
|
|
|
@@unique([vmid, node])
|
|
@@index([tenant_id])
|
|
@@index([node])
|
|
@@index([status])
|
|
}
|
|
|
|
model ServerHealthCheck {
|
|
id String @id @default(cuid())
|
|
name String
|
|
description String?
|
|
target_type HealthCheckTargetType
|
|
check_type HealthCheckType @default(RESOURCE_THRESHOLD)
|
|
tenant_id String?
|
|
vm_id String?
|
|
node_id String?
|
|
cpu_warn_pct Float?
|
|
cpu_critical_pct Float?
|
|
ram_warn_pct Float?
|
|
ram_critical_pct Float?
|
|
disk_warn_pct Float?
|
|
disk_critical_pct Float?
|
|
disk_io_read_warn Float?
|
|
disk_io_read_critical Float?
|
|
disk_io_write_warn Float?
|
|
disk_io_write_critical Float?
|
|
network_in_warn Float?
|
|
network_in_critical Float?
|
|
network_out_warn Float?
|
|
network_out_critical Float?
|
|
latency_warn_ms Int?
|
|
latency_critical_ms Int?
|
|
schedule_minutes Int @default(5)
|
|
enabled Boolean @default(true)
|
|
last_run_at DateTime?
|
|
next_run_at DateTime?
|
|
created_by String?
|
|
metadata Json @default("{}")
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
tenant Tenant? @relation(fields: [tenant_id], references: [id], onDelete: SetNull)
|
|
vm VirtualMachine? @relation(fields: [vm_id], references: [id], onDelete: SetNull)
|
|
node ProxmoxNode? @relation(fields: [node_id], references: [id], onDelete: SetNull)
|
|
results ServerHealthCheckResult[]
|
|
|
|
@@index([enabled, next_run_at])
|
|
@@index([tenant_id, enabled])
|
|
@@index([vm_id, enabled])
|
|
@@index([node_id, enabled])
|
|
}
|
|
|
|
model ServerHealthCheckResult {
|
|
id String @id @default(cuid())
|
|
check_id String
|
|
status HealthCheckStatus
|
|
severity Severity @default(INFO)
|
|
message String?
|
|
latency_ms Int?
|
|
cpu_usage Float?
|
|
ram_usage Float?
|
|
disk_usage Float?
|
|
disk_io_read Float?
|
|
disk_io_write Float?
|
|
network_in Float?
|
|
network_out Float?
|
|
metadata Json @default("{}")
|
|
checked_at DateTime @default(now())
|
|
created_at DateTime @default(now())
|
|
|
|
check ServerHealthCheck @relation(fields: [check_id], references: [id], onDelete: Cascade)
|
|
|
|
@@index([check_id, checked_at])
|
|
@@index([status, checked_at])
|
|
}
|
|
|
|
model MonitoringAlertRule {
|
|
id String @id @default(cuid())
|
|
name String
|
|
description String?
|
|
tenant_id String?
|
|
vm_id String?
|
|
node_id String?
|
|
cpu_threshold_pct Float?
|
|
ram_threshold_pct Float?
|
|
disk_threshold_pct Float?
|
|
disk_io_read_threshold Float?
|
|
disk_io_write_threshold Float?
|
|
network_in_threshold Float?
|
|
network_out_threshold Float?
|
|
consecutive_breaches Int @default(1)
|
|
evaluation_window_minutes Int @default(15)
|
|
severity Severity @default(WARNING)
|
|
channels Json @default("[\"IN_APP\"]")
|
|
enabled Boolean @default(true)
|
|
last_evaluated_at DateTime?
|
|
created_by String?
|
|
metadata Json @default("{}")
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
tenant Tenant? @relation(fields: [tenant_id], references: [id], onDelete: SetNull)
|
|
vm VirtualMachine? @relation(fields: [vm_id], references: [id], onDelete: SetNull)
|
|
node ProxmoxNode? @relation(fields: [node_id], references: [id], onDelete: SetNull)
|
|
events MonitoringAlertEvent[]
|
|
|
|
@@index([enabled, severity])
|
|
@@index([tenant_id, enabled])
|
|
@@index([vm_id, enabled])
|
|
@@index([node_id, enabled])
|
|
}
|
|
|
|
model MonitoringAlertEvent {
|
|
id String @id @default(cuid())
|
|
rule_id String
|
|
tenant_id String?
|
|
vm_id String?
|
|
node_id String?
|
|
status MonitoringAlertStatus @default(OPEN)
|
|
severity Severity @default(WARNING)
|
|
title String
|
|
message String?
|
|
metric_key String?
|
|
trigger_value Float?
|
|
threshold_value Float?
|
|
breach_count Int @default(1)
|
|
resolved_at DateTime?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
rule MonitoringAlertRule @relation(fields: [rule_id], references: [id], onDelete: Cascade)
|
|
tenant Tenant? @relation(fields: [tenant_id], references: [id], onDelete: SetNull)
|
|
vm VirtualMachine? @relation(fields: [vm_id], references: [id], onDelete: SetNull)
|
|
node ProxmoxNode? @relation(fields: [node_id], references: [id], onDelete: SetNull)
|
|
notifications MonitoringAlertNotification[]
|
|
|
|
@@index([rule_id, status])
|
|
@@index([status, severity, created_at])
|
|
@@index([tenant_id, status])
|
|
@@index([vm_id, status])
|
|
@@index([node_id, status])
|
|
}
|
|
|
|
model MonitoringAlertNotification {
|
|
id String @id @default(cuid())
|
|
alert_event_id String
|
|
channel AlertChannel
|
|
destination String?
|
|
status AlertDispatchStatus @default(QUEUED)
|
|
provider_message String?
|
|
sent_at DateTime?
|
|
created_at DateTime @default(now())
|
|
|
|
event MonitoringAlertEvent @relation(fields: [alert_event_id], references: [id], onDelete: Cascade)
|
|
|
|
@@index([alert_event_id, status])
|
|
@@index([status, created_at])
|
|
}
|
|
|
|
model IpAddressPool {
|
|
id String @id @default(cuid())
|
|
address String
|
|
cidr Int
|
|
version IpVersion
|
|
scope IpScope @default(PUBLIC)
|
|
status IpAddressStatus @default(AVAILABLE)
|
|
gateway String?
|
|
subnet String?
|
|
server String?
|
|
node_id String?
|
|
node_hostname String?
|
|
bridge String?
|
|
vlan_tag Int?
|
|
sdn_zone String?
|
|
tags Json @default("[]")
|
|
metadata Json @default("{}")
|
|
assigned_vm_id String?
|
|
assigned_tenant_id String?
|
|
imported_by String?
|
|
imported_at DateTime @default(now())
|
|
assigned_at DateTime?
|
|
returned_at DateTime?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
assigned_vm VirtualMachine? @relation("AssignedIpVm", fields: [assigned_vm_id], references: [id], onDelete: SetNull)
|
|
assigned_tenant Tenant? @relation("AssignedIpTenant", fields: [assigned_tenant_id], references: [id], onDelete: SetNull)
|
|
assignments IpAssignment[]
|
|
|
|
@@unique([address, cidr])
|
|
@@index([status, scope, version])
|
|
@@index([node_hostname, bridge, vlan_tag])
|
|
@@index([assigned_vm_id, status])
|
|
@@index([assigned_tenant_id, status])
|
|
}
|
|
|
|
model TenantIpQuota {
|
|
id String @id @default(cuid())
|
|
tenant_id String @unique
|
|
ipv4_limit Int?
|
|
ipv6_limit Int?
|
|
reserved_ipv4 Int @default(0)
|
|
reserved_ipv6 Int @default(0)
|
|
burst_allowed Boolean @default(false)
|
|
burst_ipv4_limit Int?
|
|
burst_ipv6_limit Int?
|
|
is_active Boolean @default(true)
|
|
metadata Json @default("{}")
|
|
created_by String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenant_id], references: [id], onDelete: Cascade)
|
|
|
|
@@index([is_active])
|
|
}
|
|
|
|
model IpReservedRange {
|
|
id String @id @default(cuid())
|
|
name String
|
|
cidr String
|
|
version IpVersion
|
|
scope IpScope @default(PUBLIC)
|
|
tenant_id String?
|
|
reason String?
|
|
node_hostname String?
|
|
bridge String?
|
|
vlan_tag Int?
|
|
sdn_zone String?
|
|
is_active Boolean @default(true)
|
|
metadata Json @default("{}")
|
|
created_by String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
tenant Tenant? @relation(fields: [tenant_id], references: [id], onDelete: SetNull)
|
|
|
|
@@index([scope, version, is_active])
|
|
@@index([tenant_id, is_active])
|
|
@@index([node_hostname, bridge, vlan_tag, is_active])
|
|
}
|
|
|
|
model IpPoolPolicy {
|
|
id String @id @default(cuid())
|
|
name String
|
|
tenant_id String?
|
|
scope IpScope?
|
|
version IpVersion?
|
|
node_hostname String?
|
|
bridge String?
|
|
vlan_tag Int?
|
|
sdn_zone String?
|
|
allocation_strategy IpAllocationStrategy @default(BEST_FIT)
|
|
enforce_quota Boolean @default(true)
|
|
disallow_reserved_use Boolean @default(true)
|
|
is_active Boolean @default(true)
|
|
priority Int @default(100)
|
|
metadata Json @default("{}")
|
|
created_by String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
tenant Tenant? @relation(fields: [tenant_id], references: [id], onDelete: SetNull)
|
|
|
|
@@index([tenant_id, is_active, priority])
|
|
@@index([scope, version, is_active])
|
|
@@index([node_hostname, bridge, vlan_tag, is_active])
|
|
}
|
|
|
|
model IpAssignment {
|
|
id String @id @default(cuid())
|
|
ip_address_id String
|
|
vm_id String
|
|
tenant_id String?
|
|
assignment_type IpAssignmentType @default(ADDITIONAL)
|
|
interface_name String?
|
|
notes String?
|
|
metadata Json @default("{}")
|
|
assigned_by String?
|
|
assigned_at DateTime @default(now())
|
|
released_at DateTime?
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
ip_address IpAddressPool @relation(fields: [ip_address_id], references: [id], onDelete: Cascade)
|
|
vm VirtualMachine @relation(fields: [vm_id], references: [id], onDelete: Cascade)
|
|
tenant Tenant? @relation(fields: [tenant_id], references: [id], onDelete: SetNull)
|
|
|
|
@@index([ip_address_id, is_active])
|
|
@@index([vm_id, is_active])
|
|
@@index([tenant_id, is_active])
|
|
}
|
|
|
|
model PrivateNetwork {
|
|
id String @id @default(cuid())
|
|
name String
|
|
slug String @unique
|
|
network_type PrivateNetworkType @default(VLAN)
|
|
cidr String
|
|
gateway String?
|
|
bridge String?
|
|
vlan_tag Int?
|
|
sdn_zone String?
|
|
server String?
|
|
node_hostname String?
|
|
is_private Boolean @default(true)
|
|
metadata Json @default("{}")
|
|
created_by String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
attachments PrivateNetworkAttachment[]
|
|
|
|
@@index([network_type])
|
|
@@index([node_hostname, bridge, vlan_tag])
|
|
}
|
|
|
|
model PrivateNetworkAttachment {
|
|
id String @id @default(cuid())
|
|
network_id String
|
|
vm_id String
|
|
tenant_id String?
|
|
interface_name String?
|
|
requested_ip String?
|
|
status PrivateNetworkAttachmentStatus @default(ATTACHED)
|
|
metadata Json @default("{}")
|
|
attached_by String?
|
|
attached_at DateTime @default(now())
|
|
detached_at DateTime?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
network PrivateNetwork @relation(fields: [network_id], references: [id], onDelete: Cascade)
|
|
vm VirtualMachine @relation(fields: [vm_id], references: [id], onDelete: Cascade)
|
|
tenant Tenant? @relation(fields: [tenant_id], references: [id], onDelete: SetNull)
|
|
|
|
@@unique([network_id, vm_id, interface_name])
|
|
@@index([vm_id, status])
|
|
@@index([tenant_id, status])
|
|
@@index([network_id, status])
|
|
}
|
|
|
|
model AppTemplate {
|
|
id String @id @default(cuid())
|
|
name String
|
|
slug String @unique
|
|
template_type TemplateType
|
|
virtualization_type VmType?
|
|
source String?
|
|
description String?
|
|
default_cloud_init String?
|
|
metadata Json @default("{}")
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
groups ApplicationGroupTemplate[]
|
|
provisioned_services ProvisionedService[]
|
|
|
|
@@index([template_type, is_active])
|
|
}
|
|
|
|
model ApplicationGroup {
|
|
id String @id @default(cuid())
|
|
name String
|
|
slug String @unique
|
|
description String?
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
templates ApplicationGroupTemplate[]
|
|
placement_policies NodePlacementPolicy[]
|
|
vmid_ranges VmIdRange[]
|
|
provisioned_services ProvisionedService[]
|
|
|
|
@@index([is_active])
|
|
}
|
|
|
|
model ApplicationGroupTemplate {
|
|
id String @id @default(cuid())
|
|
group_id String
|
|
template_id String
|
|
priority Int @default(100)
|
|
created_at DateTime @default(now())
|
|
|
|
group ApplicationGroup @relation(fields: [group_id], references: [id], onDelete: Cascade)
|
|
template AppTemplate @relation(fields: [template_id], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([group_id, template_id])
|
|
@@index([priority])
|
|
}
|
|
|
|
model NodePlacementPolicy {
|
|
id String @id @default(cuid())
|
|
group_id String?
|
|
node_id String?
|
|
product_type ProductType?
|
|
cpu_weight Int @default(40)
|
|
ram_weight Int @default(30)
|
|
disk_weight Int @default(20)
|
|
vm_count_weight Int @default(10)
|
|
max_vms Int?
|
|
min_free_ram_mb Int?
|
|
min_free_disk_gb Int?
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
group ApplicationGroup? @relation(fields: [group_id], references: [id], onDelete: SetNull)
|
|
node ProxmoxNode? @relation(fields: [node_id], references: [id], onDelete: SetNull)
|
|
|
|
@@index([group_id, is_active])
|
|
@@index([node_id, is_active])
|
|
@@index([product_type, is_active])
|
|
}
|
|
|
|
model VmIdRange {
|
|
id String @id @default(cuid())
|
|
node_id String?
|
|
node_hostname String
|
|
application_group_id String?
|
|
range_start Int
|
|
range_end Int
|
|
next_vmid Int
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
node ProxmoxNode? @relation(fields: [node_id], references: [id], onDelete: SetNull)
|
|
group ApplicationGroup? @relation(fields: [application_group_id], references: [id], onDelete: SetNull)
|
|
|
|
@@unique([node_hostname, range_start, range_end])
|
|
@@index([node_hostname, is_active])
|
|
@@index([application_group_id, is_active])
|
|
}
|
|
|
|
model OperationTask {
|
|
id String @id @default(cuid())
|
|
task_type OperationTaskType
|
|
status OperationTaskStatus @default(QUEUED)
|
|
vm_id String?
|
|
vm_name String?
|
|
node String?
|
|
requested_by String?
|
|
payload Json?
|
|
result Json?
|
|
error_message String?
|
|
proxmox_upid String?
|
|
scheduled_for DateTime?
|
|
started_at DateTime?
|
|
completed_at DateTime?
|
|
retry_count Int @default(0)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
vm VirtualMachine? @relation(fields: [vm_id], references: [id], onDelete: SetNull)
|
|
|
|
@@index([status])
|
|
@@index([task_type])
|
|
@@index([vm_id])
|
|
@@index([created_at])
|
|
}
|
|
|
|
model PowerSchedule {
|
|
id String @id @default(cuid())
|
|
vm_id String
|
|
action PowerScheduleAction
|
|
cron_expression String
|
|
timezone String @default("UTC")
|
|
enabled Boolean @default(true)
|
|
next_run_at DateTime?
|
|
last_run_at DateTime?
|
|
created_by String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
vm VirtualMachine @relation(fields: [vm_id], references: [id], onDelete: Cascade)
|
|
|
|
@@index([vm_id])
|
|
@@index([enabled, next_run_at])
|
|
}
|
|
|
|
model ProvisionedService {
|
|
id String @id @default(cuid())
|
|
service_group_id String?
|
|
vm_id String @unique
|
|
tenant_id String
|
|
product_type ProductType
|
|
lifecycle_status ServiceLifecycleStatus @default(ACTIVE)
|
|
application_group_id String?
|
|
template_id String?
|
|
package_options Json @default("{}")
|
|
suspended_reason String?
|
|
terminated_at DateTime?
|
|
created_by String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
vm VirtualMachine @relation(fields: [vm_id], references: [id], onDelete: Cascade)
|
|
tenant Tenant @relation(fields: [tenant_id], references: [id], onDelete: Cascade)
|
|
group ApplicationGroup? @relation(fields: [application_group_id], references: [id], onDelete: SetNull)
|
|
template AppTemplate? @relation(fields: [template_id], references: [id], onDelete: SetNull)
|
|
|
|
@@index([tenant_id, lifecycle_status])
|
|
@@index([service_group_id])
|
|
@@index([application_group_id])
|
|
}
|
|
|
|
model Invoice {
|
|
id String @id @default(cuid())
|
|
invoice_number String @unique
|
|
tenant_id String
|
|
tenant_name String?
|
|
status InvoiceStatus @default(PENDING)
|
|
amount Decimal @db.Decimal(14, 2)
|
|
currency Currency @default(NGN)
|
|
due_date DateTime
|
|
paid_date DateTime?
|
|
payment_provider PaymentProvider @default(MANUAL)
|
|
payment_reference String?
|
|
payment_url String?
|
|
line_items Json @default("[]")
|
|
notes String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenant_id], references: [id], onDelete: Cascade)
|
|
usage_records UsageRecord[]
|
|
|
|
@@index([tenant_id])
|
|
@@index([status])
|
|
@@index([due_date])
|
|
}
|
|
|
|
model UsageRecord {
|
|
id String @id @default(cuid())
|
|
vm_id String
|
|
vm_name String
|
|
tenant_id String
|
|
tenant_name String
|
|
billing_plan_id String?
|
|
plan_name String?
|
|
hours_used Decimal @default(1) @db.Decimal(8, 2)
|
|
price_per_hour Decimal @db.Decimal(12, 4)
|
|
currency Currency @default(NGN)
|
|
total_cost Decimal @db.Decimal(14, 4)
|
|
period_start DateTime
|
|
period_end DateTime
|
|
billed Boolean @default(false)
|
|
invoice_id String?
|
|
cpu_hours Decimal? @db.Decimal(10, 4)
|
|
ram_gb_hours Decimal? @db.Decimal(10, 4)
|
|
disk_gb_hours Decimal? @db.Decimal(10, 4)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
vm VirtualMachine @relation(fields: [vm_id], references: [id], onDelete: Cascade)
|
|
tenant Tenant @relation(fields: [tenant_id], references: [id], onDelete: Cascade)
|
|
billing_plan BillingPlan? @relation(fields: [billing_plan_id], references: [id], onDelete: SetNull)
|
|
invoice Invoice? @relation(fields: [invoice_id], references: [id], onDelete: SetNull)
|
|
|
|
@@index([vm_id])
|
|
@@index([tenant_id])
|
|
@@index([period_start])
|
|
@@index([billed])
|
|
@@unique([vm_id, period_start, period_end])
|
|
}
|
|
|
|
model Backup {
|
|
id String @id @default(cuid())
|
|
vm_id String
|
|
vm_name String
|
|
tenant_id String?
|
|
node String?
|
|
status BackupStatus @default(PENDING)
|
|
type BackupType @default(FULL)
|
|
source BackupSource @default(LOCAL)
|
|
size_mb Float?
|
|
storage String?
|
|
backup_path String?
|
|
pbs_snapshot_id String?
|
|
route_key String?
|
|
is_protected Boolean @default(false)
|
|
restore_enabled Boolean @default(true)
|
|
total_files Int?
|
|
schedule BackupSchedule @default(MANUAL)
|
|
retention_days Int @default(7)
|
|
snapshot_job_id String?
|
|
started_at DateTime?
|
|
completed_at DateTime?
|
|
next_run_at DateTime?
|
|
expires_at DateTime?
|
|
notes String?
|
|
proxmox_upid String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
vm VirtualMachine @relation(fields: [vm_id], references: [id], onDelete: Cascade)
|
|
tenant Tenant? @relation(fields: [tenant_id], references: [id], onDelete: SetNull)
|
|
snapshot_job SnapshotJob? @relation(fields: [snapshot_job_id], references: [id], onDelete: SetNull)
|
|
restore_tasks BackupRestoreTask[]
|
|
|
|
@@index([vm_id])
|
|
@@index([tenant_id])
|
|
@@index([status])
|
|
@@index([next_run_at])
|
|
@@index([snapshot_job_id])
|
|
}
|
|
|
|
model BackupPolicy {
|
|
id String @id @default(cuid())
|
|
tenant_id String?
|
|
billing_plan_id String?
|
|
max_files Int @default(10)
|
|
max_total_size_mb Float @default(51200)
|
|
max_protected_files Int @default(3)
|
|
allow_file_restore Boolean @default(true)
|
|
allow_cross_vm_restore Boolean @default(true)
|
|
allow_pbs_restore Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
tenant Tenant? @relation(fields: [tenant_id], references: [id], onDelete: Cascade)
|
|
billing_plan BillingPlan? @relation(fields: [billing_plan_id], references: [id], onDelete: Cascade)
|
|
|
|
@@index([tenant_id])
|
|
@@index([billing_plan_id])
|
|
}
|
|
|
|
model BackupRestoreTask {
|
|
id String @id @default(cuid())
|
|
backup_id String
|
|
source_vm_id String
|
|
target_vm_id String
|
|
mode BackupRestoreMode
|
|
requested_files Json @default("[]")
|
|
pbs_enabled Boolean @default(false)
|
|
status BackupRestoreStatus @default(PENDING)
|
|
result_message String?
|
|
started_at DateTime?
|
|
completed_at DateTime?
|
|
created_by String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
backup Backup @relation(fields: [backup_id], references: [id], onDelete: Cascade)
|
|
source_vm VirtualMachine @relation("BackupRestoreSourceVm", fields: [source_vm_id], references: [id], onDelete: Cascade)
|
|
target_vm VirtualMachine @relation("BackupRestoreTargetVm", fields: [target_vm_id], references: [id], onDelete: Cascade)
|
|
|
|
@@index([backup_id])
|
|
@@index([source_vm_id])
|
|
@@index([target_vm_id])
|
|
@@index([status])
|
|
}
|
|
|
|
model SnapshotJob {
|
|
id String @id @default(cuid())
|
|
vm_id String
|
|
name String
|
|
frequency SnapshotFrequency @default(DAILY)
|
|
interval Int @default(1)
|
|
day_of_week Int?
|
|
hour_utc Int @default(2)
|
|
minute_utc Int @default(0)
|
|
retention Int @default(7)
|
|
enabled Boolean @default(true)
|
|
next_run_at DateTime?
|
|
last_run_at DateTime?
|
|
created_by String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
vm VirtualMachine @relation(fields: [vm_id], references: [id], onDelete: Cascade)
|
|
backups Backup[]
|
|
|
|
@@index([vm_id])
|
|
@@index([enabled, next_run_at])
|
|
}
|
|
|
|
model AuditLog {
|
|
id String @id @default(cuid())
|
|
action String
|
|
resource_type ResourceType
|
|
resource_id String?
|
|
resource_name String?
|
|
actor_email String
|
|
actor_role String?
|
|
severity Severity @default(INFO)
|
|
details Json?
|
|
ip_address String?
|
|
created_at DateTime @default(now())
|
|
|
|
@@index([resource_type])
|
|
@@index([severity])
|
|
@@index([created_at])
|
|
}
|
|
|
|
model SecurityEvent {
|
|
id String @id @default(cuid())
|
|
event_type String
|
|
severity Severity @default(WARNING)
|
|
status SecurityStatus @default(OPEN)
|
|
source_ip String?
|
|
source_country String?
|
|
target_vm_id String?
|
|
node String?
|
|
description String?
|
|
details Json?
|
|
resolved_at DateTime?
|
|
resolved_by String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
@@index([status])
|
|
@@index([severity])
|
|
@@index([created_at])
|
|
}
|
|
|
|
model FirewallRule {
|
|
id String @id @default(cuid())
|
|
name String
|
|
direction Direction @default(INBOUND)
|
|
action FirewallAction @default(DENY)
|
|
protocol Protocol @default(TCP)
|
|
source_ip String?
|
|
destination_ip String?
|
|
port_range String?
|
|
priority Int @default(100)
|
|
enabled Boolean @default(true)
|
|
applies_to AppliesTo @default(ALL_VMS)
|
|
target_id String?
|
|
hit_count Int @default(0)
|
|
description String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
@@index([enabled])
|
|
@@index([priority])
|
|
}
|
|
|
|
model Setting {
|
|
id String @id @default(cuid())
|
|
key String @unique
|
|
type SettingType @default(GENERAL)
|
|
value Json
|
|
is_encrypted Boolean @default(false)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
}
|