# 실시간 태그 확장 설계안

## 1. 배경

현재 ExperionCrawler는 아날로그 태그의 `.pv`, `.sp`, `.op`, `.qv.value`만 `realtime_table`에 저장하고 있음.
디지털 장비(Pump, XV)의 상태 정보와 모든 태그의 `.desc`, `.area` 메타데이터를 추가하고자 함.

## 2. 현재 시스템 아키텍처

```
Experion HS R530 OPC Server
        ↓ (1. 크롤링 - 전체 노드 스캔)
   CSV 파일 저장
        ↓ (2. CSV 로드)
  node_map_master (530,080 행)
        ↓ (3. UI에서 태그+속성 선택 - 최대 8개)
  realtime_table (등록된 태그만)
        ↓ (4. OPC UA 구독)
  livevalue 실시간 업데이트
        ↓ (5. 히스토리 저장)
  history_table
```

### node_map_master 구조 특징
- `name`: 속성명만 (`pv`, `sp`, `desc`, `area`, `instate0` 등)
- `node_id`: 전체 경로 (`ns=1;s=sinamserver:xv-6124.pv`)
- 상위 Object (`xv-6124`)와 하위 속성 (`pv`)이 별도 행으로 존재

## 3. 추가할 태그

### 3.1 아날로그 태그 (기존 확장)
| 태그 | 데이터 타입 | 설명 |
|------|------------|------|
| `ficq-6101.area` | Enum(i=7594) | 소속 플랜트/Asset |

> 참고: ficq-6101은 `.desc` 속성이 없음 (DB 확인 결과)

### 3.2 디지털 태그 (신규 추가) (0~7까지 모두 추가)
| 태그 | 데이터 타입 | 설명 |
|------|------------|------|
| `xv-6124.pv` | Int32 (BCD 조합값) | 프로세스 값 |
| `xv-6124.op` | Int32 | 출력값 |
| `xv-6124.desc` | String | 장비 설명 |
| `xv-6124.area` | Enum(i=7594) | 소속 플랜트/Asset |
| `xv-6124.instate0` | Boolean | 상태 비트 0 (현재 값) |
| `xv-6124.instate1` | Boolean | 상태 비트 1 (현재 값) |
| `xv-6124.instate2` | Boolean | 상태 비트 2 (현재 값) |
| `xv-6124.state0descriptor` | String | 비트 0 의미 (예: "Run/Stop") |
| `xv-6124.state1descriptor` | String | 비트 1 의미 (예: "Remote/Local") |
| `xv-6124.state2descriptor` | String | 비트 2 의미 (예: "Trip/Normal") |

> **핵심 발견:** Experion HS에 `state0descriptor`~`state7descriptor`가 이미 존재합니다.
> 이는 사용자가 정의한 BCD 상태 의미를 String으로 저장한 태그로,
> OPC UA에서 구독하면 `realtime_table`에 저장 가능하므로 **별도 테이블 불필요**.

### 3.3 BCD 상태값 해석

`pv`는 HC900 컨트롤러에서 Digital Input을 BCD로 조합하여 32bit Float로 전송.
**직접 `pv` 값을 파싱하지 않고 `instate0~7` Boolean 태그를 사용.**

| 사용 비트 | 현재 프로젝트 예시 (Pump) | 현재 프로젝트 예시 (Valve) |
|-----------|---------------------------|----------------------------|
| instate0 | Run(1)/Stop(0) | Open(1)/Close(0) |
| instate0+1 | Run/Stop + R/L | Open/Close + R/L |
| instate0+1+2 | Run/Stop + R/L + Trip/Normal | Open/Close + R/L + Fault/Normal |

> **중요**: 위 값은 현재 프로젝트에서만 알려진 사용자 정의 값입니다.
> 다른 프로젝트에서는 BCD 상태 의미가 다를 수 있으므로 정형화 불가능합니다.
> 각 장비의 실제 비트 사용 수와 의미는Experion HS에서 사용자 정의됩니다.

## 4. 설계 결정

### 4.1 DB 스키마 변경: **tag_metadata 테이블 추가**

메타데이터(desc, area, state0descriptor~7)는 실시간으로 자주 변경되지 않으므로,
별도 테이블에 저장하고 OPC UA 통신 부담을 줄입니다.

