-- Local durable audit facts. Transport, signatures, acknowledgements and -- retention belong to a later Bell relay contract. CREATE TABLE IF NOT EXISTS sense.device_operation_outbox ( event_id text PRIMARY KEY, event_type text NOT NULL, tenant_id text NOT NULL, site_id text NOT NULL, device_id text NOT NULL, actor_type text NOT NULL, actor_id text NOT NULL, reason text, trace_id text, aggregate_generation bigint NOT NULL, quota_source_version bigint, area_policy_source_version bigint, payload jsonb NOT NULL, occurred_at timestamptz NOT NULL, available_at timestamptz NOT NULL, attempt_count integer NOT NULL DEFAULT 0, next_attempt_at timestamptz, delivered_at timestamptz, CONSTRAINT sense_outbox_device_fk FOREIGN KEY (tenant_id, site_id, device_id) REFERENCES sense.devices(tenant_id, site_id, id), CONSTRAINT sense_outbox_event_id_format CHECK (event_id ~ '^audit_[0-9a-f]{32}$'), CONSTRAINT sense_outbox_event_type CHECK ( event_type IN ('device.created', 'device.desired_state.accepted') ), CONSTRAINT sense_outbox_identity_not_blank CHECK ( btrim(tenant_id) <> '' AND btrim(site_id) <> '' AND btrim(device_id) <> '' AND btrim(actor_id) <> '' ), CONSTRAINT sense_outbox_actor_type CHECK ( actor_type IN ('user', 'service', 'system') ), CONSTRAINT sense_outbox_generation_positive CHECK (aggregate_generation >= 1), CONSTRAINT sense_outbox_quota_version_positive CHECK ( quota_source_version IS NULL OR quota_source_version >= 1 ), CONSTRAINT sense_outbox_area_version_positive CHECK ( area_policy_source_version IS NULL OR area_policy_source_version >= 1 ), CONSTRAINT sense_outbox_attempt_nonnegative CHECK (attempt_count >= 0), CONSTRAINT sense_outbox_reason_length CHECK (reason IS NULL OR char_length(reason) <= 500), CONSTRAINT sense_outbox_trace_length CHECK (trace_id IS NULL OR char_length(trace_id) <= 128), CONSTRAINT sense_outbox_payload_object CHECK (jsonb_typeof(payload) = 'object'), CONSTRAINT sense_outbox_payload_kind CHECK ( (event_type = 'device.created' AND payload ->> 'kind' = 'device_created') OR (event_type = 'device.desired_state.accepted' AND payload ->> 'kind' = 'desired_state_accepted') ), CONSTRAINT sense_outbox_payload_redacted CHECK ( NOT (payload ?| ARRAY[ 'endpoint_ref', 'credential_ref', 'profile_token', 'path_name', 'password', 'stream_uri', 'mediamtx_config' ]) ) ); ALTER TABLE sense.device_operation_outbox OWNER TO sense_app; CREATE INDEX IF NOT EXISTS sense_outbox_delivery_idx ON sense.device_operation_outbox(delivered_at, next_attempt_at, available_at, event_id); CREATE INDEX IF NOT EXISTS sense_outbox_device_idx ON sense.device_operation_outbox(tenant_id, site_id, device_id, occurred_at, event_id); INSERT INTO sense.schema_migrations(version) VALUES (3) ON CONFLICT (version) DO NOTHING;