-- Migration: Event System -- Description: Creates tables for triggers, sensors, events, and enforcement -- Version: 20250101000003 -- ============================================================================ -- TRIGGER TABLE -- ============================================================================ CREATE TABLE trigger ( id BIGSERIAL PRIMARY KEY, ref TEXT NOT NULL UNIQUE, pack BIGINT REFERENCES pack(id) ON DELETE CASCADE, pack_ref TEXT, label TEXT NOT NULL, description TEXT, enabled BOOLEAN NOT NULL DEFAULT TRUE, param_schema JSONB, out_schema JSONB, created TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Constraints CONSTRAINT trigger_ref_lowercase CHECK (ref = LOWER(ref)), CONSTRAINT trigger_ref_format CHECK (ref ~ '^[^.]+\.[^.]+$') ); -- Indexes CREATE INDEX idx_trigger_ref ON trigger(ref); CREATE INDEX idx_trigger_pack ON trigger(pack); CREATE INDEX idx_trigger_enabled ON trigger(enabled) WHERE enabled = TRUE; CREATE INDEX idx_trigger_created ON trigger(created DESC); CREATE INDEX idx_trigger_pack_enabled ON trigger(pack, enabled); CREATE INDEX idx_trigger_enabled_created ON trigger(enabled, created DESC) WHERE enabled = TRUE; -- Trigger CREATE TRIGGER update_trigger_updated BEFORE UPDATE ON trigger FOR EACH ROW EXECUTE FUNCTION update_updated_column(); -- Permissions GRANT SELECT, INSERT, UPDATE, DELETE ON trigger TO svc_attune; GRANT USAGE, SELECT ON SEQUENCE trigger_id_seq TO svc_attune; -- Comments COMMENT ON TABLE trigger IS 'Trigger definitions that can activate rules'; COMMENT ON COLUMN trigger.ref IS 'Unique trigger reference (format: pack.name)'; COMMENT ON COLUMN trigger.label IS 'Human-readable trigger name'; COMMENT ON COLUMN trigger.enabled IS 'Whether this trigger is active'; COMMENT ON COLUMN trigger.param_schema IS 'JSON schema defining the expected configuration parameters when this trigger is used'; COMMENT ON COLUMN trigger.out_schema IS 'JSON schema defining the structure of event payloads generated by this trigger'; -- ============================================================================ -- SENSOR TABLE -- ============================================================================ CREATE TABLE sensor ( id BIGSERIAL PRIMARY KEY, ref TEXT NOT NULL UNIQUE, pack BIGINT REFERENCES pack(id) ON DELETE CASCADE, pack_ref TEXT, label TEXT NOT NULL, description TEXT NOT NULL, entrypoint TEXT NOT NULL, runtime BIGINT NOT NULL REFERENCES runtime(id) ON DELETE CASCADE, runtime_ref TEXT NOT NULL, trigger BIGINT NOT NULL REFERENCES trigger(id) ON DELETE CASCADE, trigger_ref TEXT NOT NULL, enabled BOOLEAN NOT NULL, param_schema JSONB, config JSONB, created TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Constraints CONSTRAINT sensor_ref_lowercase CHECK (ref = LOWER(ref)), CONSTRAINT sensor_ref_format CHECK (ref ~ '^[^.]+\.[^.]+$') ); -- Indexes CREATE INDEX idx_sensor_ref ON sensor(ref); CREATE INDEX idx_sensor_pack ON sensor(pack); CREATE INDEX idx_sensor_runtime ON sensor(runtime); CREATE INDEX idx_sensor_trigger ON sensor(trigger); CREATE INDEX idx_sensor_enabled ON sensor(enabled) WHERE enabled = TRUE; CREATE INDEX idx_sensor_created ON sensor(created DESC); CREATE INDEX idx_sensor_trigger_enabled ON sensor(trigger, enabled); CREATE INDEX idx_sensor_pack_enabled ON sensor(pack, enabled); CREATE INDEX idx_sensor_runtime_enabled ON sensor(runtime, enabled); CREATE INDEX idx_sensor_config ON sensor USING GIN (config); -- Trigger CREATE TRIGGER update_sensor_updated BEFORE UPDATE ON sensor FOR EACH ROW EXECUTE FUNCTION update_updated_column(); -- Permissions GRANT SELECT, INSERT, UPDATE, DELETE ON sensor TO svc_attune; GRANT USAGE, SELECT ON SEQUENCE sensor_id_seq TO svc_attune; -- Comments COMMENT ON TABLE sensor IS 'Sensors monitor for trigger conditions and generate events'; COMMENT ON COLUMN sensor.ref IS 'Unique sensor reference (format: pack.name)'; COMMENT ON COLUMN sensor.entrypoint IS 'Code entry point for the sensor'; COMMENT ON COLUMN sensor.runtime IS 'Execution environment for the sensor'; COMMENT ON COLUMN sensor.trigger IS 'Trigger that this sensor monitors for'; COMMENT ON COLUMN sensor.enabled IS 'Whether this sensor is active'; COMMENT ON COLUMN sensor.param_schema IS 'JSON schema describing expected configuration (optional, usually inherited from trigger)'; COMMENT ON COLUMN sensor.config IS 'Actual configuration values for this sensor instance (conforms to trigger param_schema)'; -- Add foreign key constraint to key table for sensor ownership ALTER TABLE key ADD CONSTRAINT key_owner_sensor_fkey FOREIGN KEY (owner_sensor) REFERENCES sensor(id) ON DELETE CASCADE; -- ============================================================================ -- EVENT TABLE -- ============================================================================ CREATE TABLE event ( id BIGSERIAL PRIMARY KEY, trigger BIGINT REFERENCES trigger(id) ON DELETE SET NULL, trigger_ref TEXT NOT NULL, config JSONB, payload JSONB, source BIGINT REFERENCES sensor(id), source_ref TEXT, created TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Indexes CREATE INDEX idx_event_trigger ON event(trigger); CREATE INDEX idx_event_trigger_ref ON event(trigger_ref); CREATE INDEX idx_event_source ON event(source); CREATE INDEX idx_event_created ON event(created DESC); CREATE INDEX idx_event_trigger_created ON event(trigger, created DESC); CREATE INDEX idx_event_trigger_ref_created ON event(trigger_ref, created DESC); CREATE INDEX idx_event_source_created ON event(source, created DESC); CREATE INDEX idx_event_payload_gin ON event USING GIN (payload); -- Trigger CREATE TRIGGER update_event_updated BEFORE UPDATE ON event FOR EACH ROW EXECUTE FUNCTION update_updated_column(); -- Permissions GRANT SELECT, INSERT, UPDATE, DELETE ON event TO svc_attune; GRANT USAGE, SELECT ON SEQUENCE event_id_seq TO svc_attune; -- Comments COMMENT ON TABLE event IS 'Events are instances of triggers firing'; COMMENT ON COLUMN event.trigger IS 'Trigger that fired (may be null if trigger deleted)'; COMMENT ON COLUMN event.trigger_ref IS 'Trigger reference (preserved even if trigger deleted)'; COMMENT ON COLUMN event.config IS 'Snapshot of trigger/sensor configuration at event time'; COMMENT ON COLUMN event.payload IS 'Event data payload'; COMMENT ON COLUMN event.source IS 'Sensor that generated this event'; -- ============================================================================ -- ENFORCEMENT TABLE -- ============================================================================ CREATE TABLE enforcement ( id BIGSERIAL PRIMARY KEY, rule BIGINT, -- Forward reference to rule table, will add constraint in next migration rule_ref TEXT NOT NULL, trigger_ref TEXT NOT NULL, config JSONB, event BIGINT REFERENCES event(id) ON DELETE SET NULL, status enforcement_status_enum NOT NULL DEFAULT 'created', payload JSONB NOT NULL, condition enforcement_condition_enum NOT NULL DEFAULT 'all', conditions JSONB NOT NULL DEFAULT '[]'::jsonb, created TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Constraints CONSTRAINT enforcement_condition_check CHECK (condition IN ('any', 'all')) ); -- Indexes CREATE INDEX idx_enforcement_rule ON enforcement(rule); CREATE INDEX idx_enforcement_rule_ref ON enforcement(rule_ref); CREATE INDEX idx_enforcement_trigger_ref ON enforcement(trigger_ref); CREATE INDEX idx_enforcement_event ON enforcement(event); CREATE INDEX idx_enforcement_status ON enforcement(status); CREATE INDEX idx_enforcement_created ON enforcement(created DESC); CREATE INDEX idx_enforcement_status_created ON enforcement(status, created DESC); CREATE INDEX idx_enforcement_rule_status ON enforcement(rule, status); CREATE INDEX idx_enforcement_event_status ON enforcement(event, status); CREATE INDEX idx_enforcement_payload_gin ON enforcement USING GIN (payload); CREATE INDEX idx_enforcement_conditions_gin ON enforcement USING GIN (conditions); -- Trigger CREATE TRIGGER update_enforcement_updated BEFORE UPDATE ON enforcement FOR EACH ROW EXECUTE FUNCTION update_updated_column(); -- Permissions GRANT SELECT, INSERT, UPDATE, DELETE ON enforcement TO svc_attune; GRANT USAGE, SELECT ON SEQUENCE enforcement_id_seq TO svc_attune; -- Comments COMMENT ON TABLE enforcement IS 'Enforcements represent rule triggering by events'; COMMENT ON COLUMN enforcement.rule IS 'Rule being enforced (may be null if rule deleted)'; COMMENT ON COLUMN enforcement.rule_ref IS 'Rule reference (preserved even if rule deleted)'; COMMENT ON COLUMN enforcement.event IS 'Event that triggered this enforcement'; COMMENT ON COLUMN enforcement.status IS 'Processing status'; COMMENT ON COLUMN enforcement.payload IS 'Event payload for rule evaluation'; COMMENT ON COLUMN enforcement.condition IS 'Logical operator for conditions (any=OR, all=AND)'; COMMENT ON COLUMN enforcement.conditions IS 'Condition expressions to evaluate';