```sql
CREATE TABLE tag_metadata (
  id SERIAL PRIMARY KEY,
  base_tag TEXT NOT NULL,              -- ficq-6101, xv-6124
  attribute TEXT NOT NULL,             -- desc, area, state0descriptor, ...
  value TEXT,                          -- 실제 값
  node_id TEXT,                        -- OPC UA node_id (재로드용)
  loaded_at TIMESTAMP DEFAULT NOW(),   -- 마지막 로드 시간
  UNIQUE(base_tag, attribute)
);

CREATE INDEX idx_tag_metadata_base ON tag_metadata(base_tag);
```

**데이터 분리 전략:**

| 테이블 | 저장 내용 | OPC UA 구독 |
|--------|----------|-------------|
| `realtime_table` | pv, sp, op, instate0~7 등 **실시간 데이터** | ✅ 지속 구독 |
| `tag_metadata` | desc, area, state0descriptor~7 등 **메타데이터** | ❌ 한 번 로드 |

**장점:**
- OPC UA 통신 부담 대폭 감소 (메타데이터는 한 번만 읽음)
- 수천 개 태그에 대해 desc/area를 실시간 구독하지 않음
- UI에서 "재로드" 버튼으로 필요시 갱신 가능

### 4.2 메타데이터 로드/재로드 시나리오

**초기 로드:**
1. UI에서 태그 선택 후 등록 시, 실시간 태그(pv, sp, op, instate0~7)는 `realtime_table`에 등록
2. 동시에 메타데이터(desc, area, state0descriptor~7)는 OPC UA에서 **한 번 읽어서** `tag_metadata` 테이블 저장
3. 읽은 메타데이터 정보로 `node_map_master`도 동시 갱신

**재로드 (UI 버튼):**
1. UI에서 "메타데이터 재로드" 버튼 클릭
2. Backend가 OPC UA 서버에 직접 연결
3. 선택된 태그(또는 전체 등록 태그)의 메타데이터 재조회
4. `tag_metadata` 테이블 UPDATE + `node_map_master` 갱신

```
UI 재로드 버튼
    ↓
Backend API: POST /api/tags/metadata/reload
    ↓
OPC UA Read (desc, area, state0descriptor~7)
    ↓
tag_metadata UPDATE
node_map_master UPDATE (UPSERT)
    ↓
Response: 갱신된 태그 수
```

### 4.3 SQL 뷰 추가

`realtime_table` + `tag_metadata`를 JOIN하여 태그별 속성을 한눈에 보기 위한 뷰:

```sql
CREATE OR REPLACE VIEW v_tag_summary AS
SELECT
  rt_base.base_tag,
  pv_rt.livevalue AS pv,
  sp_rt.livevalue AS sp,
  op_rt.livevalue AS op,
  instate0_rt.livevalue AS instate0,
  instate1_rt.livevalue AS instate1,
  instate2_rt.livevalue AS instate2,
  desc_md.value AS description,
  area_md.value AS area,
  s0d_md.value AS state0_descriptor,
  s1d_md.value AS state1_descriptor,
  s2d_md.value AS state2_descriptor
FROM (SELECT DISTINCT split_part(tagname, '.', 1) AS base_tag FROM realtime_table) rt_base
LEFT JOIN realtime_table pv_rt ON pv_rt.tagname = rt_base.base_tag || '.pv'
LEFT JOIN realtime_table sp_rt ON sp_rt.tagname = rt_base.base_tag || '.sp'
LEFT JOIN realtime_table op_rt ON op_rt.tagname = rt_base.base_tag || '.op'
LEFT JOIN realtime_table instate0_rt ON instate0_rt.tagname = rt_base.base_tag || '.instate0'
LEFT JOIN realtime_table instate1_rt ON instate1_rt.tagname = rt_base.base_tag || '.instate1'
LEFT JOIN realtime_table instate2_rt ON instate2_rt.tagname = rt_base.base_tag || '.instate2'
LEFT JOIN tag_metadata desc_md ON desc_md.base_tag = rt_base.base_tag AND desc_md.attribute = 'desc'
LEFT JOIN tag_metadata area_md ON area_md.base_tag = rt_base.base_tag AND area_md.attribute = 'area'
LEFT JOIN tag_metadata s0d_md ON s0d_md.base_tag = rt_base.base_tag AND s0d_md.attribute = 'state0descriptor'
LEFT JOIN tag_metadata s1d_md ON s1d_md.base_tag = rt_base.base_tag AND s1d_md.attribute = 'state1descriptor'
LEFT JOIN tag_metadata s2d_md ON s2d_md.base_tag = rt_base.base_tag AND s2d_md.attribute = 'state2descriptor';
```

