drop schema "public" show search_path; set schema "ptmain"; CREATE SCHEMA if not exists ptmain; GRANT USAGE, CREATE ON SCHEMA ptmain TO sathumper; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA ptmain TO sathumper; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA ptmain TO sathumper; ALTER DEFAULT PRIVILEGES IN SCHEMA ptmain GRANT ALL PRIVILEGES ON TABLES TO sathumper; -- Create schema if not exists insert into -- Create main configuration table CREATE TABLE app_configuration ( id BIGSERIAL PRIMARY KEY, key VARCHAR(255) NOT NULL, value TEXT NOT NULL, label VARCHAR(255), content_type VARCHAR(255) DEFAULT 'text/plain', valid_from TIMESTAMPTZ, expires_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, modified_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, etag UUID DEFAULT gen_random_uuid(), CONSTRAINT app_configuration_key_unique UNIQUE (key, valid_from) ); -- Create history table CREATE TABLE app_configuration_history ( history_id BIGSERIAL PRIMARY KEY, operation CHAR(1) NOT NULL, -- I = Insert, U = Update, D = Delete changed_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, changed_by TEXT NOT NULL DEFAULT CURRENT_USER, -- Original columns id BIGINT NOT NULL, key VARCHAR(255) NOT NULL, value TEXT NOT NULL, label VARCHAR(255), content_type VARCHAR(255), valid_from TIMESTAMPTZ, expires_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL, modified_at TIMESTAMPTZ NOT NULL, etag UUID ); -- Create function for updating modified_at CREATE OR REPLACE FUNCTION update_modified_at() RETURNS TRIGGER AS $$ BEGIN NEW.modified_at = CURRENT_TIMESTAMP; RETURN NEW; END; $$ LANGUAGE plpgsql; -- Create history tracking function CREATE OR REPLACE FUNCTION track_configuration_history() RETURNS TRIGGER AS $$ BEGIN -- Indsæt historikpost baseret på operationstypen IF TG_OP = 'INSERT' THEN INSERT INTO app_configuration_history( operation, id, key, value, label, content_type, valid_from, expires_at, created_at, modified_at, etag ) VALUES ( 'I', NEW.id, NEW.key, NEW.value, NEW.label, NEW.content_type, NEW.valid_from, NEW.expires_at, NEW.created_at, NEW.modified_at, NEW.etag ); ELSIF TG_OP = 'UPDATE' OR TG_OP = 'DELETE' THEN -- Brug OLD for både UPDATE og DELETE INSERT INTO app_configuration_history( operation, id, key, value, label, content_type, valid_from, expires_at, created_at, modified_at, etag ) VALUES ( CASE WHEN TG_OP = 'UPDATE' THEN 'U' WHEN TG_OP = 'DELETE' THEN 'D' END, OLD.id, OLD.key, OLD.value, OLD.label, OLD.content_type, OLD.valid_from, OLD.expires_at, OLD.created_at, OLD.modified_at, OLD.etag ); END IF; -- Returner NULL for AFTER-trigger RETURN NULL; EXCEPTION WHEN others THEN -- Log fejl og rejs undtagelse RAISE EXCEPTION 'Fejl i track_configuration_history: %', SQLERRM; END; $$ LANGUAGE plpgsql; -- Create triggers CREATE TRIGGER trg_app_configuration_modified_at BEFORE UPDATE ON app_configuration FOR EACH ROW EXECUTE FUNCTION update_modified_at(); CREATE TRIGGER trg_app_configuration_history AFTER INSERT OR UPDATE OR DELETE ON app_configuration FOR EACH ROW EXECUTE FUNCTION track_configuration_history(); CREATE TRIGGER trg_app_configuration_notify AFTER INSERT OR UPDATE ON app_configuration FOR EACH ROW EXECUTE FUNCTION notify_config_change(); -- Comments COMMENT ON TABLE app_configuration IS 'Application configuration with temporal validity'; COMMENT ON TABLE app_configuration_history IS 'Historical changes to application configuration'; COMMENT ON COLUMN app_configuration_history.operation IS 'Type of operation: I=Insert, U=Update, D=Delete'; COMMENT ON COLUMN app_configuration_history.changed_at IS 'When the change occurred'; COMMENT ON COLUMN app_configuration_history.changed_by IS 'User who made the change'; DELETE from ptmain.app_configuration -- Email templates configuration INSERT INTO ptmain.app_configuration ("key",value,"label",content_type,valid_from,expires_at,created_at,modified_at,etag) VALUES ('Debug','true',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','f1348731-9396-4f1d-b40a-7fbd23a897d2'::uuid), ('Database:ConnectionString','"Server=db.example.com;Port=5432"',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','2aa0bc3e-fa24-449a-8f25-a76d9b4d535e'::uuid), ('Database:Timeout','30',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','d25ebb14-49f6-4e33-9ac7-a3253705d0fb'::uuid), ('Database:UseSSL','true',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','f4d52ec4-b723-4561-9b18-0e7a68b89a17'::uuid), ('Logging:FileOptions','{"Path": "/var/logs/app.log", "MaxSizeMB": 100, "RetentionDays": 7}',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','06c0891d-a860-4acc-917a-d0877f511c1b'::uuid), ('Features:Experimental','{"Enabled": true, "RolloutPercentage": 25, "AllowedUserGroups": ["beta"]}',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','0136fdef-51d9-4909-82ef-f72053ce6d6d'::uuid), ('API:Endpoints','"/api/users"',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','fe362b69-a486-48ad-9165-2e623e2e6f70'::uuid), ('API:Endpoints','"/api/products"',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','c087e2d4-1f38-4814-b4dd-f30c463dc6d1'::uuid);