-- Migration: Pack System -- Description: Creates pack, runtime, and runtime_version tables -- Version: 20250101000002 -- ============================================================================ -- PACK TABLE -- ============================================================================ CREATE TABLE pack ( id BIGSERIAL PRIMARY KEY, ref TEXT NOT NULL UNIQUE, label TEXT NOT NULL, description TEXT, version TEXT NOT NULL, conf_schema JSONB NOT NULL DEFAULT '{}'::jsonb, config JSONB NOT NULL DEFAULT '{}'::jsonb, meta JSONB NOT NULL DEFAULT '{}'::jsonb, tags TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], runtime_deps TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], dependencies TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], is_standard BOOLEAN NOT NULL DEFAULT FALSE, installers JSONB DEFAULT '[]'::jsonb, -- Installation metadata (nullable for non-installed packs) source_type TEXT, source_url TEXT, source_ref TEXT, checksum TEXT, checksum_verified BOOLEAN DEFAULT FALSE, installed_at TIMESTAMPTZ, installed_by BIGINT, installation_method TEXT, storage_path TEXT, created TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Constraints CONSTRAINT pack_ref_lowercase CHECK (ref = LOWER(ref)), CONSTRAINT pack_ref_format CHECK (ref ~ '^[a-z][a-z0-9_-]+$'), CONSTRAINT pack_version_semver CHECK ( version ~ '^\d+\.\d+\.\d+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$' ) ); -- Indexes CREATE INDEX idx_pack_ref ON pack(ref); CREATE INDEX idx_pack_created ON pack(created DESC); CREATE INDEX idx_pack_is_standard ON pack(is_standard) WHERE is_standard = TRUE; CREATE INDEX idx_pack_is_standard_created ON pack(is_standard, created DESC); CREATE INDEX idx_pack_version_created ON pack(version, created DESC); CREATE INDEX idx_pack_config_gin ON pack USING GIN (config); CREATE INDEX idx_pack_meta_gin ON pack USING GIN (meta); CREATE INDEX idx_pack_tags_gin ON pack USING GIN (tags); CREATE INDEX idx_pack_runtime_deps_gin ON pack USING GIN (runtime_deps); CREATE INDEX idx_pack_dependencies_gin ON pack USING GIN (dependencies); CREATE INDEX idx_pack_installed_at ON pack(installed_at DESC) WHERE installed_at IS NOT NULL; CREATE INDEX idx_pack_installed_by ON pack(installed_by) WHERE installed_by IS NOT NULL; CREATE INDEX idx_pack_source_type ON pack(source_type) WHERE source_type IS NOT NULL; -- Trigger CREATE TRIGGER update_pack_updated BEFORE UPDATE ON pack FOR EACH ROW EXECUTE FUNCTION update_updated_column(); -- Comments COMMENT ON TABLE pack IS 'Packs bundle related automation components'; COMMENT ON COLUMN pack.ref IS 'Unique pack reference identifier (e.g., "slack", "github")'; COMMENT ON COLUMN pack.label IS 'Human-readable pack name'; COMMENT ON COLUMN pack.version IS 'Semantic version of the pack'; COMMENT ON COLUMN pack.conf_schema IS 'JSON schema for pack configuration'; COMMENT ON COLUMN pack.config IS 'Pack configuration values'; COMMENT ON COLUMN pack.meta IS 'Pack metadata'; COMMENT ON COLUMN pack.runtime_deps IS 'Array of required runtime references (e.g., shell, python, nodejs)'; COMMENT ON COLUMN pack.dependencies IS 'Array of required pack references (e.g., core, utils)'; COMMENT ON COLUMN pack.is_standard IS 'Whether this is a core/built-in pack'; COMMENT ON COLUMN pack.source_type IS 'Installation source type (e.g., "git", "local", "registry")'; COMMENT ON COLUMN pack.source_url IS 'URL or path where pack was installed from'; COMMENT ON COLUMN pack.source_ref IS 'Git ref, version tag, or other source reference'; COMMENT ON COLUMN pack.checksum IS 'Content checksum for verification'; COMMENT ON COLUMN pack.checksum_verified IS 'Whether checksum has been verified'; COMMENT ON COLUMN pack.installed_at IS 'Timestamp when pack was installed'; COMMENT ON COLUMN pack.installed_by IS 'Identity ID of user who installed the pack'; COMMENT ON COLUMN pack.installation_method IS 'Method used for installation (e.g., "cli", "api", "auto")'; COMMENT ON COLUMN pack.storage_path IS 'Filesystem path where pack files are stored'; -- ============================================================================ -- RUNTIME TABLE -- ============================================================================ CREATE TABLE runtime ( id BIGSERIAL PRIMARY KEY, ref TEXT NOT NULL UNIQUE, pack BIGINT REFERENCES pack(id) ON DELETE CASCADE, pack_ref TEXT, description TEXT, name TEXT NOT NULL, distributions JSONB NOT NULL, installation JSONB, installers JSONB DEFAULT '[]'::jsonb, -- Execution configuration: describes how to execute actions using this runtime, -- how to create isolated environments, and how to install dependencies. -- -- Structure: -- { -- "interpreter": { -- "binary": "python3", -- interpreter binary name or path -- "args": [], -- additional args before the action file -- "file_extension": ".py" -- file extension this runtime handles -- }, -- "environment": { -- optional: isolated environment config -- "env_type": "virtualenv", -- "virtualenv", "node_modules", "none" -- "dir_name": ".venv", -- directory name relative to pack dir -- "create_command": ["python3", "-m", "venv", "{env_dir}"], -- "interpreter_path": "{env_dir}/bin/python3" -- overrides interpreter.binary -- }, -- "dependencies": { -- optional: dependency management config -- "manifest_file": "requirements.txt", -- "install_command": ["{interpreter}", "-m", "pip", "install", "-r", "{manifest_path}"] -- } -- } -- -- Template variables: -- {pack_dir} - absolute path to the pack directory -- {env_dir} - resolved environment directory (pack_dir/dir_name) -- {interpreter} - resolved interpreter path -- {action_file} - absolute path to the action script file -- {manifest_path} - absolute path to the dependency manifest file execution_config JSONB NOT NULL DEFAULT '{}'::jsonb, created TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Constraints CONSTRAINT runtime_ref_lowercase CHECK (ref = LOWER(ref)) ); -- Indexes CREATE INDEX idx_runtime_ref ON runtime(ref); CREATE INDEX idx_runtime_pack ON runtime(pack); CREATE INDEX idx_runtime_created ON runtime(created DESC); CREATE INDEX idx_runtime_name ON runtime(name); CREATE INDEX idx_runtime_verification ON runtime USING GIN ((distributions->'verification')); CREATE INDEX idx_runtime_execution_config ON runtime USING GIN (execution_config); -- Trigger CREATE TRIGGER update_runtime_updated BEFORE UPDATE ON runtime FOR EACH ROW EXECUTE FUNCTION update_updated_column(); -- Comments COMMENT ON TABLE runtime IS 'Runtime environments for executing actions and sensors (unified)'; COMMENT ON COLUMN runtime.ref IS 'Unique runtime reference (format: pack.name, e.g., core.python)'; COMMENT ON COLUMN runtime.name IS 'Runtime name (e.g., "Python", "Node.js", "Shell")'; COMMENT ON COLUMN runtime.distributions IS 'Runtime distribution metadata including verification commands, version requirements, and capabilities'; COMMENT ON COLUMN runtime.installation IS 'Installation requirements and instructions including package managers and setup steps'; COMMENT ON COLUMN runtime.installers IS 'Array of installer actions to create pack-specific runtime environments. Each installer defines commands to set up isolated environments (e.g., Python venv, npm install).'; COMMENT ON COLUMN runtime.execution_config IS 'Execution configuration: interpreter, environment setup, and dependency management. Drives how the worker executes actions and how pack install sets up environments.'; -- ============================================================================ -- RUNTIME VERSION TABLE -- ============================================================================ CREATE TABLE runtime_version ( id BIGSERIAL PRIMARY KEY, runtime BIGINT NOT NULL REFERENCES runtime(id) ON DELETE CASCADE, runtime_ref TEXT NOT NULL, -- Semantic version string (e.g., "3.12.1", "20.11.0") version TEXT NOT NULL, -- Individual version components for efficient range queries. -- Nullable because some runtimes may use non-numeric versioning. version_major INT, version_minor INT, version_patch INT, -- Complete execution configuration for this specific version. -- This is NOT a diff/override — it is a full standalone config that can -- replace the parent runtime's execution_config when this version is selected. -- Structure is identical to runtime.execution_config (RuntimeExecutionConfig). execution_config JSONB NOT NULL DEFAULT '{}'::jsonb, -- Version-specific distribution/verification metadata. -- Structure mirrors runtime.distributions but with version-specific commands. -- Example: verification commands that check for a specific binary like python3.12. distributions JSONB NOT NULL DEFAULT '{}'::jsonb, -- Whether this version is the default for the parent runtime. -- At most one version per runtime should be marked as default. is_default BOOLEAN NOT NULL DEFAULT FALSE, -- Whether this version has been verified as available on the current system. available BOOLEAN NOT NULL DEFAULT TRUE, -- When this version was last verified (via running verification commands). verified_at TIMESTAMPTZ, -- Arbitrary version-specific metadata (e.g., EOL date, release notes URL, -- feature flags, platform-specific notes). meta JSONB NOT NULL DEFAULT '{}'::jsonb, created TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Constraints CONSTRAINT runtime_version_unique UNIQUE(runtime, version) ); -- Indexes CREATE INDEX idx_runtime_version_runtime ON runtime_version(runtime); CREATE INDEX idx_runtime_version_runtime_ref ON runtime_version(runtime_ref); CREATE INDEX idx_runtime_version_version ON runtime_version(version); CREATE INDEX idx_runtime_version_available ON runtime_version(available) WHERE available = TRUE; CREATE INDEX idx_runtime_version_is_default ON runtime_version(is_default) WHERE is_default = TRUE; CREATE INDEX idx_runtime_version_components ON runtime_version(runtime, version_major, version_minor, version_patch); CREATE INDEX idx_runtime_version_created ON runtime_version(created DESC); CREATE INDEX idx_runtime_version_execution_config ON runtime_version USING GIN (execution_config); CREATE INDEX idx_runtime_version_meta ON runtime_version USING GIN (meta); -- Trigger CREATE TRIGGER update_runtime_version_updated BEFORE UPDATE ON runtime_version FOR EACH ROW EXECUTE FUNCTION update_updated_column(); -- Comments COMMENT ON TABLE runtime_version IS 'Specific versions of a runtime (e.g., Python 3.11, 3.12) with version-specific execution configuration'; COMMENT ON COLUMN runtime_version.runtime IS 'Parent runtime this version belongs to'; COMMENT ON COLUMN runtime_version.runtime_ref IS 'Parent runtime ref (e.g., core.python) for display/filtering'; COMMENT ON COLUMN runtime_version.version IS 'Semantic version string (e.g., "3.12.1", "20.11.0")'; COMMENT ON COLUMN runtime_version.version_major IS 'Major version component for efficient range queries'; COMMENT ON COLUMN runtime_version.version_minor IS 'Minor version component for efficient range queries'; COMMENT ON COLUMN runtime_version.version_patch IS 'Patch version component for efficient range queries'; COMMENT ON COLUMN runtime_version.execution_config IS 'Complete execution configuration for this version (same structure as runtime.execution_config)'; COMMENT ON COLUMN runtime_version.distributions IS 'Version-specific distribution/verification metadata'; COMMENT ON COLUMN runtime_version.is_default IS 'Whether this is the default version for the parent runtime (at most one per runtime)'; COMMENT ON COLUMN runtime_version.available IS 'Whether this version has been verified as available on the system'; COMMENT ON COLUMN runtime_version.verified_at IS 'Timestamp of last availability verification'; COMMENT ON COLUMN runtime_version.meta IS 'Arbitrary version-specific metadata';