### 4.4 UI 변경

| 항목 | 현재 | 변경 |
|------|------|------|
| 최대 선택 태그 수 | 8개 | 10개 |
| 태그 검색 | name 기준 | name + node_id 기준 |
| 메타데이터 재로드 | 없음 | "메타데이터 재로드" 버튼 추가 |
| 속성 미리보기 | 없음 | 선택 시 하위 속성 표시 (선택사항) |

## 5. 변경 사항 요약

### 5.1 Database
- **신규 테이블**: `tag_metadata` (base_tag, attribute, value, node_id, loaded_at)
- **신규 뷰**: `v_tag_summary` (realtime_table + tag_metadata JOIN)

### 5.2 Backend (`src/Infrastructure/OpcUa/`)
- **신규 서비스**: `MetadataLoaderService`
  - `LoadMetadataAsync(base_tags)` : OPC UA에서 desc, area, state0descriptor~7 읽어서 `tag_metadata` 저장
  - `ReloadMetadataAsync(base_tags)` : 재로드 시 OPC UA 재조회 + `tag_metadata` UPDATE + `node_map_master` UPSERT
- **신규 API**: `POST /api/tags/metadata/reload`

### 5.3 Frontend (`src/Web/wwwroot/js/app.js`)
- 태그 선택 최대 수 8 → 10개로 변경
- "메타데이터 재로드" 버튼 추가
- (선택사항) 상위 Object 선택 시 하위 속성 자동 표시

### 5.4 Entity/DbContext
- **신규 Entity**: `TagMetadata` class
- **DbContext**: `DbSet<TagMetadata>` 추가, `OnModelCreating` 설정 추가

### 5.5 사용자 작업
- UI에서 새로운 태그(Pump, XV)와 속성(pv, op, instate0~2) 선택하여 등록
- 메타데이터(desc, area, state descriptor)는 자동 로드
- 필요시 "메타데이터 재로드" 버튼으로 갱신

## 6. 대규모 리팩토링이 필요한 시나리오 (향후 고려사항)

현재 설계안은 기존 `realtime_table` 구조를 유지하므로 저위험입니다.
하지만 아래 기능들을 추가하려면 **DB 스키마 변경 + 코드 리팩토링**이 필요합니다.

### 6.1 자동 속성 제안 기능

**문제:** 현재 UI에서 각 태그의 속성(pv, sp, op, desc, area, instate0~2)을 수동으로 선택해야 함.
Pump/XV 같은 디지털 장비는 7개 이상의 속성을 선택해야 하므로 번거로움.

**해결 방안:**
- 상위 Object (예: `xv-6124`) 선택 시, node_map_master에서 하위 속성을 자동으로 조회하여 제안
- 장비 타입에 따라 기본 속성 조합 제안:
  - 아날로그 (ficq-6101): `.pv`, `.sp`, `.op`, `.area`
  - 디지털 XV (xv-6124): `.pv`, `.op`, `.desc`, `.area`, `.instate0`, `.instate1`, `.instate2`
  - Pump (p-6102): `.pv`, `.op`, `.desc`, `.area`, `.instate0`, `.instate1`, `.instate2`

**변경 범위:**
- Frontend: 상위 Object 선택 시 하위 속성 자동 로딩 UI
- Backend: `/api/nodemap/children?parent=xv-6124` API 추가
- node_map_master에서 `node_id LIKE '%xv-6124.%'`로 하위 속성 조회

**리팩토링 위험:** 낮음 (기존 API 추가만 필요)

### 6.2 tag_registry 테이블 도입

**문제:** BCD 상태 의미(instate0=Run/Stop, instate1=R/L 등)는 사용자 정의이므로
시스템에서 자동으로 해석할 수 없음. Text-to-SQL에서 "pump-6102 상태 알려줘" 같은
자연어 질문에 의미 있는 답변을 제공하려면 상태 의미 정보가 필요함.

