> 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/architecture.md).

# 아키텍처 개요

## 플랫폼 아키텍처

이 문서에서는 PlantPulse 플랫폼의 전체 아키텍처를 안내합니다. PlantPulse 플랫폼은 다수의 독립적인 서비스 모듈로 구성된 분산 아키텍처입니다. 각 모듈은 독립 프로세스로 실행되며, `plantpulse-startup` 스크립트에 의해 통합 관리됩니다.

처음 아키텍처를 살펴보시는 분이라면, 아래 다이어그램에서 각 레이어(계층)의 역할을 먼저 파악해 주시면 전체 구조를 이해하시기 쉽습니다. 데이터는 하단의 Storage/Messaging 계층에서 상단의 Application 계층으로 흐르는 구조입니다.

### 계층 다이어그램 (Mermaid)

```mermaid
graph TB
  USER[사용자 / 외부 시스템]

  subgraph APP["Application Layer"]
    SVR[plantpulse-server<br/>:80 · 콘솔/API/엔진]
    BAT[plantpulse-batch<br/>:9500]
    SQL[plantpulse-sql<br/>:4000]
    WH[plantpulse-warehouse<br/>:9600]
  end

  subgraph PROC["Processing Layer"]
    CEP[plantpulse-cep<br/>:7400 · Esper CEP]
    MON[plantpulse-monitor<br/>:4949]
    DG[plantpulse-data-gateway<br/>:5500]
  end

  subgraph COLL["Collection Layer"]
    PLUG[plantpulse-plugin<br/>:11004 OPC-UA · :8007 AAS]
  end

  subgraph MSG["Messaging Layer"]
    KAFKA[Kafka :9092]
    MQTT[MQTT :1883]
    STOMP[STOMP :61000]
  end

  subgraph STG["Storage Layer"]
    CASS[(Cassandra :9042)]
    PG[(PostgreSQL :5432)]
    VK[(Valkey :6379)]
    MN[(MinIO :9000)]
  end

  subgraph ANL["Analytics Layer"]
    SPARK[Spark :7077]
    KYUUBI[Kyuubi :10000]
    GRAV[Gravitino :19001]
    HIVE[Hive Metastore :9083]
    TSE[Time-Series Engine :7800]
    TSUI[Time-Series UI :3000]
  end

  subgraph WF["Workflow Layer"]
    TP[Temporal :7233 · UI :8233]
    KE[Kestra :8380]
  end

  USER --> SVR
  PLUG --> MQTT
  PLUG --> KAFKA
  MQTT --> KAFKA
  KAFKA --> SVR
  KAFKA --> CEP
  SVR --> PG
  SVR --> CASS
  SVR --> VK
  CEP --> KAFKA
  TSE --> CASS
  TSE --> VK
  SPARK --> CASS
  SPARK --> MN
  KYUUBI --> SPARK
  KYUUBI --> HIVE
  HIVE --> PG
  WH --> SPARK
  WH --> MN
  TP --> PG
  KE --> PG
  DG --> CASS
  DG --> VK
  MON --> SVR
```

