CREATE TABLE IF NOT EXISTS fabric_entry_points ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), cluster_id UUID NOT NULL REFERENCES clusters(id) ON DELETE CASCADE, name TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'active', endpoint_type TEXT NOT NULL DEFAULT 'client_access', public_endpoint TEXT, policy JSONB NOT NULL DEFAULT '{}'::JSONB, metadata JSONB NOT NULL DEFAULT '{}'::JSONB, created_by_user_id UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), CONSTRAINT fabric_entry_points_status_check CHECK (status IN ('active', 'disabled', 'maintenance')), CONSTRAINT fabric_entry_points_type_check CHECK (endpoint_type IN ('client_access', 'admin', 'api', 'other')) ); CREATE UNIQUE INDEX IF NOT EXISTS idx_fabric_entry_points_cluster_name ON fabric_entry_points(cluster_id, LOWER(name)); CREATE INDEX IF NOT EXISTS idx_fabric_entry_points_cluster_status ON fabric_entry_points(cluster_id, status, endpoint_type); CREATE TABLE IF NOT EXISTS fabric_entry_point_nodes ( entry_point_id UUID NOT NULL REFERENCES fabric_entry_points(id) ON DELETE CASCADE, cluster_id UUID NOT NULL REFERENCES clusters(id) ON DELETE CASCADE, node_id UUID NOT NULL REFERENCES nodes(id) ON DELETE CASCADE, status TEXT NOT NULL DEFAULT 'active', priority INTEGER NOT NULL DEFAULT 100, metadata JSONB NOT NULL DEFAULT '{}'::JSONB, added_by_user_id UUID REFERENCES users(id) ON DELETE SET NULL, added_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (entry_point_id, node_id), CONSTRAINT fabric_entry_point_nodes_status_check CHECK (status IN ('active', 'disabled', 'maintenance')), CONSTRAINT fabric_entry_point_nodes_priority_check CHECK (priority >= 0) ); CREATE INDEX IF NOT EXISTS idx_fabric_entry_point_nodes_cluster_node ON fabric_entry_point_nodes(cluster_id, node_id, status); CREATE TABLE IF NOT EXISTS fabric_egress_pools ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), cluster_id UUID NOT NULL REFERENCES clusters(id) ON DELETE CASCADE, name TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'active', description TEXT, route_scope JSONB NOT NULL DEFAULT '{}'::JSONB, policy JSONB NOT NULL DEFAULT '{}'::JSONB, metadata JSONB NOT NULL DEFAULT '{}'::JSONB, created_by_user_id UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), CONSTRAINT fabric_egress_pools_status_check CHECK (status IN ('active', 'disabled', 'maintenance')) ); CREATE UNIQUE INDEX IF NOT EXISTS idx_fabric_egress_pools_cluster_name ON fabric_egress_pools(cluster_id, LOWER(name)); CREATE INDEX IF NOT EXISTS idx_fabric_egress_pools_cluster_status ON fabric_egress_pools(cluster_id, status); CREATE TABLE IF NOT EXISTS fabric_egress_pool_nodes ( egress_pool_id UUID NOT NULL REFERENCES fabric_egress_pools(id) ON DELETE CASCADE, cluster_id UUID NOT NULL REFERENCES clusters(id) ON DELETE CASCADE, node_id UUID NOT NULL REFERENCES nodes(id) ON DELETE CASCADE, status TEXT NOT NULL DEFAULT 'active', priority INTEGER NOT NULL DEFAULT 100, metadata JSONB NOT NULL DEFAULT '{}'::JSONB, added_by_user_id UUID REFERENCES users(id) ON DELETE SET NULL, added_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (egress_pool_id, node_id), CONSTRAINT fabric_egress_pool_nodes_status_check CHECK (status IN ('active', 'disabled', 'maintenance')), CONSTRAINT fabric_egress_pool_nodes_priority_check CHECK (priority >= 0) ); CREATE INDEX IF NOT EXISTS idx_fabric_egress_pool_nodes_cluster_node ON fabric_egress_pool_nodes(cluster_id, node_id, status);