Skip to main content

Overview

The devices schema manages device enrollment, trust scoring, Tailscale/NetBird integration, and device lifecycle events.

Tables

devices

Core device records with enrollment and trust information.
Schema
CREATE TABLE public.devices (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
  organization_id UUID REFERENCES public.organizations(id) ON DELETE CASCADE,
  name TEXT NOT NULL,
  device_type TEXT NOT NULL DEFAULT 'laptop',
  os TEXT,
  fingerprint TEXT UNIQUE,
  enrollment_token TEXT UNIQUE,
  enrolled_at TIMESTAMP WITH TIME ZONE,
  last_seen TIMESTAMP WITH TIME ZONE DEFAULT now(),
  location TEXT,
  status TEXT NOT NULL DEFAULT 'pending',
  trust_level TEXT NOT NULL DEFAULT 'low',
  tailscale_auth_key TEXT,
  tailscale_hostname TEXT,
  tailscale_device_id TEXT,
  tailscale_ip TEXT,
  enrollment_expires_at TIMESTAMP WITH TIME ZONE,
  metadata JSONB DEFAULT '{}'::jsonb,
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()
);

Columns

id
UUID
Device unique identifier (auto-generated)
user_id
UUID
required
Owner user ID from auth.users
organization_id
UUID
Organization this device belongs to
name
TEXT
required
Device name (e.g., “John’s MacBook Pro”)
device_type
TEXT
default:"laptop"
Device type: laptop, desktop, mobile, tablet, windows, macos
os
TEXT
Operating system (e.g., “macOS 14.0”, “Windows 11”)
fingerprint
TEXT
Unique device fingerprint for silent enrollment (unique)
enrollment_token
TEXT
Enrollment token for device registration (unique, expires)
enrolled_at
TIMESTAMPTZ
Timestamp when device completed enrollment
last_seen
TIMESTAMPTZ
Last activity timestamp
location
TEXT
Device location (optional)
status
TEXT
default:"pending"
Device status: pending, active, inactive, revoked
trust_level
TEXT
default:"low"
Trust level: low, medium, high
tailscale_auth_key
TEXT
Tailscale auth key for enrollment (cleared after use)
tailscale_hostname
TEXT
Hostname in Tailscale network
tailscale_device_id
TEXT
Tailscale device ID
tailscale_ip
TEXT
Tailscale IP address (100.x.x.x)
enrollment_expires_at
TIMESTAMPTZ
When enrollment token expires (24 hours from creation)
metadata
JSONB
Additional device metadata and configuration
created_at
TIMESTAMPTZ
Device record creation timestamp

Indexes

Indexes
CREATE INDEX idx_devices_enrollment_token 
  ON public.devices(enrollment_token) 
  WHERE enrollment_token IS NOT NULL;

CREATE INDEX idx_devices_tailscale_device_id 
  ON public.devices(tailscale_device_id) 
  WHERE tailscale_device_id IS NOT NULL;

Device Statuses

StatusDescription
pendingDevice created but not enrolled
activeDevice enrolled and active
inactiveDevice not seen recently
revokedDevice access revoked

Trust Levels

LevelDescriptionRequirements
lowBasic trustToken-based enrollment only
mediumModerate trustFingerprint verified
highHigh trustTailscale/NetBird connected

Metadata Fields

Example Metadata
{
  "created_by": "user-uuid",
  "tailscale_tags": ["tag:prod", "tag:user"],
  "tailscale_group": "engineering",
  "tailscale_online": true,
  "tailscale_last_seen": "2024-01-15T10:30:00Z",
  "token_validated_at": "2024-01-15T09:00:00Z",
  "netbird_peer_id": "peer-123",
  "device_model": "MacBook Pro 16-inch",
  "serial_number": "C02XY123456"
}

device_events

Audit trail of device lifecycle events.
Schema
CREATE TABLE public.device_events (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  device_id UUID REFERENCES public.devices(id) ON DELETE CASCADE NOT NULL,
  event_type TEXT NOT NULL,
  details JSONB DEFAULT '{}'::jsonb,
  ip_address TEXT,
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()
);

Columns

id
UUID
Event unique identifier
device_id
UUID
required
Device this event relates to
event_type
TEXT
required
Event type identifier
details
JSONB
Event-specific details as JSON
ip_address
TEXT
IP address where event originated
created_at
TIMESTAMPTZ
Event timestamp

Event Types

Event TypeDescription
pending_device_createdAdmin created pending device
enrollment_initiatedUser started enrollment process
token_validatedEnrollment token validated
enrolledDevice successfully enrolled
tailscale_auth_key_generatedTailscale key generated
tailscale_connectedDevice connected to Tailscale
tailscale_enrollment_completeTailscale enrollment finished
device_revokedDevice access revoked
device_reactivatedDevice reactivated
trust_level_changedTrust level updated

Example Event Details

