-- Migration 2026-04-16 : enrichissement applications IODA + table qualys_missing_servers -- Idempotent (re-jouable sans casse) BEGIN; -- ========================================================================= -- 1) Extension table applications avec champs IODA -- ========================================================================= ALTER TABLE applications ADD COLUMN IF NOT EXISTS ioda_libelle varchar(200); ALTER TABLE applications ADD COLUMN IF NOT EXISTS ioda_lib_court varchar(50); ALTER TABLE applications ADD COLUMN IF NOT EXISTS ioda_code_pos varchar(20); ALTER TABLE applications ADD COLUMN IF NOT EXISTS ioda_type varchar(50); ALTER TABLE applications ADD COLUMN IF NOT EXISTS ioda_statut varchar(50); ALTER TABLE applications ADD COLUMN IF NOT EXISTS ioda_alias text; ALTER TABLE applications ADD COLUMN IF NOT EXISTS ioda_perimetre varchar(100); ALTER TABLE applications ADD COLUMN IF NOT EXISTS ioda_dept_domaine varchar(200); ALTER TABLE applications ADD COLUMN IF NOT EXISTS ioda_resp_metier varchar(100); ALTER TABLE applications ADD COLUMN IF NOT EXISTS ioda_resp_dsi varchar(100); ALTER TABLE applications ADD COLUMN IF NOT EXISTS ioda_nb_components integer; ALTER TABLE applications ADD COLUMN IF NOT EXISTS ioda_commentaire text; ALTER TABLE applications ADD COLUMN IF NOT EXISTS ioda_imported_at timestamptz; CREATE UNIQUE INDEX IF NOT EXISTS applications_ioda_libelle_uniq ON applications (ioda_libelle) WHERE ioda_libelle IS NOT NULL; COMMENT ON COLUMN applications.ioda_libelle IS 'Libellé service métier IODA (clé d''import)'; COMMENT ON COLUMN applications.ioda_code_pos IS 'Code zone POS IODA (TRA, ADV, …)'; COMMENT ON COLUMN applications.ioda_resp_metier IS 'Responsable Service Métier (à notifier patching)'; COMMENT ON COLUMN applications.ioda_resp_dsi IS 'Responsable Service DSI (à notifier patching)'; -- ========================================================================= -- 2) Table qualys_missing_servers (serveurs absents de Qualys + raison) -- ========================================================================= CREATE TABLE IF NOT EXISTS qualys_missing_servers ( id serial PRIMARY KEY, hostname varchar(255) NOT NULL, hostname_norm varchar(255) GENERATED ALWAYS AS (lower(hostname)) STORED, environnement varchar(50), sources_present varchar(100), -- ex: "Cyberark+S1+ITOP" in_cyberark boolean DEFAULT false, in_sentinel boolean DEFAULT false, in_itop boolean DEFAULT false, server_id integer REFERENCES servers(id) ON DELETE SET NULL, reason_category varchar(30), -- appliance | ot_scada | virtualisation | embedded | oubli | decom | inconnu | other reason_detail text, status varchar(20) DEFAULT 'a_traiter', -- a_traiter | a_enroler | exempt | enrole | decom priority smallint DEFAULT 3, -- 1 (urgent) → 5 (faible) notes text, source_file varchar(100), -- fichier d'origine last_seen_at timestamptz DEFAULT now(), created_at timestamptz DEFAULT now(), updated_at timestamptz DEFAULT now(), CONSTRAINT qms_status_check CHECK (status IN ('a_traiter','a_enroler','exempt','enrole','decom')), CONSTRAINT qms_reason_check CHECK (reason_category IS NULL OR reason_category IN ('appliance','ot_scada','virtualisation','embedded','oubli','decom','inconnu','other')) ); CREATE UNIQUE INDEX IF NOT EXISTS qms_hostname_norm_uniq ON qualys_missing_servers (hostname_norm); CREATE INDEX IF NOT EXISTS qms_status_idx ON qualys_missing_servers (status); CREATE INDEX IF NOT EXISTS qms_reason_idx ON qualys_missing_servers (reason_category); CREATE INDEX IF NOT EXISTS qms_server_id_idx ON qualys_missing_servers (server_id); COMMENT ON TABLE qualys_missing_servers IS 'Serveurs détectés ailleurs (CA/S1/iTop) mais absents de Qualys + raison'; COMMENT ON COLUMN qualys_missing_servers.reason_category IS 'appliance, ot_scada, virtualisation (ESXi), embedded, oubli (à enrôler), decom, inconnu, other'; COMMENT ON COLUMN qualys_missing_servers.status IS 'a_traiter, a_enroler, exempt (légitimement hors Qualys), enrole (fait), decom'; COMMENT ON COLUMN qualys_missing_servers.priority IS '1 urgent → 5 faible (auto-calc selon sources)'; -- Trigger updated_at CREATE OR REPLACE FUNCTION qms_set_updated_at() RETURNS trigger AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS qms_updated_at_trg ON qualys_missing_servers; CREATE TRIGGER qms_updated_at_trg BEFORE UPDATE ON qualys_missing_servers FOR EACH ROW EXECUTE FUNCTION qms_set_updated_at(); COMMIT;