WAVE Synapse uses role-based access control (RBAC) to govern who can view, configure, and control devices. Roles can be assigned at the organization level (affecting all devices) or at the individual device level (scoping permissions to specific equipment).
Synapse defines 5 roles, ordered from least to most privileged:
| Role | Level | Description |
|---|---|---|
viewer | Read-only | View device status, health scores, and routing matrix. Cannot modify anything. |
technician | Operate | Everything a viewer can do, plus: approve discovered devices, create and modify routes, send device commands, manage show profiles. |
producer | Production | Everything a technician can do, plus: lock devices to productions, manage tally states, activate show profiles during live events. |
device_admin | Device management | Everything a producer can do, plus: register and decommission devices, configure failover, manage network segments, modify discovery permissions. |
org_admin | Full control | Everything a device_admin can do, plus: manage role assignments, delete sites and segments, access audit logs, modify organization-level settings. |
| Action | viewer | technician | producer | device_admin | org_admin |
|---|---|---|---|---|---|
| View devices | Yes | Yes | Yes | Yes | Yes |
| View routing matrix | Yes | Yes | Yes | Yes | Yes |
| View health summary | Yes | Yes | Yes | Yes | Yes |
| View topology | Yes | Yes | Yes | Yes | Yes |
| View show profiles | Yes | Yes | Yes | Yes | Yes |
| Approve discovered devices | - | Yes | Yes | Yes | Yes |
| Create/modify routes | - | Yes | Yes | Yes | Yes |
| Send device commands | - | Yes | Yes | Yes | Yes |
| Create/edit show profiles | - | Yes | Yes | Yes | Yes |
| Lock devices to production | - | - | Yes | Yes | Yes |
| Manage tally state | - | - | Yes | Yes | Yes |
| Activate show profiles (live) | - | - | Yes | Yes | Yes |
| Register devices | - | - | - | Yes | Yes |
| Decommission devices | - | - | - | Yes | Yes |
| Configure failover | - | - | - | Yes | Yes |
| Manage network segments | - | - | - | Yes | Yes |
| Modify discovery permissions | - | - | - | Yes | Yes |
| Assign/revoke roles | - | - | - | - | Yes |
| Delete sites/segments | - | - | - | - | Yes |
| View audit logs | - | - | - | - | Yes |
When a role is assigned with device_id: null, it applies to all devices in the organization:
-- User has technician access to ALL devices in the org
INSERT INTO ncp_device_roles (organization_id, user_id, device_id, role, granted_by)
VALUES ('org-uuid', 'user-uuid', NULL, 'technician', 'admin-uuid');
When a role is assigned with a specific device_id, it applies only to that device:
-- User has producer access to ONLY this specific camera
INSERT INTO ncp_device_roles (organization_id, user_id, device_id, role, granted_by)
VALUES ('org-uuid', 'user-uuid', 'camera-uuid', 'producer', 'admin-uuid');
Device-level roles override organization-level roles for the specific device. If a user has viewer at the org level but producer for a specific camera, they can control that camera but only view all other devices.
When checking permissions, Synapse resolves the effective role for a user-device pair:
// Pseudo-code for role resolution
function getEffectiveRole(userId: string, deviceId: string, orgId: string): DeviceRole | null {
// 1. Check device-specific role
const deviceRole = await getDeviceRole(orgId, userId, deviceId);
if (deviceRole) return deviceRole;
// 2. Check org-level role (device_id = null)
const orgRole = await getOrgRole(orgId, userId);
if (orgRole) return orgRole;
// 3. No role assigned
return null;
}
Devices that communicate directly with Synapse APIs (rather than through a user session) authenticate using HMAC-signed API keys. This is separate from user authentication and is used for:
org_admin generates an API key for a deviceAuthorization header| Field | Description |
|---|---|
key_prefix | First 8 characters of the key, stored in plaintext for lookup |
key_hash | SHA-256 hash of the full key |
expires_at | Expiration timestamp; expired keys are rejected |
revoked_at | If set, the key has been manually revoked |
failed_attempts | Count of failed authentication attempts |
last_used_at | Timestamp of last successful use |
org_adminCREATE TABLE ncp_device_roles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES organizations(id),
user_id UUID NOT NULL REFERENCES auth.users(id),
device_id UUID REFERENCES ncp_devices(id), -- NULL = org-level
role TEXT NOT NULL CHECK (role IN (
'viewer', 'technician', 'producer', 'device_admin', 'org_admin'
)),
granted_by UUID REFERENCES auth.users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(organization_id, user_id, device_id)
);
CREATE TABLE ncp_device_api_keys (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
device_id UUID NOT NULL REFERENCES ncp_devices(id),
key_hash TEXT NOT NULL,
key_prefix TEXT NOT NULL,
expires_at TIMESTAMPTZ NOT NULL,
revoked_at TIMESTAMPTZ,
failed_attempts INT DEFAULT 0,
last_used_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Row Level Security policies enforce access control at the database level:
org_admin (mapped to organization owner/admin roles) can insert, update, or delete role assignmentsorg_admin can create, update, or delete device API keysDiscovery permissions restrict which subnets can be scanned:
CREATE TABLE ncp_discovery_permissions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES organizations(id),
allowed_subnet CIDR NOT NULL,
allowed_methods TEXT[] DEFAULT '{}',
rate_limit_per_hour INT DEFAULT 10,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Only org_admin can create or modify discovery permissions, ensuring that network scanning is controlled.