392 lines
14 KiB
Plaintext
392 lines
14 KiB
Plaintext
// SysDeck Web Edition v0.2.0 — state schema
|
|
// Mirrors the cockpit edition's /var/lib/sysdeck state dirs + /etc/sysdeck config.
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "sqlite"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// ── Global audit log (mirrors /etc/cockpit/MODULE_LICENSES.log pattern) ──
|
|
model AuditLog {
|
|
id String @id @default(cuid())
|
|
ts DateTime @default(now())
|
|
module String
|
|
action String
|
|
detail String?
|
|
actor String @default("operator")
|
|
}
|
|
|
|
// ── Image Builder ──────────────────────────────────────────────────
|
|
model SdProfile {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
backend String // mkosi | vmdb2 | archiso | live-build
|
|
base String? // shipped profile it was copied from
|
|
packages String @default("") // newline-separated package list
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model SdBuild {
|
|
id String @id @default(cuid())
|
|
buildId String @unique // <profile>-<timestamp>
|
|
profile String
|
|
backend String
|
|
state String @default("queued") // queued | running | succeeded | failed
|
|
rc Int?
|
|
durationMs Int?
|
|
log String @default("")
|
|
artifacts SdArtifact[]
|
|
startedAt DateTime @default(now())
|
|
finishedAt DateTime?
|
|
}
|
|
|
|
model SdArtifact {
|
|
id String @id @default(cuid())
|
|
buildId String
|
|
path String
|
|
sizeBytes Int
|
|
createdAt DateTime @default(now())
|
|
build SdBuild @relation(fields: [buildId], references: [buildId])
|
|
}
|
|
|
|
// ── Firewall ───────────────────────────────────────────────────────
|
|
model FwRuleset {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
backend String // nftables | iptables | firewalld | sysdeck-fw | cilium
|
|
template String? // public-webserver | vps-webserver | ai-llm | remote-admin | no-services | cilium
|
|
active Boolean @default(false)
|
|
appliedAt DateTime?
|
|
}
|
|
|
|
model FwRule {
|
|
id String @id @default(cuid())
|
|
ruleset String
|
|
chain String @default("INPUT")
|
|
action String // accept | drop | reject | log
|
|
proto String @default("tcp")
|
|
port String?
|
|
source String?
|
|
comment String?
|
|
position Int @default(0)
|
|
}
|
|
|
|
// ── Service / Ports editor (SERVICES_REGISTRY from firewall.py) ────
|
|
model ServicePort {
|
|
id String @id @default(cuid())
|
|
service String @unique // ssh | cockpit | caddy | varnish | mariadb | ollama | openwebui | hermes | odysseus
|
|
label String
|
|
port Int
|
|
configPath String
|
|
configKey String
|
|
running Boolean @default(false)
|
|
updatedPort Int?
|
|
}
|
|
|
|
// ── Policy & permissions ───────────────────────────────────────────
|
|
model PolicyRule {
|
|
id String @id @default(cuid())
|
|
scope String // e.g. "org.sysdeck.builder.modify"
|
|
subject String
|
|
effect String @default("allow") // allow | deny
|
|
priority Int @default(50)
|
|
enabled Boolean @default(true)
|
|
note String?
|
|
}
|
|
|
|
// ── Encryption Vault ───────────────────────────────────────────────
|
|
model VaultEntry {
|
|
id String @id @default(cuid())
|
|
label String
|
|
kind String // luks-volume | keyfile | tpm-sealed | secret
|
|
device String?
|
|
cipher String?
|
|
sizeBytes Int?
|
|
status String @default("locked") // locked | unlocked | sealed
|
|
note String?
|
|
createdAt DateTime @default(now())
|
|
}
|
|
|
|
// ── Hardware alerts (orphaned bridge finally gets its panel) ────────
|
|
model HwDevice {
|
|
id String @id @default(cuid())
|
|
deviceId String @unique
|
|
kind String // usb-storage | thunderbolt | bluetooth | pci | rfid | firewire
|
|
name String
|
|
vendor String?
|
|
authorized Boolean @default(true)
|
|
whitelisted Boolean @default(false)
|
|
firstSeen DateTime @default(now())
|
|
lastSeen DateTime @default(now())
|
|
}
|
|
|
|
model HwAlert {
|
|
id String @id @default(cuid())
|
|
deviceId String
|
|
kind String // unauthorized-usb | dma-thunderbolt | rogue-bluetooth | firmware-tamper | new-pci
|
|
severity String @default("warn") // info | warn | danger
|
|
message String
|
|
state String @default("active") // active | acknowledged | dismissed
|
|
ts DateTime @default(now())
|
|
}
|
|
|
|
// ── Mining ──────────────────────────────────────────────────────────
|
|
model MiningRig {
|
|
id String @id @default(cuid())
|
|
name String
|
|
host String
|
|
coins String @default("BTC")
|
|
status String @default("online") // online | offline | idle | error
|
|
hashrate Float @default(0) // TH/s
|
|
powerW Int @default(0)
|
|
tempC Float @default(0)
|
|
pool String?
|
|
gpus MiningGpu[]
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model MiningGpu {
|
|
id String @id @default(cuid())
|
|
rigId String
|
|
model String
|
|
hashrate Float @default(0)
|
|
tempC Float @default(0)
|
|
fanPct Int @default(0)
|
|
rig MiningRig @relation(fields: [rigId], references: [id])
|
|
}
|
|
|
|
// ── Databases ──────────────────────────────────────────────────────
|
|
model DbInstance {
|
|
id String @id @default(cuid())
|
|
name String
|
|
engine String // mariadb | postgres | sqlite | redis
|
|
host String @default("127.0.0.1")
|
|
port Int
|
|
status String @default("running")
|
|
sizeMb Float @default(0)
|
|
conns Int @default(0)
|
|
version String?
|
|
note String?
|
|
}
|
|
|
|
// ── Containers & VMs / Kata / Remote FS ────────────────────────────
|
|
model Container {
|
|
id String @id @default(cuid())
|
|
name String
|
|
driver String // incus | lxc | podman | libvirt | firecracker
|
|
kind String @default("container") // container | vm
|
|
image String?
|
|
state String @default("stopped") // running | stopped | frozen | error
|
|
cpuPct Float @default(0)
|
|
memMb Float @default(0)
|
|
uptimeS Int @default(0)
|
|
ports String?
|
|
createdAt DateTime @default(now())
|
|
}
|
|
|
|
model KataPod {
|
|
id String @id @default(cuid())
|
|
name String
|
|
runtime String @default("kata-qemu")
|
|
sandbox String
|
|
state String @default("running")
|
|
vmm String?
|
|
memMb Float @default(0)
|
|
cpuPct Float @default(0)
|
|
pods Int @default(1)
|
|
}
|
|
|
|
model RemoteFs {
|
|
id String @id @default(cuid())
|
|
name String
|
|
backend String // ceph | glusterfs | moosefs | beegfs | orangefs
|
|
state String @default("healthy") // healthy | degraded | offline
|
|
sizeGb Float @default(0)
|
|
usedGb Float @default(0)
|
|
mounts Int @default(1)
|
|
bricks Int @default(0)
|
|
note String?
|
|
}
|
|
|
|
// ── Media: Jellyfin + Photos ───────────────────────────────────────
|
|
model MediaItem {
|
|
id String @id @default(cuid())
|
|
kind String // movie | series | episode | photo
|
|
title String
|
|
library String
|
|
sizeMb Float @default(0)
|
|
year Int?
|
|
addedAt DateTime @default(now())
|
|
playCount Int @default(0)
|
|
}
|
|
|
|
model MediaSession {
|
|
id String @id @default(cuid())
|
|
user String
|
|
device String
|
|
item String
|
|
state String @default("playing") // playing | paused | idle
|
|
startedAt DateTime @default(now())
|
|
}
|
|
|
|
model PhotoLibrary {
|
|
id String @id @default(cuid())
|
|
backend String // photoprism | piwigo | lychee | nextcloud-memories | librephotos
|
|
name String
|
|
photos Int @default(0)
|
|
videos Int @default(0)
|
|
sizeGb Float @default(0)
|
|
state String @default("idle") // indexing | idle | scanning | error
|
|
}
|
|
|
|
// ── Benchmark history ──────────────────────────────────────────────
|
|
model BenchmarkResult {
|
|
id String @id @default(cuid())
|
|
suite String // cpu | memory | disk | network
|
|
score Float
|
|
metric String
|
|
detail String?
|
|
ts DateTime @default(now())
|
|
}
|
|
|
|
// ── Integrity (tripwire-style) ─────────────────────────────────────
|
|
model IntegrityBaseline {
|
|
id String @id @default(cuid())
|
|
path String @unique
|
|
hash String
|
|
kind String @default("file")
|
|
ts DateTime @default(now())
|
|
}
|
|
|
|
model IntegrityDrift {
|
|
id String @id @default(cuid())
|
|
path String
|
|
oldHash String?
|
|
newHash String?
|
|
change String // modified | added | removed
|
|
detected DateTime @default(now())
|
|
resolved Boolean @default(false)
|
|
}
|
|
|
|
// ── Netsec ─────────────────────────────────────────────────────────
|
|
model NetsecBan {
|
|
id String @id @default(cuid())
|
|
ip String
|
|
service String @default("sshd")
|
|
jail String @default("sysdeck")
|
|
reason String?
|
|
strikes Int @default(1)
|
|
bannedAt DateTime @default(now())
|
|
expiresAt DateTime?
|
|
}
|
|
|
|
model NetsecScan {
|
|
id String @id @default(cuid())
|
|
target String
|
|
kind String @default("port-sweep")
|
|
ports String
|
|
result String @default("done")
|
|
ts DateTime @default(now())
|
|
}
|
|
|
|
// ── 3rd-party module installer (catalog from modules3p.py) ─────────
|
|
model Module3pInstall {
|
|
id String @id @default(cuid())
|
|
moduleId String @unique
|
|
action String @default("install") // install | uninstall
|
|
license String
|
|
ts DateTime @default(now())
|
|
}
|
|
|
|
// ── Fleet nodes ────────────────────────────────────────────────────
|
|
model FleetNode {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
host String
|
|
role String @default("compute") // compute | storage | edge | control
|
|
arch String @default("x86_64")
|
|
state String @default("online") // online | offline | degraded
|
|
cpuModel String?
|
|
cores Int @default(4)
|
|
memGb Int @default(8)
|
|
local Boolean @default(false)
|
|
}
|
|
|
|
// ── Themes ─────────────────────────────────────────────────────────
|
|
model ThemeSetting {
|
|
id String @id @default(cuid())
|
|
key String @unique
|
|
value String
|
|
}
|
|
|
|
// ── Klanker / Frosty Deno LLM gateway (klanker-gate) ───────────────
|
|
model KlankerProvider {
|
|
id String @id @default(cuid())
|
|
name String @unique // openai | anthropic | gemini | openrouter | groq | ollama-local
|
|
kind String // openai | anthropic | gemini | openrouter | groq | ollama
|
|
models Int @default(0) // enabled model count on the account
|
|
status String @default("ok") // ok | error | unknown | disabled
|
|
latencyMs Int? // last list-models probe latency
|
|
note String?
|
|
createdAt DateTime @default(now())
|
|
}
|
|
|
|
model KlankerVKey {
|
|
id String @id @default(cuid())
|
|
label String @unique
|
|
team String? // governance hierarchy: key -> team -> customer
|
|
scope String @default("unrestricted") // unrestricted | scoped providers/models
|
|
requests24h Int @default(0)
|
|
tokens24h Int @default(0)
|
|
costMicroUsd Int @default(0) // repo-wide cost unit: integer micro-USD
|
|
rateLimitPerMin Int? // maxRequests of the 60s window, when set
|
|
budgetUsd Float? // budget.maxCostUsd, when set
|
|
state String @default("active") // active | disabled
|
|
createdAt DateTime @default(now())
|
|
}
|
|
|
|
model KlankerLogEntry {
|
|
id String @id @default(cuid())
|
|
ts DateTime @default(now())
|
|
model String
|
|
provider String
|
|
vkey String? // virtual key label, when the request was keyed
|
|
tokensIn Int @default(0)
|
|
tokensOut Int @default(0)
|
|
costMicroUsd Int @default(0)
|
|
latencyMs Int @default(0)
|
|
status Int @default(200)
|
|
cacheHit Boolean @default(false)
|
|
surface String @default("openai") // ingress dialect: openai | anthropic | gemini | openrouter
|
|
}
|
|
|
|
// ── KV store for misc module state ─────────────────────────────────
|
|
model SdKv {
|
|
key String @id
|
|
value String
|
|
ts DateTime @default(now())
|
|
}
|
|
|
|
// ── Local console accounts (v0.4.0 unix-login fallback) ────────────
|
|
// When the host PAM path is unavailable (non-root service on a box
|
|
// where unix_chkpwd only serves the invoking uid, or a python3-less
|
|
// install), SYSDECK_AUTH_MODE=local/pam+local authenticates against
|
|
// these instead: scrypt-hashed passwords, per-account lockout flag.
|
|
// This is the escape hatch, NOT the primary path — PAM (the host's
|
|
// own account system) is, exactly like Cockpit.
|
|
model SdUser {
|
|
username String @unique
|
|
realname String?
|
|
hash String // scrypt: salt$N$r$p$hex — never the password
|
|
disabled Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
lastLoginAt DateTime?
|
|
lastLoginIp String?
|
|
}
|