Enrollment Event
{
  "method": "qr_code",
  "device_type": "laptop",
  "os": "macOS 14.0"
}
Tailscale Event
{
  "tailscale_device_id": "device-123",
  "hostname": "johns-macbook",
  "ip": "100.64.0.1",
  "tags": ["tag:prod"],
  "group": "engineering"
}

organization_tailscale_config

Tailscale configuration per organization.
Schema
CREATE TABLE public.organization_tailscale_config (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  organization_id UUID NOT NULL REFERENCES public.organizations(id) ON DELETE CASCADE,
  tailscale_auth_key TEXT NOT NULL,
  tags TEXT[] DEFAULT ARRAY['tag:prod'],
  description TEXT,
  is_active BOOLEAN DEFAULT true,
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  expires_at TIMESTAMP WITH TIME ZONE,
  created_by UUID REFERENCES auth.users(id),
  UNIQUE(organization_id, tailscale_auth_key)
);

Columns

id
UUID
Configuration ID
organization_id
UUID
required
Organization this config belongs to
tailscale_auth_key
TEXT
required
Tailscale authentication key
tags
TEXT[]
Default Tailscale ACL tags to apply
description
TEXT
Configuration description
is_active
BOOLEAN
default:"true"
Whether this config is active
created_at
TIMESTAMPTZ
Creation timestamp
expires_at
TIMESTAMPTZ
Key expiration timestamp
created_by
UUID
Admin user who created this config

Example Queries

Create Pending Device

Create Device
INSERT INTO devices (
  user_id,
  organization_id,
  name,
  device_type,
  os,
  enrollment_token,
  enrollment_expires_at,
  status,
  trust_level
) VALUES (
  'user-uuid',
  'org-uuid',
  'MacBook Pro',
  'laptop',
  'macOS 14.0',
  gen_random_uuid()::text,
  now() + interval '24 hours',
  'pending',
  'low'
)
RETURNING id, enrollment_token;

Get User Devices

List User Devices
SELECT 
  id,
  name,
  device_type,
  os,
  status,
  trust_level,
  tailscale_ip,
  last_seen,
  enrolled_at
FROM devices
WHERE user_id = 'user-uuid'
ORDER BY last_seen DESC;

Update Device Status

Activate Device
UPDATE devices
SET 
  status = 'active',
  enrolled_at = now(),
  trust_level = 'high',
  enrollment_token = NULL,
  tailscale_auth_key = NULL
WHERE id = 'device-uuid'
RETURNING *;

Get Device Events

Device Audit Trail
SELECT 
  event_type,
  details,
  ip_address,
  created_at
FROM device_events
WHERE device_id = 'device-uuid'
ORDER BY created_at DESC;

Find Tailscale Device

Find by Tailscale ID
SELECT 
  d.*,
  p.full_name,
  o.name as organization_name
FROM devices d
JOIN profiles p ON p.id = d.user_id
JOIN organizations o ON o.id = d.organization_id
WHERE d.tailscale_device_id = 'ts-device-id';

Row Level Security

devices

RLS Policies
-- Users can view their own devices
CREATE POLICY "Users can view their own devices"
ON public.devices FOR SELECT
USING (user_id = auth.uid());

-- Users can insert their own devices
CREATE POLICY "Users can insert their own devices"
ON public.devices FOR INSERT
WITH CHECK (user_id = auth.uid());

-- Users can update their own devices
CREATE POLICY "Users can update their own devices"
ON public.devices FOR UPDATE
USING (user_id = auth.uid());

-- Users can delete their own devices
CREATE POLICY "Users can delete their own devices"
ON public.devices FOR DELETE
USING (user_id = auth.uid());

-- Admins can view all devices in their org
CREATE POLICY "Admins can view devices in their org"
ON public.devices FOR SELECT
USING (
  organization_id IN (
    SELECT organization_id FROM profiles
    WHERE id = auth.uid() AND role IN ('org_admin', 'global_admin')
  )
);

device_events

RLS Policies
-- Users can view events for their devices
CREATE POLICY "Users can view their device events"
ON public.device_events FOR SELECT
USING (
  device_id IN (
    SELECT id FROM devices WHERE user_id = auth.uid()
  )
);

-- System can insert device events
CREATE POLICY "System can insert device events"
ON public.device_events FOR INSERT
WITH CHECK (true);

organization_tailscale_config

RLS Policies
-- Admins can manage Tailscale config
CREATE POLICY "Admins can manage tailscale config"
ON public.organization_tailscale_config FOR ALL
USING (
  organization_id = get_user_org_id(auth.uid()) 
  AND get_user_role(auth.uid()) IN ('org_admin', 'global_admin')
);
  • /functions/v1/device-enrollment - Device enrollment operations
  • /functions/v1/tailscale-api - Tailscale integration
  • /functions/v1/netbird-proxy - NetBird integration
  • profiles - Device owners
  • organizations - Device organization membership
  • audit_logs - Additional audit trail

Build docs developers (and LLMs) love