frontend — 사용자 인터페이스 (SPA)
Nuxt 3 기반 산업용 데이터 히스토리안/제조 분석 플랫폼 Factory Sight의 프론트엔드. 대시보드·시계열 분석·알람·모니터링 에디터·공장 마스터·시스템 관리 화면을 제공하는 데이터 집약형 엔터프라이즈 SPA.
1개요
package.json name은 "nuxt-app", README는 기본 "Nuxt Minimal Starter" 템플릿 그대로라 실질 미작성. 정체성은 코드/CI에서 드러난다 — 배포 경로 /opt/factorysight/frontend/webroot, 산출물 historian-frontend-*.zip, 모든 API baseURL /historian/api.
ssr: false. CI는 pnpm generate로 정적 산출물(.output/public)을 만들어 zip 배포. 즉 정적 호스팅 + 별도 백엔드(/historian/api) 구조. InfluxDB 기반 시계열 질의가 핵심 데이터 소스.2빠른 시작 · 실행
pnpm install # (--frozen-lockfile 로 CI 재현성)
pnpm dev # 개발 서버 (vite proxy: /historian/api → :8080)
pnpm generate # 정적 산출물 생성 (.output/public)
pnpm preview # 산출물 미리보기
/historian/api가 localhost:8080(backend)으로 프록시된다. 백엔드가 떠 있어야 로그인·데이터 조회가 동작. 운영은 동일 origin 백엔드 가정.3디렉터리 · 라우팅
주요 라우트 그룹
| 그룹 | 페이지(예) |
|---|---|
| 인증/엔트리 | index, login, changePassword, error/401 |
| analytics(핵심) | TagTrend, HistogramBoxPlot, MultiHistogram, CorrelationRegression, ParallelCoordinate, RawData |
| alarm / alert | TagAlarm(Log), MultiAlarm(Log), SopAlarm / AlertAlarm, Channel |
| monitoring | MonitoringMgmt/[monitoringNo], MonitoringViewer/[monitoringNo] (동적 라우트, 에디터/뷰어) |
| factory / system | MachineMgmt·ProcessMgmt·TagMgmt / UserMgmt·AuthMgmt·MenuMgmt·CodeMgmt 등 |
| custom | custom/gnp/*, custom/scr/* — GNP·SCR 고객사 전용 화면이 코어에 직접 포함 |
메뉴는 정적 라우트가 아니라 백엔드에서 동적으로 받은 메뉴 트리(arrayToTree) + 탭 네비게이션으로 구성. <NuxtPage keepalive />로 페이지가 메모리 상주.
4상태관리 (Pinia)
모두 setup-store(컴포지션) 스타일 + HMR. storesDirs로 자동 등록, persistedstate로 localStorage 영속화.
authStore(영속authState): access/refresh 토큰을 쿠키 + 스토어 동시 저장,login/loginByXApiKey(임베드)/logout/checkAuth. 비밀번호 초기화 강제 이동 로직 보유.historianStore(영속tabs): 메뉴 트리, 탭 네비게이션 전체 로직,isLoading(전역 로더), snackbar/drawer/toasts.MONITORING타입 메뉴는 URI를/monitoring/MonitoringViewer/{no}로 재작성.- 그 외
tagStore,tag/tagGridStore,common/commonStore(집계함수 목록 등),dstts/histogramStore.
FetchFactory.call()이 요청 시 historianStore.isLoading을 직접 토글한다 → API 계층이 전역 로딩 상태에 강결합(테스트/재사용 시 스토어 의존).5API 통신 계층
3중 구조로 체계적이다.
repository/FetchFactory.ts— 기반 클래스.call(method,url,data,opts)표준 호출(GET body 생략, isLoading 플래그로 전역 로더 토글),useAsyncFetch(),excelExportStream()(견고한 Blob 다운로드 — Content-Disposition 파싱, RFC 5987filename*, sanitize).repository/modules/**(60+) — 각extends FetchFactory,PREFIX_URI(대개/api/v1) + 엔드포인트 메서드. 응답CommonResponse {result,code,message,data}.plugins/apiHistorian.ts(client) — DI 컨테이너. 모든 모듈을$api도메인 트리(api.factory.tag,api.analytics.tagTrend…)로 provide.$fetch.create의onRequest(Bearer 토큰 자동 주입, 없으면/login) /onResponseError(401→/login).plugins/code.ts(client) — 부팅 시 공통코드 전량 로드 후Map메모이즈 →$code(id)헬퍼(매번 API 호출 없이 코드 조회).
/historian/api → localhost:8080. 운영은 정적 배포라 동일 origin 백엔드 가정.6인증 · 미들웨어
핵심은 middleware/auth.global.ts (전역, client-only — if(import.meta.server) return).
- 임베드 모드(
?embed=true): 레이아웃empty강제,?token=있으면loginByXApiKey로 X-API-KEY 로그인 → 성공 시 URL에서 token 제거, 실패 시/error/401. (외부 iframe 임베드 인증,docs/embedded-guide와 대응) - 일반 모드:
/login진입 시clearAuth(); 비밀번호 초기화 대상 →/changePassword; accessToken 쿠키 있으면 통과; refreshToken만 있으면/auth/refresh-token재발급; 둘 다 없으면/login. - 토큰 주입은 미들웨어가 아닌
apiHistorian onRequest에서, 401은onResponseError에서 이중 방어.
middleware/routing.global.ts는 빈 함수(defineNuxtRouteMiddleware(()=>{})) — 미사용.레이아웃: default(AppBar/Navigation/TabBar/Loader/SnackBar), login, empty(임베드).
7UI · 컴포넌트
총 213개 .vue 컴포넌트, 자동 import(pathPrefix:false)로 전역 사용. 도메인별: system 33, editor 32, analytics 24, custom 24, form 19 …
components/form/(19) — Kendo 입력을 사내 표준으로 래핑(FormInput·FormDropDownList·FormDateTimePicker…).components/editor/(32) — 모니터링 대시보드 비주얼 에디터(도형/레이어 조건/뷰어). 제품의 가장 복잡한 영역.components/grid/— Kendo Grid 커스텀 셀/필터.
layouts/default.vue의 Kendo 팝업 위치 보정 MutationObserver는 라이브러리 충돌 회피용 DOM 핫픽스(코드 스멜).8설정
nuxt.config.ts:ssr:false,compatibilityDate 2024-11-01, viewportmaximum-scale=1(줌 차단, 키오스크 지향). modules 12종, plugins 5종 전부mode:"client". vite proxy +usePolling(파일 변경 폴링).tsconfig.json:strict:false·noImplicitAny:false·strictNullChecks:false·skipLibCheck:true— 타입 안정성 의도적 완화(빌드 통과 우선).- 환경변수:
runtimeConfig미사용, baseURL·프록시·서버 IP가 코드/설정에 하드코딩 → 멀티 환경 대응 취약.
9빌드 · 배포
- pnpm 고정(
packageManager: pnpm@9.15.2),pnpm.overrides로 일부 버전 핀. - CI(
.gitlab-ci.yml) 2-stage:build(pnpm install --frozen-lockfile→pnpm generate→historian-frontend-{VERSION}.zip, develop/tags) →deploy(수동, 웹루트 비우고 unzip,fsuser권한, 백업). - 전통적 온프레미스 정적 zip 배포.
10기술 부채 · 개선 과제
| # | 항목 | 심각도 |
|---|---|---|
| 1 | TypeScript strict:false 등 → 잠재 타입 버그(apiHistorian의 존재하지 않는 타입 GnpCommonModules, authStore.isCheckedPassword 타입 누락). 점진적 strict 전환 | HIGH |
| 2 | README 미작성(기본 템플릿) → 온보딩 곤란. 실제 정보는 CI/docs에 산재 | MEDIUM |
| 3 | 죽은 코드/스텁(routing.global.ts, utils/workers/*, pages/test/*) 정리 | MEDIUM |
| 4 | 검증기 미완성(주석 처리·빈 반환), zod와 함수형 validator 혼용 정리 | MEDIUM |
| 5 | UI 스택 과중(3 UI + 4 차트) → 번들·일관성. 표준화/경량화 검토 | MEDIUM |
| 6 | 환경설정 하드코딩(runtimeConfig/.env 미활용) → 멀티 환경 대응 | MEDIUM |
| 7 | 토큰 localStorage+쿠키 저장 → XSS 노출면 검토. console.log 프로덕션 잔존 | MEDIUM |
| 8 | 고객사 커스텀(custom/gnp·scr) 코어 혼입 → 멀티테넌트/빌드 분리 고려 | MEDIUM |
11신규 개발자 가이드
읽는 순서
nuxt.config.ts— 모듈·프록시·플러그인 전반app.vue+layouts/default.vue— 셸·네비게이션 구조middleware/auth.global.ts— 인증·임베드 흐름repository/FetchFactory.ts+plugins/apiHistorian.ts— API 계층·$api DI(핵심)stores/authStore.ts,stores/historianStore.ts— 전역 상태·탭- 대표 페이지
pages/analytics/TagTrend.vue— 검색바+차트+다이얼로그 패턴 components/form/*,components/editor/*— 표준 폼·에디터
$api 도메인 트리 DI)이 일관·확장성 있게 설계됨. 공통코드 캐싱, 견고한 Blob 다운로드, 임베드 인증, 분석 검증 composable 등 실무 디테일이 잘 잡혀 있고, 폼/그리드/차트를 사내 표준으로 래핑해 재사용성 확보.