Database Schema¶
The cluster management system uses Sequelize ORM with PostgreSQL. While Sequelize supports other databases, only PostgreSQL is officially supported.
Entity Relationship Diagram¶
erDiagram
Sites ||--o{ Nodes : contains
Sites ||--o{ ExternalDomains : "default site"
Nodes ||--o{ Containers : hosts
Containers ||--o{ Services : exposes
Containers }o--o| Jobs : "created by"
Services ||--|| HTTPServices : "type: http"
Services ||--|| TransportServices : "type: transport"
Services ||--|| DnsServices : "type: dns"
ExternalDomains ||--o{ HTTPServices : "used by"
Jobs ||--o{ JobStatuses : tracks
Users }o--o{ Groups : "member of"
UserGroups }|--|| Users : joins
UserGroups }|--|| Groups : joins
PasswordResetTokens }o--|| Users : "for"
InviteTokens ||--o| Users : "creates"
Sites {
int id PK
string name
string internalDomain
string dhcpRange
string subnetMask
string gateway
string dnsForwarders
string externalIp "Public IP for DNS A records"
}
Nodes {
int id PK
string name UK
string ipv4Address
string apiUrl
string apiTokenIdOrUsername
string apiTokenSecretOrPassword
boolean disableTlsVerification
string imageStorage "default: local"
string volumeStorage "default: local-lvm"
string networkBridge "default: vmbr0"
boolean nvidiaAvailable "default: false"
int siteId FK
}
Containers {
int id PK
string hostname UK
string username
string status "pending,creating,running,failed"
string template
int creationJobId FK
int nodeId FK
int containerId
string macAddress UK
string ipv4Address UK
string aiContainer
boolean nvidiaRequested "default: false"
}
Services {
int id PK
int containerId FK
enum type "http,transport,dns"
int containerPort
}
HTTPServices {
int id PK
int serviceId FK,UK
string externalHostname
int externalDomainId FK
enum backendProtocol "http | https (default: http)"
boolean authRequired "default: false"
}
TransportServices {
int id PK
int serviceId FK,UK
enum protocol "tcp,udp"
int externalPort UK
boolean useTls
}
DnsServices {
int id PK
int serviceId FK,UK
enum recordType "SRV"
string serviceName
}
ExternalDomains {
int id PK
string domain
string acmeEmail
string acmeDirectory
string cloudflareApiEmail
string cloudflareApiKey
int siteId FK "nullable, default site"
string authServer "nullable, auth server URL"
}
Jobs {
int id PK
string name
string associatedResource
enum status "pending,running,success,failure,cancelled"
}
JobStatuses {
int id PK
int jobId FK
text message
}
Users {
int uidNumber PK
string username UK
string cn "Common Name"
string sn "Surname"
string givenName
string mail UK
text sshPublicKey
string userPassword
string status "pending,active,suspended"
}
Groups {
int gidNumber PK
string cn UK "Group Name"
boolean isAdministrator
}
UserGroups {
int uidNumber PK,FK
int gidNumber PK,FK
}
SessionSecrets {
int id PK
string secret UK
}
Settings {
string key PK,UK
string value
}
PasswordResetTokens {
uuid id PK
int uidNumber FK
string token UK
datetime expiresAt
boolean used
}
InviteTokens {
uuid id PK
string email
string token UK
datetime expiresAt
boolean used
}
Core Models¶
Site¶
Top-level organizational unit. Has many Nodes. Has many ExternalDomains (as default site). externalIp is the public IP used as the target for Cloudflare DNS A records when cross-site HTTP services are created.
Node¶
Proxmox VE server within a site. name must match Proxmox hostname (unique). imageStorage defaults to 'local' (CT templates). volumeStorage defaults to 'local-lvm' (container rootfs). networkBridge defaults to 'vmbr0' (Proxmox bridge used in container net0 config). nvidiaAvailable indicates the node has NVIDIA drivers and nvidia-container-toolkit configured for GPU passthrough. Belongs to Site, has many Containers.
Container¶
LXC container on a Proxmox node. Unique composite index on (nodeId, containerId). hostname, macAddress, ipv4Address globally unique. nvidiaRequested indicates GPU passthrough was requested — the container is assigned to an NVIDIA-capable node and the nvidia hookscript is attached. Belongs to Node and optionally to a Job.
Service (STI)¶
Base model with type discriminator (http, transport, dns). Belongs to Container.
- HTTPService:
(externalHostname, externalDomainId)unique. Belongs to ExternalDomain.backendProtocolcontrolsproxy_passscheme (httporhttps).authRequiredenables NGINXauth_request— requires the domain'sauthServerto be configured. - TransportService:
(protocol, externalPort)unique.findNextAvailablePort()static method. - DnsService: SRV records with
serviceName.
ExternalDomain¶
Manages public domains for HTTP service exposure. siteId is nullable — when set, indicates the "default site" whose DNS is assumed pre-configured (e.g., wildcard A record). Global resource available to all sites. Has many HTTPServices. Cloudflare credentials used for both ACME DNS-01 challenges and cross-site A record management. authServer is an optional URL pointing to an authentication server that implements the NGINX auth_request protocol (see External Domains).
User Management Models¶
User¶
LDAP-compatible user accounts. Passwords hashed with argon2. UIDs start at 2000 (getNextUid()). Only active users can authenticate. First registered user auto-added to sysadmins.
Group¶
LDAP-compatible groups. Default groups: ldapusers (gid: 2000), sysadmins (gid: 2001).
UserGroup¶
Join table. Composite primary key on (uidNumber, gidNumber).
PasswordResetToken¶
UUID-based tokens with 1-hour default expiry. Methods: generateToken(), validateToken(), cleanup().
InviteToken¶
UUID-based invite tokens with 24-hour default expiry. Email tied to token and locked during registration. Methods: generateToken(), validateToken(), cleanup().
Job Management¶
Job¶
Tracks async operations (container creation, etc.). Statuses: pending, running, success, failure, cancelled.
JobStatus¶
Progress messages for a Job.
System¶
- SessionSecret: Stores express-session secrets
- Setting: Key-value pairs for system config. Methods:
get(),set(),getMultiple()
Database Abstraction¶
Implemented with Sequelize ORM backed by PostgreSQL. Includes migrations, field validation, hooks (password hashing, UID assignment), and declarative associations.
Key Design Patterns¶
- Service STI: Base
Servicestable withtypediscriminator; child tables (HTTPServices,TransportServices,DnsServices) extend via one-to-one relationships - LDAP compatibility: User/Group models use LDAP naming (
uidNumber,gidNumber,cn,sn,givenName) - Hierarchy: Site → Nodes → Containers → Services (mirrors physical topology)