```
┌─────────────────────────────────────────────────────────────────────┐
│                        사용자 / 웹 브라우저                              │
└───────────────────────────────┬─────────────────────────────────────┘
                                │ HTTP (7500) / WebSocket
┌───────────────────────────────▼─────────────────────────────────────┐
│                        APPLICATION LAYER                             │
│  ┌────────────────┐  ┌────────────┐  ┌──────────┐  ┌────────────┐  │
│  │ plantpulse-    │  │ plantpulse-│  │plantpulse│  │ plantpulse-│  │
│  │ server (:80)   │  │ batch      │  │-sql      │  │ warehouse  │  │
│  │ Web/API/Engine │  │ (:9500)    │  │ (:4000)  │  │ (:9600)    │  │
│  └────────────────┘  └────────────┘  └──────────┘  └────────────┘  │
├─────────────────────────────────────────────────────────────────────┤
│                        PROCESSING LAYER                              │
│  ┌────────────────┐  ┌────────────┐  ┌──────────────────────────┐  │
│  │ plantpulse-    │  │ plantpulse-│  │ plantpulse-data-gateway  │  │
│  │ cep (:7400)    │  │ monitor    │  │ (:5500)                  │  │
│  │ CEP/Esper      │  │ (:4949)    │  │ HTTP REST Gateway        │  │
│  └────────────────┘  └────────────┘  └──────────────────────────┘  │
├─────────────────────────────────────────────────────────────────────┤
│                        COLLECTION LAYER                              │
│  ┌────────────────────────────┐  ┌──────────────────────────────┐  │
│  │ plantpulse-agent (:60000)  │  │ plantpulse-plugin (:11004)   │  │
│  │ OPC/PLC/Modbus/DB/MQTT     │  │ OPC-UA Plugin                │  │
│  └────────────────────────────┘  └──────────────────────────────┘  │
├─────────────────────────────────────────────────────────────────────┤
│                        MESSAGING LAYER                               │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │ plantpulse-messaging                                         │   │
│  │  Kafka (:9092) │ MQTT (:1883) │ STOMP (:61000)              │   │
│  └──────────────────────────────────────────────────────────────┘   │
├─────────────────────────────────────────────────────────────────────┤
│                        STORAGE LAYER                                 │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │ plantpulse-storage                                           │   │
│  │  Cassandra (:9042) │ PostgreSQL (:5432) │ Valkey (:6379)    │   │
│  │  MinIO (:9000) │ JanusGraph │ RustFS │ WeedFS               │   │
│  └──────────────────────────────────────────────────────────────┘   │
├─────────────────────────────────────────────────────────────────────┤
│                        ANALYTICS LAYER                               │
│  ┌────────────────────────────────┐  ┌──────────────────────────┐  │
│  │ plantpulse-analytics           │  │ plantpulse-timeseries    │  │
│  │  Spark (:7077) │ Kyuubi (:10000) │  │ Engine (:7800) │ UI (:3000)│
│  │  Gravitino (:19001) │ Hadoop/Hive │  └──────────────────────────┘  │
│  └────────────────────────────────┘                                 │
├─────────────────────────────────────────────────────────────────────┤
│                        WORKFLOW LAYER                                 │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │ plantpulse-workflow                                          │   │
│  │  Kestra (:8233) │ Temporal (:8380)                          │   │
│  └──────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────┘
```

## Server 모듈 내부 아키텍처

`plantpulse-server`는 플랫폼의 핵심 모듈로, 웹 관리 콘솔과 IIoT 엔진을 포함하는 계층형 구조입니다. 아래에서 각 레이어의 역할을 확인하실 수 있습니다.

```
┌─────────────────────────────────────────────────────────┐
│                    웹 브라우저 / 모바일                      │
└──────────────────────┬──────────────────────────────────┘
                       │ HTTP / WebSocket
┌──────────────────────▼──────────────────────────────────┐
│                  Presentation Layer                      │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐  │
│  │ Security │ │   MVC    │ │   API    │ │ WebSocket │  │
│  │ Filters  │ │Controller│ │ V3 / V4  │ │   Push    │  │
│  └──────────┘ └──────────┘ └──────────┘ └───────────┘  │
├─────────────────────────────────────────────────────────┤
│                   Service Layer                          │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐  │
│  │  Alarm   │ │  Asset   │ │   Data   │ │ Dashboard │  │
│  │ Service  │ │ Service  │ │ Service  │ │  Service  │  │
│  └──────────┘ └──────────┘ └──────────┘ └───────────┘  │
├─────────────────────────────────────────────────────────┤
│                    Core Engine                           │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐  │
│  │ Pipeline │ │   CEP    │ │ Scheduler│ │   Cache   │  │
│  │ (36 thr) │ │ (Esper)  │ │ (Quartz) │ │ Manager   │  │
│  └──────────┘ └──────────┘ └──────────┘ └───────────┘  │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐  │
│  │Messaging │ │   DDS    │ │Monitoring│ │   OEE     │  │
│  │MQTT/Kafka│ │(EventBus)│ │ (JMX)    │ │Calculator │  │
│  └──────────┘ └──────────┘ └──────────┘ └───────────┘  │
├─────────────────────────────────────────────────────────┤
│                  Data Access Layer                       │
│  ┌──────────────────┐  ┌──────────────────────────────┐ │
│  │   PostgreSQL     │  │   Cassandra / ScyllaDB       │ │
│  │   (Metastore)    │  │   (TimeSeries)               │ │
│  │   32+ DAO        │  │   Select/Insert/Create DAO   │ │
│  └──────────────────┘  └──────────────────────────────┘ │
│  ┌──────────────────┐                                   │
│  │     Redis         │                                   │
│  │   (Write Buffer)  │                                   │
│  └──────────────────┘                                   │
└─────────────────────────────────────────────────────────┘
```

## 엔진 라이프사이클

