Rule‐engine ‐세부기능 - nhnacademy-aiot3-4iren/4iren-wiki GitHub Wiki

룰엔진 기능 및 비기능 요구사항

룰은 단순 목록이 아니라 그래프(플로우) 구조다. START → 조건 노드 → (분기/OR 병합) → ALERT 노드로 연결한다.

1. 기능 요구사항

1.1 플로우 CRUD

  • 플로우 생성 / 조회 / 수정 / 삭제
  • 플로우 활성화 / 비활성화
  • 플로우 유효성 검증 (진입점 단일성, 순환 참조 방지 — DFS 기반 사이클 탐지)
  • 노드·엣지는 개별 API가 아니라 플로우 단위로 함께 저장한다. 수정 시 기존 노드·연결을 모두 교체하므로 노드 ID는 수정 전후로 유지되지 않는다.

1.2 플로우 스케줄

  • 요일 및 시간대 범위를 지정해 플로우가 동작할 구간을 제한한다.
  • 스케줄 등록 / 조회 / 삭제

1.3 템플릿

  • 템플릿 CRUD
  • 강의실이 보유한 측정 항목을 기준으로, 요구 항목을 모두 충족하는 템플릿만 추천한다.
  • 템플릿 상세를 조회한 뒤 클라이언트가 플로우 생성 API로 다시 제출하는 방식이다. (서버 측 복사 전용 API는 없다)

1.4 노드 설정 검증

  • 노드 타입별 설정값(JSON)의 유효성을 검증한다.
  • 타입별 기본값을 내려주는 API는 제공하지 않는다.

1.5 노드 타입

구분 노드 설명
시작 START 플로우 진입점
조건 THRESHOLD 수신된 현재값과 임계치 비교
조건 AVERAGE 지정 구간 평균 비교
조건 DURATION 조건이 일정 시간 지속되었는지 판단
조건 GRADIENT 지정 구간 변화율 비교
논리 OR 여러 상위 분기 결과를 병합
액션 ALERT 텔레그램 알림 이벤트 발행
  • 측정 항목: CO2, 온도, 습도, 조도, 기압, TVOC, 적외선
  • 비교 연산자: >, >=, <, <=, =, !=

1.6 플로우 실행

  • RabbitMQ로 수신한 센서 데이터가 트리거가 된다. (주기 폴링·스케줄 평가 없음)
  • 해당 강의실의 활성 플로우를 조회해(Redis 캐시) 스케줄 조건을 통과한 플로우만 실행한다.
  • 센서 메시지 수신 시 TimeSeriesPreparationService가 AVERAGE/DURATION/GRADIENT 노드용 시계열 데이터를 Redis ZSet(room:{id}:metric:{TYPE}:ts)에 자동 저장한다.
  • 실행은 START의 참(TRUE) 분기부터 시작하는 BFS 그래프 순회이며, 각 조건 노드의 판정 결과에 따라 TRUE 또는 FALSE 한쪽 분기만 진행한다.
  • 선택되지 않은 분기는 하위 OR 노드의 입력을 BLOCKED로 표시해, 남은 입력만으로 판정 가능한 OR을 다시 평가한다.
  • ALERT 노드는 순회 도중 인라인으로 실행된다.

1.7 알림 발행

  • 알림 유형: COMFORT_LIMIT_EXCEEDED(쾌적 범위 이탈), VENTILATION_RECOMMEND(환기 권장) — 유형은 ALERT 노드 설정에서 작성자가 선택한다.
  • 알림 이벤트를 RabbitMQ로 발행하며, 실제 텔레그램 발송은 Notification 서비스가 수행한다.
  • 중복 발송 방지: ALERT 노드 ID + 조건 판정 결과 해시를 키로 Redis 락을 걸고, 노드에 설정된 쿨다운 시간 동안 재발행을 차단한다. (해시에 측정값 자체는 포함되지 않으므로, 같은 조건이면 값이 더 악화되어도 쿨다운 중에는 재발행하지 않는다)

1.8 권한

  • 플로우 관련 API는 X-User-Id / X-User-Role 헤더를 검증하고, Core에 해당 강의실 관리 권한을 조회해 OWNER·ADMIN만 허용한다.

2. 이 서비스가 하지 않는 것

  • 기기 제어를 하지 않는다. 액션 노드는 ALERT 하나뿐이며 냉난방기 on/off 등 제어 명령 경로가 없다.
  • 룰 간 우선순위·충돌 조정을 하지 않는다. 플로우에 우선순위 필드가 없고, 활성 플로우는 모두 독립적으로 동시에 실행된다. 같은 상황에 두 플로우가 걸리면 각각 알림을 발행한다.
  • 실행 이력을 저장하지 않는다. 실행·오류는 로그로만 남고, 이력 테이블이 없다. 발송된 알림 이력은 Notification 서비스에 남는다.
  • 센서 오작동 누적 탐지를 하지 않는다. 임계치 이탈 누적 카운트와 쿨다운은 Processing 서비스가 담당한다.

3. 비기능 요구사항

3.1 성능

  • 강의실의 여러 플로우를 가상 스레드 기반으로 동시 실행한다.
  • 메시지 리스너는 비동기로 룰 엔진 처리를 수행하되, 처리 완료 후 RabbitMQ ack를 한다.
  • 강의실별 활성 플로우 조회는 Redis 캐시로 처리한다.
  • 시계열 데이터는 Redis ZSet에 최대 1시간 보관 후 자동 정리된다.

3.2 신뢰성

  • 알림 발행 실패 시 재시도하지 않는다. 로그를 남기고 중복 방지 락만 해제해, 다음 트리거에서 다시 발행될 수 있게 한다.
  • 센서 수신 큐에는 DLQ를 구성한다.
  • 플로우 실행 오류는 격리되어 한 플로우의 실패가 다른 플로우 실행에 영향을 주지 않는다.

3.3 확장성

  • 노드 타입 추가가 용이한 구조 (실행기 레지스트리 기반)