**해결 방안:**
```sql
CREATE TABLE tag_registry (
  id SERIAL PRIMARY KEY,
  base_tag TEXT NOT NULL UNIQUE,           -- xv-6124, p-6102
  equipment_type TEXT,                      -- pump, xv, ai, ao, fi, ti
  bit_count INT DEFAULT 1,                  -- 사용하는 instate 비트 수 (1~3)
  state0_meaning TEXT,                      -- Run/Stop, Open/Close
  state1_meaning TEXT,                      -- Remote/Local
  state2_meaning TEXT,                      -- Trip/Normal, Fault/Normal
  area TEXT,                                -- 소속 플랜트/Asset
  description TEXT,                         -- 장비 설명
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);
```

**활용 시나리오:**
- BCD 상태 의미 저장: 사용자가 UI에서 상태 의미 정의 → DB 저장
- 자동 속성 제안: `equipment_type`에 따라 기본 속성 조합 제안
- Text-to-SQL: "pump-6102 현재 상태" → instate0~2를 Boolean으로 읽어서 상태 의미와 매핑하여 "Run, Remote, Normal" 표시
- P&ID 매핑: P&ID에서 추출한 장비와 Experion 태그를 `tag_registry`를 통해 연결

**리팩토링 위험:** 중간 (새 테이블 + Entity + Service 추가)

### 6.3 장비 타입별 다른 처리 로직

**문제:** 현재 `realtime_table`은 모든 태그를 동일하게 처리.
하지만 장비 타입에 따라 다른 처리가 필요할 수 있음:
- 아날로그: pv/sp/op를 숫자로 표시, 단위 표시
- 디지털 XV: instate0~2를 Boolean으로 읽어서 "Open/Close", "R/L"로 표시
- Pump: instate0~2를 Boolean으로 읽어서 "Run/Stop", "R/L", "Trip/Normal"로 표시
- 알람: alarmflags, alarmvalue를 파싱해서 알람 상태 표시

**해결 방안:**
- `tag_registry.equipment_type`에 따라 UI에서 다른 컴포넌트 렌더링
- Backend에서 장비 타입별 상태 해석 서비스 추가
- BCD 상태값을 Boolean 배열로 파싱하는 유틸리티 함수

**변경 범위:**
- Frontend: 장비 타입별 상태 표시 컴포넌트
- Backend: `EquipmentStateService` 추가 (BCD → Boolean 배열 → 상태 문자열)
- `tag_registry` 테이블과 연동

**리팩토링 위험:** 높음 (Frontend 컴포넌트 + Backend 서비스 + DB 연동)

### 6.4 desc/area 별도 테이블

**문제:** desc/area는 자주 변경되지 않지만, 현재는 `realtime_table`에 실시간 데이터로 저장.
수천 개의 태그에 대해 desc/area를 OPC UA에서 계속 구독하면 불필요한 트래픽 발생.

**해결 방안:**
```sql
CREATE TABLE tag_metadata (
  tagname TEXT PRIMARY KEY,        -- ficq-6101.area, xv-6124.desc
  value TEXT NOT NULL,
  updated_at TIMESTAMP DEFAULT NOW()
);
```
- 초기 로드 시 OPC UA에서 desc/area 한 번 읽어서 저장
- 변경 감지: 주기적 폴링 또는 이벤트 기반 업데이트
- UI 조회 시 `tag_metadata`에서 읽되, 변경 의심 시 OPC UA에서 재조회

**리팩토링 위험:** 중간 (새 테이블 + 폴링 서비스 추가)

## 7. 권장 진행 순서

### Phase 1: 기본 확장 (현재 설계안)
1. **UI 변경**: 태그 선택 최대 수 8 → 10개
2. **테스트**: xv-6124의 pv, op, desc, area, instate0~2 등록 및 OPC UA 구독 확인
3. **SQL 뷰**: `v_tag_summary` 생성 (선택사항)

### Phase 2: 자동화 (향후)
4. **자동 속성 제안**: 상위 Object 선택 시 하위 속성 자동 제안
5. **tag_registry 테이블**: BCD 상태 의미 저장, 장비 타입 관리

### Phase 3: 지능형 처리 (장기)
6. **장비 타입별 처리**: BCD 상태 해석, UI 컴포넌트별 렌더링
7. **desc/area 최적화**: 별도 테이블 + 변경 감지 폴링
8. **Text-to-SQL 연동**: 자연어 질문 → BCD 상태 해석 → 의미 있는 답변

## 8. NL2SQL 변경 사항

현재 NL2SQL worker(`mcp-server/worker/nl2sql_worker.py`)는 `history_table`과 `realtime_table`만 인식합니다.
새로운 테이블과 뷰, 태그 타입을 인식하도록 `DB_SCHEMA`를 업데이트해야 합니다.

