All Drizzle ORM schema definitions are in apps/api/src/db/schema/.
The central table for managed endpoints:
| Column |
Type |
Description |
id |
UUID |
Primary key |
orgId |
UUID |
FK → organizations |
siteId |
UUID |
FK → sites |
agentId |
varchar(64) |
Unique agent identifier |
agentTokenHash |
varchar(64) |
SHA-256 hash of the main agent bearer token (nullable for pre-migration devices) |
watchdogTokenHash |
varchar(64) |
SHA-256 hash of the companion watchdog token |
helperTokenHash |
varchar(64) |
SHA-256 hash of the user-helper token |
agentTokenSuspendedAt |
timestamp |
Set when the agent token is auto-suspended (e.g. cross-tenant access attempt). Re-enrollment is blocked until cleared. |
agentTokenSuspendedReason |
varchar(255) |
Reason recorded alongside agentTokenSuspendedAt. |
hostname |
varchar(255) |
Device hostname |
displayName |
varchar(255) |
Optional display name (editable inline from the device detail page) |
osType |
enum |
windows, macos, linux |
osVersion |
varchar(100) |
OS version string |
osBuild |
varchar(100) |
OS build identifier (optional) |
architecture |
varchar(20) |
CPU architecture (e.g. amd64, arm64) |
agentVersion |
varchar(20) |
Installed agent version |
status |
enum |
online, offline, maintenance, updating, pending, decommissioned, quarantined |
lastSeenAt |
timestamp |
Last telemetry received |
lastSeenIp |
inet |
Source IP recorded on the most recent heartbeat; changes raise an agent.source.ip.changed audit event. |
mainAgentSilentSince |
timestamp |
Set by the server when the main agent stops heartbeating but the watchdog is still online. Cleared when the agent resumes. |
watchdogStatus |
enum |
connected, failover, offline — last reported watchdog state. |
watchdogLastSeenAt |
timestamp |
Last watchdog check-in. |
watchdogVersion |
varchar(20) |
Installed watchdog binary version. |
enrolledAt |
timestamp |
When the device was enrolled |
enrolledBy |
UUID |
FK → users (who initiated enrollment) |
tags |
text[] |
Array of string tags |
mtlsCertSerialNumber |
varchar(128) |
Cloudflare mTLS cert serial (optional) |
mtlsCertExpiresAt |
timestamp |
mTLS cert expiry (optional) |
mtlsCertIssuedAt |
timestamp |
mTLS cert issue date (optional) |
mtlsCertCfId |
varchar(128) |
Cloudflare cert ID (optional) |
quarantinedAt |
timestamp |
When device was quarantined (optional) |
quarantinedReason |
varchar(255) |
Reason for quarantine (optional) |
createdAt |
timestamp |
Row creation time |
updatedAt |
timestamp |
Last update time |
| Table |
Description |
deviceHardware |
CPU model, cores, RAM, disk, GPU, serial number, manufacturer |
deviceNetworkInterfaces |
Network interfaces with MAC, IP, type, primary flag, public IP |
deviceDisks |
Mount points, filesystem type, capacity, health |
deviceTelemetry |
Time-series CPU, RAM, disk, network, process count |
deviceSoftware |
Installed applications with version, publisher, install location |
deviceRegistryEntries |
Windows registry snapshots |
deviceConfigEntries |
Configuration file key-value pairs |
deviceNetworkConnections |
Active TCP/UDP connections with process info |
deviceGroups |
Static and dynamic device groups with filter rules |
deviceGroupMemberships |
Many-to-many device ↔ group mapping |
deviceCommands |
Command queue (pending, completed, failed) |
elevationRequests |
Privileged-action mode (PAM) elevation requests awaiting approval |
elevationAudit |
Immutable audit trail of elevation approve/deny/expire decisions |
refreshTokenFamilies |
Refresh-token lineage for reuse-detection (RFC 9700 §4.13.2) |
└── organizations (customer)
| Table |
Purpose |
users |
User accounts with email, password hash, MFA status |
roles |
Role definitions (Partner Admin, Technician, Viewer, etc.) |
permissions |
Resource + action pairs (e.g., devices:read) |
rolePermissions |
Maps roles to permissions |
partnerUsers |
Maps users to partners with roles |
Seeded by pnpm db:seed:
| Role |
Scope |
Permissions |
| Partner Admin |
partner |
*:* (full access) |
| Partner Technician |
partner |
Read + execute on devices, scripts, alerts |
| Partner Viewer |
partner |
Read-only |
| Org Admin |
organization |
Full access within org |
| Org User |
organization |
Read + limited write |
# Push schema changes (development)
# Run migrations (production)
# Seed default roles, permissions, templates
# Open Drizzle Studio (visual schema browser)
# Connect to the database
docker compose -f docker/docker-compose.prod.yml exec postgres \
SELECT count(*) FROM devices;