PlantPulse 엔진은 Tomcat 기동 시 `EngineManager`를 통해 9단계 초기화 과정을 거칩니다. 각 단계가 순서대로 완료되어야 다음 단계로 진행되므로, 문제 발생 시 어느 단계에서 멈추었는지 확인하시면 원인을 파악하시기 쉽습니다.

```mermaid
flowchart LR
  S1[1 Context<br/>설정 로드] --> S2[2 Database<br/>PG/Cassandra 연결]
  S2 --> S3[3 Cache<br/>Site/Asset/Tag 캐시]
  S3 --> S4[4 Model<br/>메타 검증]
  S4 --> S5[5 Engine<br/>Pipeline/CEP/DDS]
  S5 --> S6[6 Messaging<br/>Kafka/MQTT Listener]
  S6 --> S7[7 Scheduler<br/>Quartz Job]
  S7 --> S8[8 Monitoring<br/>JMX/타이머]
  S8 --> S9[9 Plugin<br/>OEE/RAM/EMS]
```

### 초기화 순서

| 단계 | 이름             | 설명                                 |
| -- | -------------- | ---------------------------------- |
| 1  | Context 초기화    | 서버 환경, 설정 파일 로드                    |
| 2  | Database 초기화   | PostgreSQL, Cassandra 연결 수립        |
| 3  | Cache 초기화      | Site, Asset, Tag, OPC 등 인메모리 캐시 로드 |
| 4  | Model 초기화      | 메타 모델 구조 로드 및 검증                   |
| 5  | Engine 초기화     | 파이프라인, CEP, DDS 엔진 시작              |
| 6  | Messaging 초기화  | Kafka Consumer, MQTT Listener 시작   |
| 7  | Scheduler 초기화  | Quartz 잡 등록 및 스케줄러 시작              |
| 8  | Monitoring 초기화 | 18개 모니터링 타이머 시작, JMX 등록            |
| 9  | Plugin 초기화     | OEE, 통계 등 플러그인 모듈 시작               |

### 종료 순서

종료는 초기화의 역순으로 진행되며, `EngineManager.shutdown()`이 Graceful Shutdown을 수행합니다. 이를 통해 진행 중인 작업을 안전하게 마무리한 뒤 종료됩니다.

## 데이터 처리 파이프라인

### 수집 → 처리 → 저장 흐름

데이터가 소스에서 저장소까지 어떻게 흐르는지 아래 다이어그램을 통해 확인하실 수 있습니다.

```mermaid
flowchart LR
  subgraph SOURCE["데이터 소스"]
    OPCUA[OPC-UA]
    PLC[PLC]
    MODBUS[Modbus]
    DB[Database]
    HTTP_S[HTTP]
    CSV[CSV / File]
  end

  subgraph TRANSPORT["전송"]
    MQTT_T[MQTT]
    KAFKA_T[Kafka]
  end

  subgraph PIPE["6단계 파이프라인 (36 스레드)"]
    P1[1 Prepare<br/>파싱]
    P2[2 Validate<br/>검증]
    P3[3 Cache<br/>최신값 갱신]
    P4[4 Stream<br/>WebSocket 푸시]
    P5[5 Store<br/>Cassandra]
    P6[6 DDS<br/>Kafka 재발행]
  end

  subgraph SINK["저장"]
    CASS_S[(Cassandra<br/>시계열)]
    PG_S[(PostgreSQL<br/>메타)]
    VK_S[(Valkey<br/>버퍼)]
  end

  OPCUA --> KAFKA_T
  PLC --> KAFKA_T
  MODBUS --> KAFKA_T
  DB --> KAFKA_T
  HTTP_S --> KAFKA_T
  CSV --> KAFKA_T
  MQTT_T --> KAFKA_T

  KAFKA_T --> P1 --> P2 --> P3 --> P4 --> P5 --> P6
  P3 --> VK_S
  P5 --> CASS_S
  P5 --> PG_S
```

```
데이터 소스                    파이프라인                      저장소
┌──────────┐              ┌─────────────────┐          ┌──────────┐
│ OPC-UA   │──┐           │  6단계 처리       │          │Cassandra │
│ OPC-DA   │  │  ┌─────┐  │ 1.Prepare       │  ┌─────┐ │(시계열)  │
│ Modbus   │──┼─▶│MQTT │─▶│ 2.Validate      │─▶│Store│─▶│          │
│ PLC      │  │  │Kafka│  │ 3.Cache         │  │     │  │PostgreSQL│
│ Database │  │  └─────┘  │ 4.Stream(WS)    │  └─────┘  │(메타)    │
│ HTTP     │──┘           │ 5.Store         │           │          │
│ File     │              │ 6.DDS(Kafka)    │           │Redis     │
└──────────┘              └─────────────────┘           │(버퍼)    │
                                                        └──────────┘
```