### 8.1 DB_SCHEMA 업데이트 필요 항목

**추가할 테이블 정의:**
```
테이블: tag_metadata  (태그 메타데이터 - 변경 드묾)
  base_tag    TEXT         - 기본 태그명 (예: 'ficq-6101', 'xv-6124')
  attribute   TEXT         - 속성명 ('desc', 'area', 'state0descriptor', ...)
  value       TEXT         - 메타데이터 값
  node_id     TEXT         - OPC UA 노드 ID
  loaded_at   TIMESTAMPTZ  - 마지막 로드 시각

뷰: v_tag_summary  (실시간 + 메타데이터 통합)
  base_tag          TEXT   - 기본 태그명
  pv                TEXT   - 현재 프로세스 값
  sp                TEXT   - 설정값
  op                TEXT   - 출력값
  instate0          TEXT   - 상태 비트 0 (true/false)
  instate1          TEXT   - 상태 비트 1 (true/false)
  instate2          TEXT   - 상태 비트 2 (true/false)
  description       TEXT   - 장비 설명 (tag_metadata.desc)
  area              TEXT   - 소속 플랜트 (tag_metadata.area)
  state0_descriptor TEXT   - 비트 0 의미 (예: "Run/Stop")
  state1_descriptor TEXT   - 비트 1 의미 (예: "Remote/Local")
  state2_descriptor TEXT   - 비트 2 의미 (예: "Trip/Normal")
```

### 8.2 NL2SQL 사용 예시 (새로운 시나리오)

| 자연어 질문 | 생성 SQL |
|------------|----------|
| "xv-6124의 현재 상태와 설명을 알려줘" | `SELECT instate0, instate1, state0_descriptor, state1_descriptor, description FROM v_tag_summary WHERE base_tag = 'xv-6124'` |
| "Unit-A에 있는 모든 pump의 상태를 보여줘" | `SELECT base_tag, instate0, state0_descriptor, description FROM v_tag_summary WHERE area = 'Unit-A' AND base_tag LIKE 'p-%'` |
| "ficq-6101의 현재 값과 설명은?" | `SELECT pv, description FROM v_tag_summary WHERE base_tag = 'ficq-6101'` |
| "모든 XV 중 instate0이 true인 것" | `SELECT base_tag, instate0, state0_descriptor FROM v_tag_summary WHERE instate0 = 'True' AND base_tag LIKE 'xv-%'` |
| "p-6102의 3개 상태 비트와 의미를 보여줘" | `SELECT instate0, instate1, instate2, state0_descriptor, state1_descriptor, state2_descriptor FROM v_tag_summary WHERE base_tag = 'p-6102'` |

### 8.3 변경 파일 목록

| 파일 | 변경 내용 |
|------|----------|
| `mcp-server/worker/nl2sql_worker.py` | `DB_SCHEMA`에 `tag_metadata`, `v_tag_summary` 추가 |
| `mcp-server/server.py` | `_DB_SCHEMA`에 동일하게 추가 (동기용) |

### 8.4 DB_SCHEMA 추가 내용 예시

```
테이블: tag_metadata  (태그 메타데이터 - 변경 드묾, OPC UA 폴링으로 갱신)
  base_tag    TEXT         - 기본 태그명 (예: 'ficq-6101', 'xv-6124')
  attribute   TEXT         - 속성명 ('desc', 'area', 'state0descriptor'~'state7descriptor')
  value       TEXT         - 메타데이터 값
  loaded_at   TIMESTAMPTZ  - 마지막 로드 시각

뷰: v_tag_summary  (실시간값 + 메타데이터 통합 뷰)
  base_tag, pv, sp, op, instate0~2, description, area, state0~2_descriptor

새로운 태그 타입:
  - 아날로그: ficq-6101.pv/sp/op (Double), ficq-6101.area
  - 디지털 XV: xv-6124.pv/op (Int32), xv-6124.instate0~7 (Boolean)
  - Pump: p-6102.pv/op (Int32), p-6102.instate0~7 (Boolean)
  - 메타데이터: desc (String), area (Enum), state0descriptor~7 (String)

BCD 상태 조회 팁:
  - instate0~7은 Boolean (true/false)
  - state0descriptor~7은 해당 비트의 의미 설명 (예: "Run/Stop")
  - instate0=true이고 state0descriptor="Run/Stop"이면 → "Run" 상태
  - v_tag_summary 뷰를 사용하면 실시간값+메타데이터 한 번에 조회 가능
```

