87 lines
3.5 KiB
SQL
87 lines
3.5 KiB
SQL
-- Sense owns device desired state and reconciliation progress. It deliberately
|
|||
|
|
-- has no writable Site or quota truth table.
|
||
|
|
|
||
|
|
CREATE SCHEMA IF NOT EXISTS sense AUTHORIZATION sense_app;
|
||
|
|
ALTER SCHEMA sense OWNER TO sense_app;
|
||
|
|
|
||
|
|
CREATE TABLE IF NOT EXISTS sense.schema_migrations (
|
||
|
|
version bigint PRIMARY KEY,
|
||
|
|
applied_at timestamptz NOT NULL DEFAULT clock_timestamp()
|
||
|
|
);
|
||
|
|
ALTER TABLE sense.schema_migrations OWNER TO sense_app;
|
||
|
|
|
||
|
|
CREATE TABLE IF NOT EXISTS sense.devices (
|
||
|
|
id text PRIMARY KEY,
|
||
|
|
tenant_id text NOT NULL,
|
||
|
|
site_id text NOT NULL,
|
||
|
|
serial_number text NOT NULL,
|
||
|
|
name text NOT NULL,
|
||
|
|
modality text NOT NULL,
|
||
|
|
desired_state text NOT NULL,
|
||
|
|
actual_state text NOT NULL,
|
||
|
|
endpoint_ref text NOT NULL DEFAULT '',
|
||
|
|
credential_ref text NOT NULL DEFAULT '',
|
||
|
|
path_name text NOT NULL DEFAULT '',
|
||
|
|
generation bigint NOT NULL DEFAULT 1,
|
||
|
|
quota_source_version bigint,
|
||
|
|
created_at timestamptz NOT NULL,
|
||
|
|
updated_at timestamptz NOT NULL,
|
||
|
|
CONSTRAINT sense_devices_identity_not_blank CHECK (
|
||
|
|
btrim(id) <> '' AND btrim(tenant_id) <> '' AND btrim(site_id) <> ''
|
||
|
|
AND btrim(serial_number) <> '' AND btrim(name) <> ''
|
||
|
|
),
|
||
|
|
CONSTRAINT sense_devices_modality CHECK (
|
||
|
|
modality IN ('video', 'radar', 'contact', 'button', 'wearable', 'other')
|
||
|
|
),
|
||
|
|
CONSTRAINT sense_devices_desired_state CHECK (desired_state IN ('disabled', 'enabled')),
|
||
|
|
CONSTRAINT sense_devices_actual_state CHECK (actual_state IN ('pending', 'online', 'offline', 'failed')),
|
||
|
|
CONSTRAINT sense_devices_generation_positive CHECK (generation >= 1),
|
||
|
|
CONSTRAINT sense_devices_quota_version_positive CHECK (
|
||
|
|
quota_source_version IS NULL OR quota_source_version >= 1
|
||
|
|
),
|
||
|
|
UNIQUE (tenant_id, site_id, serial_number)
|
||
|
|
);
|
||
|
|
ALTER TABLE sense.devices OWNER TO sense_app;
|
||
|
|
|
||
|
|
CREATE TABLE IF NOT EXISTS sense.device_capabilities (
|
||
|
|
device_id text NOT NULL REFERENCES sense.devices(id) ON DELETE CASCADE,
|
||
|
|
capability text NOT NULL,
|
||
|
|
PRIMARY KEY (device_id, capability),
|
||
|
|
CONSTRAINT sense_device_capability_known CHECK (
|
||
|
|
capability IN ('video_capture', 'audio_capture', 'spatial_rule', 'telemetry')
|
||
|
|
)
|
||
|
|
);
|
||
|
|
ALTER TABLE sense.device_capabilities OWNER TO sense_app;
|
||
|
|
|
||
|
|
CREATE TABLE IF NOT EXISTS sense.reconcile_state (
|
||
|
|
device_id text PRIMARY KEY REFERENCES sense.devices(id) ON DELETE CASCADE,
|
||
|
|
failure_count integer NOT NULL DEFAULT 0,
|
||
|
|
next_attempt_at timestamptz,
|
||
|
|
last_error_code text,
|
||
|
|
observed_generation bigint NOT NULL DEFAULT 0,
|
||
|
|
updated_at timestamptz NOT NULL,
|
||
|
|
CONSTRAINT sense_reconcile_failure_nonnegative CHECK (failure_count >= 0),
|
||
|
|
CONSTRAINT sense_reconcile_generation_nonnegative CHECK (observed_generation >= 0)
|
||
|
|
);
|
||
|
|
ALTER TABLE sense.reconcile_state OWNER TO sense_app;
|
||
|
|
|
||
|
|
CREATE TABLE IF NOT EXISTS sense.site_quota_projection_state (
|
||
|
|
tenant_id text NOT NULL,
|
||
|
|
site_id text NOT NULL,
|
||
|
|
source_version bigint NOT NULL,
|
||
|
|
synced_at timestamptz NOT NULL,
|
||
|
|
PRIMARY KEY (tenant_id, site_id),
|
||
|
|
CONSTRAINT sense_quota_projection_version_positive CHECK (source_version >= 1)
|
||
|
|
);
|
||
|
|
ALTER TABLE sense.site_quota_projection_state OWNER TO sense_app;
|
||
|
|
|
||
|
|
CREATE INDEX IF NOT EXISTS sense_devices_site_state_idx
|
||
|
|
ON sense.devices(tenant_id, site_id, desired_state);
|
||
|
|
CREATE UNIQUE INDEX IF NOT EXISTS sense_devices_path_name_idx
|
||
|
|
ON sense.devices(path_name) WHERE path_name <> '';
|
||
|
|
CREATE INDEX IF NOT EXISTS sense_reconcile_due_idx
|
||
|
|
ON sense.reconcile_state(next_attempt_at);
|
||
|
|
|
||
|
|
INSERT INTO sense.schema_migrations(version) VALUES (1)
|
||
|
|
ON CONFLICT (version) DO NOTHING;
|