### 파이프라인 성능 사양

| 항목      | 기본값            | 설명                           |
| ------- | -------------- | ---------------------------- |
| 워커 스레드  | 36             | `engine.pipeline.threads`    |
| 처리율 제한  | 40,000 msg/sec | `engine.pipeline.ratelimit`  |
| 버퍼 큐 크기 | 1,200,000      | `engine.pipeline.queue.size` |
| 비동기 병렬  | 256            | `engine.async.parallelism`   |

## HTTP 필터 체인

웹 요청은 다음과 같은 필터 체인을 순서대로 통과합니다. 각 필터가 어떤 역할을 하는지 이해하시면 보안 및 요청 처리 흐름을 파악하시는 데 도움이 됩니다.

```
Request → EncodingFilter (UTF-8)
        → MDCFilter (로깅 컨텍스트)
        → SecurityHeaderFilter (CSP, X-Frame-Options)
        → XSSFilter (XSS 방어, 10개 패턴)
        → SecurityFilter (URL 패턴 기반 인증, 43개 규칙)
        → APIFilter_V3 (/api/v3/* 토큰 인증)
        → V4_Filter (/api/v4/* Bearer 토큰)
        → MobileFilter (/m/* 모바일 라우팅)
        → ResourcesFilter (정적 리소스 캐싱)
        → DispatcherServlet (Spring MVC)
```

## Spring 설정 구조

```
META-INF/spring/
├── spring-context.xml       # Root Spring 컨텍스트
├── servlet-context.xml      # DispatcherServlet 설정
└── controllers.xml          # @Controller 컴포넌트 스캔
```

* 컴포넌트 스캔: `plantpulse.server.mvc` 패키지
* 비동기 Executor: 10스레드
* i18n: CookieLocaleResolver (한국어, 영어)
* 뷰 리졸버: JSP (`/WEB-INF/jsp/`)

## 캐시 아키텍처

싱글턴 패턴의 인메모리 캐시 매니저 8개가 핫 데이터를 관리합니다. 자주 조회되는 데이터를 메모리에 미리 올려두어 응답 속도를 높이는 역할을 합니다.

| 캐시                    | 대상        | 용도           |
| --------------------- | --------- | ------------ |
| SiteCacheManager      | 사이트 메타    | 사이트 조회 가속    |
| AssetCacheManager     | 에셋 계층     | 설비 트리 조회     |
| TagCacheManager       | 태그 정의     | 태그 메타데이터     |
| PointCacheManager     | 최신 포인트 값  | 실시간 데이터 서빙   |
| OPCCacheManager       | OPC 서버 정보 | 연결 상태 추적     |
| AlarmCacheManager     | 활성 알람     | 알람 실시간 조회    |
| MetaModelCacheManager | 모델 구조     | 계층 구조 탐색     |
| StreamingCacheMap     | 스트리밍 버퍼   | WebSocket 푸시 |

## 메시징 아키텍처

PlantPulse는 다양한 프로토콜을 통해 데이터를 수신하고 분배합니다. 아래에서 수신(Inbound)과 분배(DDS) 구조를 안내합니다.

### 수신 (Inbound)

| 리스너                  | 프로토콜      | 용도            |
| -------------------- | --------- | ------------- |
| MQTTMessageListener  | MQTT      | IoT 센서 데이터 수집 |
| KafkaConsumerRunner  | Kafka     | 대용량 데이터 스트림   |
| STOMPMessageListener | STOMP     | WebSocket 이벤트 |
| HTTPEventServlet     | HTTP POST | Webhook 이벤트   |

### 분배 (DDS - Data Distribution Service)

Kafka 토픽을 통한 멀티 구독 데이터 분배 구조입니다. 관심 있는 토픽을 구독하시면 해당 데이터를 실시간으로 수신하실 수 있습니다.

| 토픽                        | 용도       |
| ------------------------- | -------- |
| `pp-tag-point`            | 태그 값 변경  |
| `pp-tag-alarm`            | 태그 알람    |
| `pp-asset-data`           | 에셋 데이터   |
| `pp-asset-alarm`          | 에셋 알람    |
| `pp-asset-event`          | 에셋 이벤트   |
| `pp-domain-changed-event` | 메타데이터 변경 |
