-- ============================================================================= -- migration_add_leak.sql - SHT30 전용 서버에 누수(leak) 수신을 다시 추가(통합) -- -- [목적] 1번 모듈(누수+카메라, sensor_id=1)과 2번 모듈(SHT30 온습도, sensor_id=2)이 -- "하나의 cafe24 서버 php/" 로 함께 보고하도록 통합한다. 이 마이그레이션은 -- sql/migration_drop_leak.sql 가 제거했던 누수 요소를 "가산(additive)·멱등"으로 -- 되돌린다(= migration_drop_leak.sql 의 역방향, 단 데이터 삭제 없이 가산만 수행). -- -- [안전성] 운영 중인 SHT30 서버에서 그대로 실행해도 안전하다: -- - sensor_metric(SHT30 측정) / sms_log / sensor_status / ingest_nonce 등 기존 테이블· -- 데이터는 전혀 건드리지 않는다. -- - 모든 변경은 "없을 때만 추가"(IF NOT EXISTS / information_schema 가드)이므로 -- 여러 번 재실행해도 오류가 나지 않는다. -- -- [되돌리는 항목] -- - sensor_log.event_type ENUM 에 leak_alert / leak_recovery 재추가 -- - sensor_log.is_leak 컬럼(없으면 추가) -- - sensor_status.is_leak 컬럼(없으면 추가) -- - leak_incident 테이블(없으면 생성) — 누수 사고(에피소드) 시작/복구 추적 -- - leak_photo 테이블(없으면 생성) — 누수 시 촬영 사진 메타데이터 -- -- 신규(통합) 설치라면 이 파일이 아니라 sql/schema_sht30.sql 하나만 실행하면 된다 -- (schema_sht30.sql 이 이미 누수 요소를 포함하도록 통합되어 있다). -- ============================================================================= SET NAMES utf8mb4; -- 1) sensor_log.event_type: 누수 enum 값을 다시 허용(멱등 — 동일 enum 재적용은 안전). ALTER TABLE `sensor_log` MODIFY `event_type` ENUM('startup','periodic','leak_alert','leak_recovery') NOT NULL DEFAULT 'periodic'; -- 2~3) 컬럼/인덱스 추가는 "없을 때만" 수행해 재실행해도 오류가 없게 한다. -- (MySQL/MariaDB 는 ADD COLUMN IF NOT EXISTS 호환이 일정치 않으므로 -- information_schema 로 가드하는 멱등 프로시저를 사용한다.) DROP PROCEDURE IF EXISTS _mig_add_leak; DELIMITER // CREATE PROCEDURE _mig_add_leak() BEGIN DECLARE db VARCHAR(64); SELECT DATABASE() INTO db; -- sensor_log.is_leak: 누수 여부(0/1) — 없으면 추가 IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = db AND TABLE_NAME = 'sensor_log' AND COLUMN_NAME = 'is_leak') THEN ALTER TABLE `sensor_log` ADD COLUMN `is_leak` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '누수 여부 (1=누수, 0=정상)' AFTER `event_type`; END IF; -- sensor_status.is_leak: 최신 누수 상태(0/1) — 없으면 추가 IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = db AND TABLE_NAME = 'sensor_status' AND COLUMN_NAME = 'is_leak') THEN ALTER TABLE `sensor_status` ADD COLUMN `is_leak` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '최신 누수 상태 (1=누수, 0=정상)' AFTER `last_event_type`; END IF; END // DELIMITER ; CALL _mig_add_leak(); DROP PROCEDURE IF EXISTS _mig_add_leak; -- 4) leak_incident: 누수 사고(에피소드) 추적. leak_alert 시 행을 열고(open), 같은 -- 센서의 leak_recovery 시 가장 최근 미복구 행을 닫는다(recovered_at 채움). CREATE TABLE IF NOT EXISTS `leak_incident` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `sensor_id` TINYINT UNSIGNED NOT NULL COMMENT '센서 번호(누수=1)', `device_id` VARCHAR(64) NOT NULL DEFAULT '', `sensor_name` VARCHAR(100) NOT NULL DEFAULT '', `device_location` VARCHAR(100) NOT NULL DEFAULT '', `started_at` DATETIME NOT NULL COMMENT '누수 감지(시작) 시각', `recovered_at` DATETIME NULL DEFAULT NULL COMMENT '누수 복구 시각(미복구면 NULL)', `log_id_alert` BIGINT UNSIGNED NULL DEFAULT NULL COMMENT 'leak_alert sensor_log.id', `log_id_recovery` BIGINT UNSIGNED NULL DEFAULT NULL COMMENT 'leak_recovery sensor_log.id', `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), INDEX `idx_sensor_open` (`sensor_id`, `recovered_at`), INDEX `idx_started_at` (`started_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='누수 사고(에피소드) 추적 (시작/복구)'; -- 5) leak_photo: 누수 시 촬영한 사진 메타데이터. 실제 파일은 php/var/photos/ 에 저장되고 -- filename 은 서버가 생성한 무작위 파일명(클라이언트 경로 미사용 — 경로주입 방지). CREATE TABLE IF NOT EXISTS `leak_photo` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `log_id` BIGINT UNSIGNED NOT NULL COMMENT 'leak_alert sensor_log.id', `sensor_id` TINYINT UNSIGNED NOT NULL, `device_id` VARCHAR(64) NOT NULL DEFAULT '', `filename` VARCHAR(128) NOT NULL COMMENT '서버 생성 파일명(var/photos/ 하위)', `mime` VARCHAR(40) NOT NULL DEFAULT 'image/jpeg', `bytes` INT UNSIGNED NOT NULL DEFAULT 0, `captured_at` DATETIME NOT NULL COMMENT '촬영(업로드) 시각', `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), INDEX `idx_log_id` (`log_id`), INDEX `idx_captured_at` (`captured_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='누수 사진 메타데이터 (파일은 var/photos/)';