feat(core): add ontology-backed asset and host runtime

This commit is contained in:
DCCONSTRUCTIONS
2026-08-22 14:47:44 +03:00
parent 6ed4414a97
commit b302b6ba1a
13 changed files with 1959 additions and 89 deletions
@@ -0,0 +1,284 @@
begin;
alter table device_management_command_receipts
drop constraint if exists device_management_command_receipts_command_kind_check;
alter table device_management_command_receipts
add constraint device_management_command_receipts_command_kind_check
check (command_kind in (
'owner_scope.ensure',
'project.ensure',
'collection.ensure',
'project_grant.upsert',
'adapter_package.ensure',
'adapter_version.register',
'model_profile.register',
'edge.ensure',
'route.ensure',
'enrollment_intent.ensure',
'device.claim',
'device.update',
'device.transfer',
'discovery.reject',
'discovery.expire',
'device_credential_binding.upsert',
'device_credential_binding.revoke',
'device_binding.ensure',
'device_binding.revoke',
'device_configuration_revision.create',
'device_configuration_desired.set',
'asset.ensure',
'asset_binding.ensure',
'asset_binding.close',
'infrastructure_host.ensure',
'infrastructure_endpoint.ensure',
'infrastructure_deployment.ensure',
'infrastructure_service_instance.ensure',
'health_observation.record'
));
create table if not exists device_assets (
id uuid primary key,
owner_scope_id uuid not null,
project_id uuid not null,
asset_key text not null
check (asset_key ~ '^[a-z][a-z0-9-]{1,62}$'),
display_name text not null
check (length(btrim(display_name)) between 1 and 160),
asset_type_ref text not null
check (length(btrim(asset_type_ref)) between 3 and 256),
lifecycle_state text not null default 'active'
check (lifecycle_state in ('active', 'retired')),
ontology_entity_id text not null default 'asset.asset'
check (ontology_entity_id = 'asset.asset'),
ontology_catalog_hash text not null default '229c61c02a790906'
check (ontology_catalog_hash = '229c61c02a790906'),
created_by_ref text not null
check (length(btrim(created_by_ref)) between 3 and 256),
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique (project_id, asset_key),
unique (id, project_id, owner_scope_id),
foreign key (project_id, owner_scope_id)
references device_projects(id, owner_scope_id)
);
create index if not exists device_assets_project_state_idx
on device_assets (project_id, lifecycle_state, updated_at desc);
create table if not exists device_asset_bindings (
id uuid primary key,
owner_scope_id uuid not null,
project_id uuid not null,
binding_key text not null
check (binding_key ~ '^[a-z][a-z0-9-]{1,62}$'),
device_id uuid not null,
asset_id uuid not null,
binding_kind text not null default 'tracking'
check (binding_kind in ('tracking', 'installed', 'assigned')),
valid_from timestamptz not null,
valid_to timestamptz,
provenance_ref text not null
check (length(btrim(provenance_ref)) between 3 and 256),
ontology_entity_id text not null default 'device.asset_binding'
check (ontology_entity_id = 'device.asset_binding'),
ontology_catalog_hash text not null default '229c61c02a790906'
check (ontology_catalog_hash = '229c61c02a790906'),
created_by_ref text not null
check (length(btrim(created_by_ref)) between 3 and 256),
closed_by_ref text
check (closed_by_ref is null or length(btrim(closed_by_ref)) between 3 and 256),
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique (project_id, binding_key),
foreign key (device_id, project_id, owner_scope_id)
references device_instances(id, project_id, owner_scope_id),
foreign key (asset_id, project_id, owner_scope_id)
references device_assets(id, project_id, owner_scope_id),
check (valid_to is null or valid_to > valid_from),
check ((valid_to is null and closed_by_ref is null) or (valid_to is not null and closed_by_ref is not null))
);
create unique index if not exists device_asset_bindings_active_device_idx
on device_asset_bindings (device_id)
where valid_to is null;
create index if not exists device_asset_bindings_asset_time_idx
on device_asset_bindings (asset_id, valid_from desc, valid_to);
create table if not exists device_infrastructure_hosts (
id uuid primary key,
owner_scope_id uuid not null,
project_id uuid not null,
host_key text not null
check (host_key ~ '^[a-z][a-z0-9-]{1,62}$'),
display_name text not null
check (length(btrim(display_name)) between 1 and 160),
provider_ref text
check (provider_ref is null or length(btrim(provider_ref)) between 3 and 256),
external_ref text
check (external_ref is null or length(btrim(external_ref)) between 3 and 256),
management_credential_ref text
check (
management_credential_ref is null
or management_credential_ref ~ '^secret-ref:[A-Za-z0-9][A-Za-z0-9._:/+-]{2,244}$'
),
lifecycle_state text not null default 'provisioning'
check (lifecycle_state in ('provisioning', 'active', 'suspended', 'retired')),
ontology_entity_id text not null default 'infrastructure.host'
check (ontology_entity_id = 'infrastructure.host'),
ontology_catalog_hash text not null default '229c61c02a790906'
check (ontology_catalog_hash = '229c61c02a790906'),
created_by_ref text not null
check (length(btrim(created_by_ref)) between 3 and 256),
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique (project_id, host_key),
unique (id, project_id, owner_scope_id),
foreign key (project_id, owner_scope_id)
references device_projects(id, owner_scope_id)
);
create index if not exists device_infrastructure_hosts_project_state_idx
on device_infrastructure_hosts (project_id, lifecycle_state, updated_at desc);
create table if not exists device_infrastructure_endpoints (
id uuid primary key,
owner_scope_id uuid not null,
project_id uuid not null,
host_id uuid not null,
endpoint_key text not null
check (endpoint_key ~ '^[a-z][a-z0-9-]{1,62}$'),
purpose text not null
check (purpose in ('management', 'service', 'monitoring')),
endpoint_uri text not null
check (
length(btrim(endpoint_uri)) between 8 and 512
and endpoint_uri !~ '@'
),
lifecycle_state text not null default 'active'
check (lifecycle_state in ('active', 'disabled', 'retired')),
ontology_entity_id text not null default 'infrastructure.endpoint'
check (ontology_entity_id = 'infrastructure.endpoint'),
ontology_catalog_hash text not null default '229c61c02a790906'
check (ontology_catalog_hash = '229c61c02a790906'),
created_by_ref text not null
check (length(btrim(created_by_ref)) between 3 and 256),
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique (host_id, endpoint_key),
unique (id, project_id, owner_scope_id),
foreign key (host_id, project_id, owner_scope_id)
references device_infrastructure_hosts(id, project_id, owner_scope_id)
);
create table if not exists device_infrastructure_deployments (
id uuid primary key,
owner_scope_id uuid not null,
project_id uuid not null,
host_id uuid not null,
deployment_key text not null
check (deployment_key ~ '^[a-z][a-z0-9-]{1,62}$'),
display_name text not null
check (length(btrim(display_name)) between 1 and 160),
artifact_ref text not null
check (length(btrim(artifact_ref)) between 3 and 256),
artifact_digest text not null
check (artifact_digest ~ '^sha256:[a-f0-9]{64}$'),
lifecycle_state text not null default 'desired'
check (lifecycle_state in ('desired', 'applying', 'active', 'failed', 'retired')),
ontology_entity_id text not null default 'infrastructure.deployment'
check (ontology_entity_id = 'infrastructure.deployment'),
ontology_catalog_hash text not null default '229c61c02a790906'
check (ontology_catalog_hash = '229c61c02a790906'),
created_by_ref text not null
check (length(btrim(created_by_ref)) between 3 and 256),
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique (project_id, deployment_key),
unique (id, project_id, owner_scope_id),
foreign key (host_id, project_id, owner_scope_id)
references device_infrastructure_hosts(id, project_id, owner_scope_id)
);
create table if not exists device_infrastructure_service_instances (
id uuid primary key,
owner_scope_id uuid not null,
project_id uuid not null,
host_id uuid not null,
deployment_id uuid not null,
edge_id uuid references device_edges(id),
service_key text not null
check (service_key ~ '^[a-z][a-z0-9-]{1,62}$'),
display_name text not null
check (length(btrim(display_name)) between 1 and 160),
service_role text not null
check (service_role ~ '^[a-z][a-z0-9._-]{1,63}$'),
lifecycle_state text not null default 'provisioning'
check (lifecycle_state in ('provisioning', 'active', 'degraded', 'stopped', 'retired')),
ontology_entity_id text not null default 'infrastructure.service_instance'
check (ontology_entity_id = 'infrastructure.service_instance'),
ontology_catalog_hash text not null default '229c61c02a790906'
check (ontology_catalog_hash = '229c61c02a790906'),
created_by_ref text not null
check (length(btrim(created_by_ref)) between 3 and 256),
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique (host_id, service_key),
unique (id, project_id, owner_scope_id),
foreign key (host_id, project_id, owner_scope_id)
references device_infrastructure_hosts(id, project_id, owner_scope_id),
foreign key (deployment_id, project_id, owner_scope_id)
references device_infrastructure_deployments(id, project_id, owner_scope_id)
);
create table if not exists device_health_observations (
id uuid primary key,
owner_scope_id uuid not null,
project_id uuid not null,
host_id uuid,
service_instance_id uuid,
observed_state text not null
check (observed_state in ('reachable', 'degraded', 'unreachable')),
evidence_class text not null
check (evidence_class in ('agent_probe', 'channel', 'management_probe', 'manual')),
source_ref text not null
check (length(btrim(source_ref)) between 3 and 256),
schema_ref text not null
check (length(btrim(schema_ref)) between 3 and 256),
evidence_projection jsonb not null default '{}'::jsonb
check (
jsonb_typeof(evidence_projection) = 'object'
and octet_length(evidence_projection::text) <= 16384
),
observed_at timestamptz not null,
expires_at timestamptz not null,
ontology_entity_id text not null default 'observation.health_observation'
check (ontology_entity_id = 'observation.health_observation'),
ontology_catalog_hash text not null default '229c61c02a790906'
check (ontology_catalog_hash = '229c61c02a790906'),
recorded_by_ref text not null
check (length(btrim(recorded_by_ref)) between 3 and 256),
created_at timestamptz not null default now(),
foreign key (project_id, owner_scope_id)
references device_projects(id, owner_scope_id),
foreign key (host_id, project_id, owner_scope_id)
references device_infrastructure_hosts(id, project_id, owner_scope_id),
foreign key (service_instance_id, project_id, owner_scope_id)
references device_infrastructure_service_instances(id, project_id, owner_scope_id),
check (
(host_id is not null and service_instance_id is null)
or (host_id is null and service_instance_id is not null)
),
check (expires_at > observed_at)
);
create index if not exists device_health_observations_host_time_idx
on device_health_observations (host_id, observed_at desc)
where host_id is not null;
create index if not exists device_health_observations_service_time_idx
on device_health_observations (service_instance_id, observed_at desc)
where service_instance_id is not null;
commit;