## 9. Event & Alarm 테이블 (지능형 가동 상태 보고용)

### 9.1 필요성

"어제 18시부터 6차 플랜트의 가동상태 알려줘" 같은 지능형 보고를 하려면:
- 펌프/밸브 상태 변화 이력
- 알람 발생/해제 시점
- 비상정지(ESHUTDOWN) 발생/해제 시점
- 유량계 적산값(qv.value)으로 생산량 계산

이 정보들은 **실시간 값이 아닌 이벤트 이력**이므로 별도 테이블 필요.

### 9.2 테이블 구조

```sql
CREATE TABLE event_alarm_log (
  id BIGSERIAL PRIMARY KEY,
  base_tag TEXT NOT NULL,              -- xv-6124, p-6102
  event_type TEXT NOT NULL,            -- state_change, alarm, shutdown
  bit_index INT,                       -- instate0~7 중 어떤 비트 (state_change용)
  old_value TEXT,                      -- 이전 값
  new_value TEXT,                      -- 새 값
  state_descriptor TEXT,               -- state0descriptor 등 의미
  alarm_priority TEXT,                 -- Urgent/High/Low/Journal
  alarm_message TEXT,                  -- 알람 메시지
  occurred_at TIMESTAMPTZ NOT NULL,    -- 발생 시각
  acknowledged_at TIMESTAMPTZ,         -- 확인 시각
  source TEXT DEFAULT 'opcua'          -- opcua, manual
);

CREATE INDEX idx_eal_base_tag ON event_alarm_log(base_tag);
CREATE INDEX idx_eal_occurred ON event_alarm_log(occurred_at);
CREATE INDEX idx_eal_type ON event_alarm_log(event_type);
```

### 9.3 수집 방법

**방법 1: OPC UA Event Subscription (권장)**
- Experion HS의 OPC UA Event Mechanism 구독
- 알람 발생 시 실시간으로 이벤트 수신 → DB 저장

**방법 2: 폴링 기반 상태 변화 감지**
- instate0~7 값을 주기적 폴링
- 이전 값과 비교하여 변화 감지 → event_alarm_log INSERT
- alarmflags, alarmvalue 변화도 함께 감지

### 9.4 활용 시나리오

| 질문 | 필요한 데이터 |
|------|--------------|
| "p6 플랜트 가동상태 알려줘" | pump instate0 변화 이력 + shutdown 이벤트 |
| "00시에 왜 정지됐어?" | event_alarm_log WHERE event_type='shutdown' |
| "오늘 생산량?" | qv.value 적산 (history_table) |
| "xv-6124 알람 이력" | event_alarm_log WHERE base_tag='xv-6124' |

### 9.5 NL2SQL DB_SCHEMA 추가 내용

```
테이블: event_alarm_log  (이벤트/알람 이력)
  base_tag      TEXT         - 기본 태그명
  event_type    TEXT         - state_change, alarm, shutdown
  bit_index     INT          - instate 비트 인덱스 (0~7)
  old_value     TEXT         - 이전 값
  new_value     TEXT         - 새 값
  state_descriptor TEXT      - 상태 의미 (예: "Trip, Fault") 
  alarm_priority TEXT        - Urgent/High/Low/Journal
  occurred_at   TIMESTAMPTZ  - 발생 시각
  area                       - 그룹명 (플랜트 'p1~10' 에 그룹 알람 정보 찾기 쉬움)

예시: "오늘 p6 플랜트 알람 목록"
  SELECT base_tag, event_type, new_value, state_descriptor, alarm_priority, occurred_at
  FROM event_alarm_log
  WHERE base_tag IN (SELECT base_tag FROM tag_metadata WHERE attribute='area' AND value='p6')
    AND occurred_at >= date_trunc('day', NOW())
  ORDER BY occurred_at
```


##### future Plan 항목
이 디자인 플랜의 후순위

- 알람 관련 작업 :Experion HS 알람 구성 파악, 알람 테이블 긁어올 가능성 있는지 체크
- WebUI 도입관련 : 진정한 AX도입의 FINAL WORK가 될 것이며, 위의 모든 기능은 최종 AX화를 위한 걸 기본으로 설계되어야 한다.
