> For the complete documentation index, see [llms.txt](https://kopens.gitbook.io/plantpulse-platform/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kopens.gitbook.io/plantpulse-platform/developer/api-manual/tag-service.md).

# 8. Tag 서비스

`client.tag()` 으로 접근합니다. Tag는 데이터 포인트(센서 값, 카운터, 상태)의 **정의(메타데이터)** 입니다. V5에서는 **탭별 PATCH 10종**을 통해 알람·집계·계산 등 세부 설정을 안전하게 부분 수정할 수 있습니다.

> **ID 규칙**: `TAG_` 접두사 필수. 자세한 내용은 [도메인 ID 규칙](/plantpulse-platform/developer/api-manual/id-rules.md#25-tag-id) 참고.

## 8.1 메서드 일람

### CRUD

| 메서드                            | 반환 타입                     | HTTP   | 엔드포인트                     |
| ------------------------------ | ------------------------- | ------ | ------------------------- |
| `create(TagRequestV5)`         | `TagResponseV5` 또는 `null` | POST   | `/api/v5/tag`             |
| `update(tag_id, TagRequestV5)` | `TagResponseV5` 또는 `null` | PUT    | `/api/v5/tag/{id}`        |
| `delete(tag_id)`               | `boolean`                 | DELETE | `/api/v5/tag/{id}`        |
| `get(tag_id)`                  | `TagResponseV5` 또는 `null` | GET    | `/api/v5/tag/{id}`        |
| `exists(tag_id)`               | `boolean`                 | GET    | `/api/v5/tag/{id}/exists` |

### 목록 / 카운트

| 메서드                      | 반환 타입                 | HTTP | 엔드포인트                            |
| ------------------------ | --------------------- | ---- | -------------------------------- |
| `list()`                 | `List<TagResponseV5>` | GET  | `/api/v5/tag`                    |
| `listBySite(site_id)`    | `List<TagResponseV5>` | GET  | `/api/v5/tag?site_id=...`        |
| `listByOpc(opc_id)`      | `List<TagResponseV5>` | GET  | `/api/v5/tag?opc_id=...`         |
| `listByAsset(asset_id)`  | `List<TagResponseV5>` | GET  | `/api/v5/tag?asset_id=...`       |
| `count()`                | `long`                | GET  | `/api/v5/tag/count`              |
| `countBySite(site_id)`   | `long`                | GET  | `/api/v5/tag/count?site_id=...`  |
| `countByOpc(opc_id)`     | `long`                | GET  | `/api/v5/tag/count?opc_id=...`   |
| `countByAsset(asset_id)` | `long`                | GET  | `/api/v5/tag/count?asset_id=...` |

### PATCH — 탭별 부분 수정 (V5 핵심 기능)

10종의 PATCH는 **null 필드 = 변경 안 함** 규칙을 따릅니다 (서버 DAO에서 `COALESCE` 처리). 일부 PATCH는 서버에서 CEP/EQL 재배포까지 자동 수행합니다.

| 메서드                                                  | HTTP  | 엔드포인트                          | 부수 효과                   |
| ---------------------------------------------------- | ----- | ------------------------------ | ----------------------- |
| `patchBasic(id, TagBasicPatchRequestV5)`             | PATCH | `/api/v5/tag/{id}/basic`       | —                       |
| `patchAlarm(id, TagAlarmPatchRequestV5)`             | PATCH | `/api/v5/tag/{id}/alarm`       | CEP/EQL 재배포             |
| `patchMetadata(id, TagMetadataPatchRequestV5)`       | PATCH | `/api/v5/tag/{id}/metadata`    | —                       |
| `patchCalculation(id, TagCalculationPatchRequestV5)` | PATCH | `/api/v5/tag/{id}/calculation` | `deployCalculation` 재호출 |
| `patchSampling(id, TagSamplingPatchRequestV5)`       | PATCH | `/api/v5/tag/{id}/sampling`    | —                       |
| `patchAggregation(id, TagAggregationPatchRequestV5)` | PATCH | `/api/v5/tag/{id}/aggregation` | `deployAggregation` 재호출 |
| `patchAi(id, TagAiPatchRequestV5)`                   | PATCH | `/api/v5/tag/{id}/ai`          | —                       |
| `patchPublish(id, TagPublishPatchRequestV5)`         | PATCH | `/api/v5/tag/{id}/publish`     | —                       |
| `patchAttribute(id, TagAttributePatchRequestV5)`     | PATCH | `/api/v5/tag/{id}/attribute`   | —                       |
| `patchLink(id, TagLinkPatchRequestV5)`               | PATCH | `/api/v5/tag/{id}/link`        | —                       |

## 8.2 TagRequestV5 / TagResponseV5 (전체 등록·수정용)

| 필드                | 타입     | 설명                                                                             |
| ----------------- | ------ | ------------------------------------------------------------------------------ |
| `tag_id`          | String | 태그 ID (PK, `TAG_` 필수)                                                          |
| `tag_name`        | String | 표시명                                                                            |
| `opc_id`          | String | 소속 OPC (FK)                                                                    |
| `site_id`         | String | 소속 사이트                                                                         |
| `linked_asset_id` | String | 연결된 자산(Equipment)                                                              |
| `java_type`       | String | 값 자료형 — `Double`, `Float`, `Int`, `Long`, `Short`, `Boolean`, `String`, `Date` |
| `unit`            | String | 단위 (예: `℃`, `RPM`, `kPa`)                                                      |
| `tag_source`      | String | 데이터 출처 (예: `OPC`, `API`, `FILE`)                                               |
| `description`     | String | 설명                                                                             |

## 8.3 PATCH DTO 필드 (탭별)

### TagBasicPatchRequestV5 (기본)

| 필드            | 설명  |
| ------------- | --- |
| `tag_name`    | 표시명 |
| `java_type`   | 자료형 |
| `description` | 설명  |

### TagMetadataPatchRequestV5 (메타데이터)

| 필드                               | 설명                   |
| -------------------------------- | -------------------- |
| `tag_type`                       | 태그 유형                |
| `importance`                     | 중요도 (1\~10)          |
| `tag_source`                     | 출처                   |
| `use_metric`                     | 메트릭 사용 여부            |
| `rate`                           | 수집 주기 (ms)           |
| `rw`                             | 읽기/쓰기 (`R`/`W`/`RW`) |
| `alias_name`                     | 별칭                   |
| `min_value` / `max_value`        | 측정 범위                |
| `display_format`                 | UI 표시 형식             |
| `unit`                           | 단위                   |
| `number_round` / `number_scale`  | 반올림 / 소수점            |
| `io_address` / `source_tag_name` | I/O 주소·원본 태그명        |
| `lat` / `lng`                    | 위경도                  |

### TagAlarmPatchRequestV5 (알람)

| 필드                                                        | 설명              |
| --------------------------------------------------------- | --------------- |
| `trip_hi`, `hi_hi`, `hi`, `lo`, `lo_lo`, `trip_lo`        | 임계치 (6단계)       |
| `bool_true`, `bool_true_priority`, `bool_true_message`    | 불린 TRUE 알람      |
| `bool_false`, `bool_false_priority`, `bool_false_message` | 불린 FALSE 알람     |
| `band_message`                                            | 정상 밴드 메시지       |
| `duplicate_check_minutes`                                 | 중복 알람 차단 분      |
| `user_defined_alarm_class`                                | 사용자 정의 클래스      |
| `use_alarm`                                               | 알람 사용 (`Y`/`N`) |
| `recieve_me`, `recieve_others`                            | 본인/타인 수신        |
| `send_email`, `send_sms`                                  | 이메일/SMS 발송      |

### TagCalculationPatchRequestV5 (계산)

| 필드                | 설명              |
| ----------------- | --------------- |
| `calculation_eql` | EQL 표현식         |
| `use_calculation` | 사용 여부 (`Y`/`N`) |

### TagSamplingPatchRequestV5 (샘플링)

| 필드             | 설명              |
| -------------- | --------------- |
| `use_sampling` | 사용 여부 (`Y`/`N`) |

### TagAggregationPatchRequestV5 (집계)

| 필드                                               | 설명             |
| ------------------------------------------------ | -------------- |
| `use_aggregation`                                | 사용 여부          |
| `aggregation_1_minutes` \~ `aggregation_1_hours` | 5가지 주기 활성화 플래그 |

### TagAiPatchRequestV5 (AI 이상 진단)

| 필드             | 설명         |
| -------------- | ---------- |
| `use_target`   | 학습 대상      |
| `use_category` | 카테고리 분류 사용 |

### TagPublishPatchRequestV5 (발행)

| 필드              | 설명                 |
| --------------- | ------------------ |
| `publish_mqtt`  | MQTT 발행 (`Y`/`N`)  |
| `publish_kafka` | Kafka 발행 (`Y`/`N`) |

### TagAttributePatchRequestV5 (노트)

| 필드     | 설명       |
| ------ | -------- |
| `note` | 자유 형식 메모 |

### TagLinkPatchRequestV5 (설비 매핑)

| 필드                | 설명                      |
| ----------------- | ----------------------- |
| `linked_asset_id` | 연결 자산 ID. 빈 문자열 = 매핑 해제 |

## 8.4 사용 예시

### Tag 생성 (OPC 연결 태그)

```java
import plantpulse.api.v5.dto.request.TagRequestV5;
import plantpulse.api.v5.dto.response.TagResponseV5;

TagRequestV5 req = new TagRequestV5();
req.setTag_id("TAG_EDGE_00303_90007");
req.setTag_name("Spindle RPM");
req.setOpc_id("OPC_EDGE_00303");
req.setSite_id("SITE_DJ");
req.setLinked_asset_id("ASSET_DJ_M_0001");
req.setJava_type("Double");
req.setUnit("RPM");
req.setTag_source("OPC");
req.setDescription("Spindle 회전수");

TagResponseV5 created = client.tag().create(req);
```

### 단건 조회 / 존재 확인

```java
TagResponseV5 tag = client.tag().get("TAG_EDGE_00303_90007");
if (tag != null) {
    System.out.println(tag.getTag_name() + " (" + tag.getUnit() + ")");
}

boolean exists = client.tag().exists("TAG_EDGE_00303_90007");
```

### 사이트 / OPC / 에셋별 목록

```java
List<TagResponseV5> siteTags  = client.tag().listBySite("SITE_DJ");
List<TagResponseV5> opcTags   = client.tag().listByOpc("OPC_PLC_L1_001");
List<TagResponseV5> assetTags = client.tag().listByAsset("ASSET_DJ_M_0001");
```

### 카운트

```java
long total       = client.tag().count();
long siteTotal   = client.tag().countBySite("SITE_DJ");
long opcTotal    = client.tag().countByOpc("OPC_PLC_L1_001");
long assetTotal  = client.tag().countByAsset("ASSET_DJ_M_0001");
```

### 전체 수정 (PUT)

전체 필드를 다시 보낼 때:

```java
TagRequestV5 update = new TagRequestV5();
update.setTag_id("TAG_EDGE_00303_90007");
update.setTag_name("Spindle RPM (변경됨)");
update.setOpc_id("OPC_EDGE_00303");
update.setSite_id("SITE_DJ");
update.setJava_type("Double");
update.setUnit("RPM");
// ... 모든 필드 ...
client.tag().update("TAG_EDGE_00303_90007", update);
```

### 부분 수정 — patchBasic

이름과 설명만 변경:

```java
import plantpulse.api.v5.dto.request.TagBasicPatchRequestV5;

TagBasicPatchRequestV5 patch = new TagBasicPatchRequestV5();
patch.setTag_name("Spindle RPM (보정 후)");
patch.setDescription("2026-05-14 보정 적용");
// java_type 은 null 로 두면 변경 안 함
client.tag().patchBasic("TAG_EDGE_00303_90007", patch);
```

### 부분 수정 — patchAlarm

알람 임계치 설정 (서버에서 CEP/EQL 재배포):

```java
import plantpulse.api.v5.dto.request.TagAlarmPatchRequestV5;

TagAlarmPatchRequestV5 alarm = new TagAlarmPatchRequestV5();
alarm.setUse_alarm("Y");
alarm.setLo_lo("0");
alarm.setLo("10");
alarm.setHi("80");
alarm.setHi_hi("95");
alarm.setTrip_hi("100");
alarm.setDuplicate_check_minutes(5);
alarm.setSend_email("Y");
client.tag().patchAlarm("TAG_EDGE_00303_90007", alarm);
```

### 부분 수정 — patchMetadata

별칭과 표시 형식 변경:

```java
import plantpulse.api.v5.dto.request.TagMetadataPatchRequestV5;

TagMetadataPatchRequestV5 meta = new TagMetadataPatchRequestV5();
meta.setAlias_name("HMI_TAG_RPM_01");
meta.setDisplay_format("#,##0");
meta.setNumber_scale(0);
meta.setImportance(8);
client.tag().patchMetadata("TAG_EDGE_00303_90007", meta);
```

### 부분 수정 — patchCalculation

EQL 계산식 부착 (서버에서 deployCalculation 재호출):

```java
import plantpulse.api.v5.dto.request.TagCalculationPatchRequestV5;

TagCalculationPatchRequestV5 calc = new TagCalculationPatchRequestV5();
calc.setUse_calculation("Y");
calc.setCalculation_eql("VAL('TAG_RAW_RPM') * 60 / 1000");   // 가상의 EQL
client.tag().patchCalculation("TAG_EDGE_00303_90007", calc);
```

### 부분 수정 — patchAggregation

5가지 주기 집계 활성화 (deployAggregation 재호출):

```java
import plantpulse.api.v5.dto.request.TagAggregationPatchRequestV5;

TagAggregationPatchRequestV5 agg = new TagAggregationPatchRequestV5();
agg.setUse_aggregation("Y");
agg.setAggregation_1_minutes("Y");
agg.setAggregation_5_minutes("Y");
agg.setAggregation_10_minutes("Y");
agg.setAggregation_30_minutes("N");
agg.setAggregation_1_hours("Y");
client.tag().patchAggregation("TAG_EDGE_00303_90007", agg);
```

### 부분 수정 — patchPublish

MQTT/Kafka 발행 토글:

```java
import plantpulse.api.v5.dto.request.TagPublishPatchRequestV5;

TagPublishPatchRequestV5 pub = new TagPublishPatchRequestV5();
pub.setPublish_mqtt("Y");
pub.setPublish_kafka("N");
client.tag().patchPublish("TAG_EDGE_00303_90007", pub);
```

### 부분 수정 — patchLink (자산 매핑)

```java
import plantpulse.api.v5.dto.request.TagLinkPatchRequestV5;

// 자산에 연결
TagLinkPatchRequestV5 link = new TagLinkPatchRequestV5();
link.setLinked_asset_id("ASSET_DJ_M_0001");
client.tag().patchLink("TAG_EDGE_00303_90007", link);

// 매핑 해제 — 빈 문자열
TagLinkPatchRequestV5 unlink = new TagLinkPatchRequestV5();
unlink.setLinked_asset_id("");
client.tag().patchLink("TAG_EDGE_00303_90007", unlink);
```

### 삭제

```java
boolean ok = client.tag().delete("TAG_EDGE_00303_90007");
```

## 8.5 활용 시나리오

### 시나리오 — 신규 라인 태그 자동 분류 후 일괄 설정

```java
// 1) 자동 등록된 태그 목록 (OPC 연결 직후)
List<TagResponseV5> tags = client.tag().listByOpc("OPC_PLC_L2_001");

// 2) 이름 패턴으로 자산 자동 연결 + 알람 일괄 설정
for (TagResponseV5 t : tags) {
    String name = t.getTag_name();

    // 자산 매핑
    TagLinkPatchRequestV5 link = new TagLinkPatchRequestV5();
    if (name.contains("CNC1")) {
        link.setLinked_asset_id("ASSET_DJ_M_CNC1");
    } else if (name.contains("CNC2")) {
        link.setLinked_asset_id("ASSET_DJ_M_CNC2");
    } else {
        continue;
    }
    client.tag().patchLink(t.getTag_id(), link);

    // 온도 태그는 알람 임계치 자동 설정
    if (name.endsWith("_TEMP")) {
        TagAlarmPatchRequestV5 alarm = new TagAlarmPatchRequestV5();
        alarm.setUse_alarm("Y");
        alarm.setHi("80");
        alarm.setHi_hi("95");
        client.tag().patchAlarm(t.getTag_id(), alarm);
    }
}
```

### 시나리오 — 집계와 발행을 한꺼번에 활성화

```java
String tagId = "TAG_EDGE_00303_90007";

TagAggregationPatchRequestV5 agg = new TagAggregationPatchRequestV5();
agg.setUse_aggregation("Y");
agg.setAggregation_1_minutes("Y");
agg.setAggregation_1_hours("Y");
client.tag().patchAggregation(tagId, agg);

TagPublishPatchRequestV5 pub = new TagPublishPatchRequestV5();
pub.setPublish_mqtt("Y");
client.tag().patchPublish(tagId, pub);
```

## 다음 단계

* [Alarm 서비스](/plantpulse-platform/developer/api-manual/alarm-service.md) — 알람 이벤트 조회
* [Path 서비스](/plantpulse-platform/developer/api-manual/path-service.md) — 태그의 자산 경로
