backend — REST API 서버 (Historian)
historian (제품명 Factory Sight) 백엔드. 공장(Machine)→공정(Process)→태그(Tag) 계층의 시계열 데이터를 수집·집계·분석하고, 알람·알림·대시보드·에디터·모니터링·Excel 입출력을 제공하는 Spring Boot 애플리케이션.
1개요
정체성. pom.xml의 <description>LSITC Historian</description> — LS ITC가 개발한 제조 설비 데이터 히스토리안/모니터링·분석 플랫폼의 백엔드. README는 개발 환경 셋업 위주로, 비즈니스 개요 문서는 부재하여 정체성은 코드로 확인.
2빠른 시작 · 실행
./mvnw setup # (initialize) Git Hook 설치 — 단, Windows(setup-hooks.cmd) 하드코딩 주의
./mvnw clean verify # 빌드 + 테스트 + JaCoCo
./mvnw spring-boot:run # 로컬 실행 → http://localhost:8080
./mvnw spotless:apply # Google Java Style 포맷
src/main/resources-${environment}(local/dev/prod)를 필터링 리소스로 오버레이한다. Flyway/Liquibase 없이 db/V1/*.sql을 수작업 적용해야 스키마가 준비된다(ddl-auto: validate라 불일치 시 기동 실패).3아키텍처 — 두 스타일 공존
3.1 레거시 MVC api.* (다수)
도메인: factory·dashboard·analytics·alarm·editor·monitoring·excel·system·user·login·influxdb·custom 등.
3.2 헥사고날/클린 menu · user · notification · role · thirdParty (신규)
user 도메인은 Password·PasswordPolicy·LoginAttempts·Email·Username·UserStatus 값 객체로 풍부하게 모델링.
3.3 공통/횡단
config/(Security·Jpa·Mybatis·Influxdb·JdbcTemplates·Web) · aop/(CommonResponseBodyAdvice 응답 래핑, TransactionAspect) · exception/(GlobalExceptionHandler) · interceptor/(감사 필드 주입) · security/ · common/(response, DatabaseMessageSource i18n).
4데이터베이스
스키마 · 명명 규칙
- 버전 관리 도구 없음 — Flyway/Liquibase 미사용,
db/V1/Factory Sight v1.0.0-DDL/DML.sql수작업 관리. - 문자셋 전 테이블
utf8mb4_unicode_ci. PK{ENTITY}_NO(AUTO_INC), 비즈니스 키{ENTITY}_ID(UUID 추정), 코드{도메인}_CD. - 소프트 삭제
IS_DELETED+ 감사 컬럼(CREATED_BY/DATE등).
'Y'/'N'(char)와 신규 0/1(tinyint)로 혼재.주요 테이블 도메인 (v1.0.0, 38개)
| 도메인 | 테이블(예) |
|---|---|
| 공장/설비 | h_machine, h_process(계층), h_tag(LSL/USL/LCL/UCL) |
| 알람 | h_tag_alarm_rule, h_tag_alarm_log, h_multi_alarm_rule(표현식), alarm_status |
| 사용자/권한/메뉴 | h_user(BCrypt), h_auth, h_user_auth, h_auth_menu, h_menu(계층), h_user_conn_hist |
| 데이터셋/프리셋 | h_dataset, h_preset, h_file |
| 시각화 | h_editor, h_editor_layer, h_monitoring, h_user_monitoring |
| 시스템 | h_code_type, h_code, h_language, system_env, tag_unit |
v1.0.1 추가: api_token(외부 API 토큰), external_api_log(호출 감사).
transactionManager(@Primary)와 JPA jpaTransactionManager 2개가 동일 DataSource에 존재. 레거시·신규 모듈을 한 논리 트랜잭션에서 호출 시 롤백 동기화가 보장되지 않을 수 있다.5API 엔드포인트
총 65개 컨트롤러. 내부 API와 외부(X-API-KEY) API로 나뉜다.
내부 API
| 영역 | 대표 컨트롤러 |
|---|---|
| 인증 | AuthController, LoginController (login, loginByXApiKey, refresh-token) |
| 공장 | Machine/Process/Tag Controller + Mgmt |
| 분석 | RawData, TagTrend, CorrelationRegression, HistogramBoxPlot, MultiHistogram, ParallelCoordinate |
| 알람/알림 | TagAlarm, MultiAlarm, SopAlarm, Alert, Channel |
| 모니터링/에디터 | Dashboard, MonitoringMgmt/Viewer, Editor, EditorLayerCondition |
| 시스템 | User·AuthMgmt·CodeMgmt·Language·ApiToken·SystemEnv 등 |
| Excel/커스텀 | ExcelExport/Upload, Gnp*, SbCpkDetlRead, QueryExplorer |
외부 API /external/api/v1/** — X-API-KEY
ExternalRawDataController(원시 시계열),ExternalAggrController(집계 mean/min/max/median, windowPeriod 10s~12h)- 마스터: Machine/Tags/Process/VirtualTag/TagAlarms/AlarmEvents. 응답은
ExternalResponse(내부CommonResponse와 별도) + 전용 예외 핸들러 + Swagger 그룹(X-API-KEY).
CommonResponseBodyAdvice가 모든 성공 응답을 CommonResponse(true,"SUCCESS",...)로 래핑. 단 swagger·/external/api·/api/v1/alerts/notify·byte[]·ErrorResponse는 제외.6인증 · 보안 중요
SecurityConfig
STATELESS 세션, CSRF/formLogin 비활성. 필터 순서 XApiKeyFilter → JwtAuthFilter → UsernamePasswordAuthenticationFilter. permitAll: /auth/login·logout·refresh-token, swagger, 공통 파일, /api/v1/system/codes, /api/v1/alerts/notify, /external/api/**.
JwtAuthFilter가 모든 인증 사용자에게 ROLE_ADMIN을 일괄 부여(SimpleGrantedAuthority("ROLE_ADMIN") 고정). DB에 h_auth/h_user_auth/h_auth_menu 권한 모델이 있으나 시큐리티 인가에 연결되지 않는다. QueryExplorer의 임의 SQL 실행과 결합 시 위험 증폭.ENC() 미적용. 본 매뉴얼엔 값 미기재. → 환경변수/Vault 분리 + 즉시 로테이션.JwtProvider에서 만료가 상수로 박혀 application.yml의 jwt.*Expiration이 무시된다. 액세스 =24시간(설정은 1시간), 리프레시 ≈48일(설정은 3일). 설정-구현 불일치.security/token/RefreshToken이 static ConcurrentHashMap 저장 → 재시작 시 소실, 다중 인스턴스 불가, 정리 부재(누수). removeUserRefreshToken의 entry.getValue() == userId 참조 비교 버그(.equals() 미사용)로 제거가 사실상 무동작. 토큰 회전 로직은 주석 처리됨.LoginAttempts.MAX_ATTEMPTS=5 5회 실패 시 계정 잠금(관리자 수동 해제). 검증 로직이 user 헥사고날 도메인에 잘 캡슐화됨.7외부 연동
| 대상 | 용도 / 특징 |
|---|---|
| InfluxDB | OkHttp 풀(40, 5분), raw/aggr/custom 버킷별 클라이언트. Flux DSL 필터, windowPeriod에 따라 버킷 자동 선택. InfluxdbUtil: 보간·이상치 제거·8종 기초통계. |
| Teams 알림 | WebClient(Reactor Netty) Incoming Webhook. ⚠️ InsecureTrustManagerFactory로 SSL 검증 비활성 — 보안 약점. |
| 외부 알람 서버 | alarm.address: http://10.123.202.120:8082 (edge-processor 알림 수신 측) |
| 멀티 데이터소스 (thirdParty) | JdbcTemplatesConfig 동적 DS(MySQL/MariaDB/PG/MSSQL/Oracle/SQLite). QueryExplorer가 임의 SQL 실행 — 인가 통제 필수. |
8설정 · 프로파일
- Maven 프로파일
local/dev/prod→resources-${env}오버레이.test는 H2(application-test.yml). - JPA
ddl-auto: validate,open-in-view: false(권장),default_batch_fetch_size: 2000. - MyBatis
map-underscore-to-camel-case,default-executor-type: reuse, stdout SQL 로깅. PageHelper(mysql), springdoc Swagger. WebConfig비동기 응답 타임아웃 600초(대용량 Excel/파일 스트리밍 대비).
9빌드 · 배포
- Maven Wrapper,
${revision}${changelist}CI 버전(flatten-maven-plugin). Spotless(Google Style) 강제, Git Hook 자동 설치. - CI(
.gitlab-ci.yml):test(mvn verify + JaCoCo) →build(develop/tags) →deploy(수동). - 배포: jar 백업 후
/opt/factorysight/backend복사, 소유자fsuser,systemctl restart factorysight-backend.service. systemd 단일 서버 방식(컨테이너 아님).
cmd /c setup-hooks.cmd Windows 전용 하드코딩. README는 setup-hooks.sh를 안내하나 해당 파일은 저장소에 부재.10기술 부채 · 개선 과제
| # | 항목 | 심각도 |
|---|---|---|
| 1 | 모든 사용자 ROLE_ADMIN 일괄 부여 제거 → DB 권한 모델과 인가 연동 | CRITICAL |
| 2 | 평문 비밀정보(DB PW·JWT·Influx 토큰) YML 분리 + 로테이션 | CRITICAL |
| 3 | 리프레시 토큰 인메모리→Redis(TTL), == 버그 수정, 회전 활성화 | HIGH |
| 4 | 외부 API 로그의 API 키 평문 저장 → 마스킹/해시 | HIGH |
| 5 | Teams Webhook InsecureTrustManagerFactory 제거(SSL 검증) | MEDIUM |
| 6 | JWT 만료 하드코딩 상수 제거 → 설정값 일치 | MEDIUM |
| 7 | 이중 트랜잭션 매니저 → 단일(JPA)로 수렴 | MEDIUM |
| 8 | 수작업 SQL → Flyway/Liquibase, Boolean(Y/N vs 0/1) 표준화 | MEDIUM |
11신규 개발자 가이드
읽는 순서
config/SecurityConfig.java+security/filter/{JwtAuthFilter,XApiKeyFilter}.java— 인증 흐름(그리고 §6 결함 인지)config/{MybatisConfig,JpaConfig,InfluxdbConfig}.java— 이중 ORM·트랜잭션 구조aop/CommonResponseBodyAdvice.java+exception/GlobalExceptionHandler.java— 응답·예외 표준- 레거시 예:
api/factory/machine/*(Controller→ServiceImpl→Mapper→Vo) - 헥사고날 예:
menu/또는user/(domain→application→adapter) api/external/**— 외부 API·X-API-KEYdb/V1/*.sql— 스키마 전체