fastTable fastRecord 필요성
- 현재 데이터 저장 간격(1분) 으로는 상세한 필드 데이터의 변동을 캐치 하기 힘듬.
- 정해진 시간동안 초 단위로 데이터를 받아서 평균을 넘어서는 데이터 분류 등에 분석을 위한 데이터 재료로 사용
Expected Fucnctional Act Sequence
- UI : 에서 최대 8개 까지 태그명을 선정 및 수집기간(시간 , 일) 선정 하고 시작하면,
- 테이블 완성() 테이블은 미리 만들어 놓은 형태여도 좋고, 컬럼의 태그명만 바꾸는 방식도 좋다
- OPC UA 서버로 부터 받는 Realtime 테이블에서 선정된 태그값을 초 단위 (사용자 지정 가능)로 데이터 수집
- 정해진 시간이 만료되면 수집동작 종료
- 수집되고 있는 또는 수집된 데이터를 realtime trend graph로 표시
- UI : 사용자 필요에 따라 전체 테이블 내용 또는 부분 시간 구간을 Excel로 Export 할수있게
- UI : 테이블 삭제 또는 데이터로 보관 가능? 하게
Claude 가 더 추가하거나 유용한 방식이 있으면 아래에 적어주세요
추가 아이디어 (Claude 제안, 2026-04-28)
핵심 설계 결정
1. 데이터 출처 — 별도 OPC UA Subscription 신설 권장
- 기존
ExperionRealtimeService의 Subscription은 SamplingInterval 500ms / PublishingInterval 1000ms로 고정
- fastRecord는 분해능이 핵심이므로 별도 Subscription 생성:
- SamplingInterval: 100/250/500/1000ms 중 사용자 선택
- PublishingInterval: SamplingInterval과 동일하게
- 세션 종료 시 Subscription dispose → 평소엔 부하 없음
- 대안(기존
_pendingUpdates ConcurrentDictionary 폴링)은 분해능 한계(500ms) 때문에 부적합
2. 스토리지 — 단일 hypertable + session_id 컬럼 (Long 형태)
- Long 형태(태그 1행/시점) 권장 이유: 태그 개수 가변, 태그별 NULL 처리 단순, TimescaleDB 압축 효율
- 조회 시 서버 또는 클라이언트에서 PIVOT → Wide 변환 (그래프/Excel용)
3. 데이터 규모 추정
| 시나리오 |
행수 |
비고 |
| 8태그 × 1s × 1시간 |
28,800 |
즉시 처리 |
| 8태그 × 1s × 24시간 |
691,200 |
TimescaleDB 무난 |
| 8태그 × 100ms × 1시간 |
288,000 |
TimescaleDB 권장 |
| 8태그 × 100ms × 24시간 |
6,912,000 |
retention/압축 필수 |
- 세션당 최대 행수 가드(예: 5,000,000) → 도달 시 자동 종료 + 상태
RowLimitReached
4. 세션 상태 머신
- 동시 Running 세션 최대 N개 제한(권장 3개) — OPC UA Subscription 부하 고려
- 앱 재기동 시 Running 세션은
Failed 처리(중간값 보존, 재개 X — 단순화)
추가 기능 제안
5. 실시간 트렌드 그래프 — uPlot 권장
- Chart.js: 친숙하지만 10만점 초과 시 버벅임
- uPlot: 시계열 특화, 100만점도 부드러움. CDN 단일 파일(~50KB)
- 다운샘플링: LTTB 알고리즘으로 화면 픽셀 폭에 맞춰 축소(예: 화면 1200px → 1200점)
- 라이브 갱신: 1~2초 간격 폴링으로 새 데이터만 append
6. 통계 + 이상치 분석 (사용자가 언급한 "평균을 넘어서는 데이터 분류")
- 세션 종료 후 또는 실시간 패널에 표시:
- 태그별 mean / stddev / min / max / median / p95 / p99
- 이상치 강조:
|value - mean| > k × stddev (k 사용자 설정, 기본 3)
- 임계값 알람: 태그별 상/하한 설정 → 초과 구간 그래프에 색상 강조
- 변화율(slope): Δvalue/Δt 급변 구간 표시
- DB 부하 없이 클라이언트 JS로 계산 가능 (8태그 × ~30만점 수준)
7. Excel/CSV Export — 클라이언트 사이드
xlsx.full.min.js가 이미 wwwroot에 추가되어 있음 → 즉시 활용
- Wide 포맷:
recorded_at | tag1 | tag2 | ...
- 옵션: 전체 / 그래프 현재 줌 구간만 / 시간 슬라이더로 지정한 구간
- 행수 50,000 초과 시 CSV 권장 (Excel 시트당 1,048,576행 제한 고려)
- 큰 세션은 서버에서 스트리밍 응답(
text/csv)으로 제공하는 엔드포인트 추가 권장
8. 보관/정리 정책
- 세션별
retention_days 필드 (기본 30, 무한=NULL)
pinned 플래그(불 표시) → 자동 정리 제외
ExperionFastCleanupService BackgroundService — 일 1회 새벽 만료 세션 + 데이터 삭제
- TimescaleDB
drop_chunks 활용 가능
9. 사용성 개선
- 세션 템플릿: 자주 쓰는 태그 조합 + 설정 저장 → 원클릭 시작
- 진행률 표시:
(현재행수 / 예상행수) × 100, 남은 시간 추정
- 다중 태그 단위 그룹: 같은 단위 태그를 같은 Y축으로 묶고 다른 단위는 보조 Y축
- 태그별 색상 자동 할당 + 토글로 표시/숨김
- 그래프 위에 마우스 호버 → 모든 태그의 해당 시점 값 툴팁
- 시간 동기화 표시: 서버 시각(UTC) ↔ 브라우저 KST 변환 (이력 조회와 동일 패턴)
10. Subscription 동시성 / 안전성
- 같은 nodeId를 여러 fast 세션이 동시 구독해도 OPC SDK가 처리 — 단, 각 Subscription 별도 비용
- 세션 시작 시 노드 유효성 사전 검증(
Read 단발) → bad이면 시작 거부
- OPC 연결 끊김 시 → 세션 자동
Failed + 그때까지 데이터 보존
- 메모리 보호: 콜백마다 직접 INSERT가 아니라 기존 패턴(ConcurrentDictionary 버퍼 + 1~2초 배치 INSERT)
11. 라이브 vs 완료 화면 통합
- 동일 화면에서 상태에 따라 컨트롤만 다르게:
- Running: [중지] 버튼, 라이브 갱신 ON, 진행률
- Completed: [Excel] [CSV] [삭제] [고정/해제] 버튼, 통계 패널, 줌/팬
구현 플랜
전체 구조
Task A — DB 스키마 + 엔티티
| 파일 |
작업 |
ExperionEntities.cs |
FastSession, FastRecord 엔티티 추가 |
ExperionDbContext.cs |
DbSet<FastSession>, DbSet<FastRecord>, 테이블 DDL, hypertable 생성(SELECT create_hypertable('fast_record', 'recorded_at', if_not_exists => TRUE)) |
IExperionServices.cs |
IExperionFastService 인터페이스 + FastSessionStatus/FastSessionInfo/FastQueryResult record |
Task B — FastService (백그라운드 + 컨트롤러)
| 파일 |
작업 |
Infrastructure/OpcUa/ExperionFastService.cs (신규) |
IHostedService + IExperionFastService 구현. 세션별 Subscription 관리, 콜백 → 버퍼, FlushLoop 2s, 자동 종료(만료/행수초과/외부중지) |
ExperionDbContext.cs |
BatchInsertFastRecordsAsync(IEnumerable<FastRecord>), GetFastSessionsAsync(), GetFastRecordsAsync(sessionId, from?, to?), DeleteFastSessionAsync(sessionId) 등 |
Web/Controllers/ExperionControllers.cs |
ExperionFastController 추가:
POST /api/fast/start (tags, samplingMs, durationSec, name, retentionDays)
POST /api/fast/{id}/stop
GET /api/fast/sessions
GET /api/fast/{id} (세션 메타)
GET /api/fast/{id}/records?from&to&format=long|wide
GET /api/fast/{id}/csv (스트리밍)
DELETE /api/fast/{id}
POST /api/fast/{id}/pin |
Web/Program.cs |
ExperionFastService Singleton + HostedService 등록 |
Web/appsettings.json |
Fast 섹션 — MaxConcurrentSessions:3, MaxRowsPerSession:5000000, FlushIntervalMs:2000 |
Task C — UI: 09 fastRecord 탭
| 파일 |
작업 |
wwwroot/index.html |
사이드바 09번 pane-fast 섹션 추가: - 좌측: 세션 목록(상태/이름/태그수/시작시각/진행률) - 우측 상단: [신규 세션] 버튼 → 모달(태그 선택 8개, 샘플링 select, 기간 select, 이름, retention) - 우측: 선택 세션의 트렌드 그래프 + 통계 + 이상치 패널 + Export 버튼 |
wwwroot/lib/uPlot.iife.min.js |
uPlot 라이브러리 추가 (CDN에서 다운로드한 파일) |
wwwroot/lib/uPlot.min.css |
uPlot 스타일 |
wwwroot/js/app.js |
fastSessionsLoad(), fastStart(), fastStop(id), fastDelete(id), fastPin(id), fastSelect(id), fastRenderChart(), fastRenderStats(), fastExportXlsx(), fastExportCsv(), fastLivePollStart/Stop |
wwwroot/css/style.css |
.fast-session-list, .fast-progress, .fast-stats-grid, .fast-outlier, 모달 스타일 |
Task D — 정리/보관 백그라운드
| 파일 |
작업 |
Infrastructure/OpcUa/ExperionFastCleanupService.cs (신규) |
BackgroundService — 일 1회(03:00) 만료된 세션 + record 삭제. pinned=true 제외 |
Web/Program.cs |
HostedService 등록 |
Task E — 안정성 / QA
- 노드 유효성 사전 검증(시작 시 Read 1회) — bad이면 400 반환
- 동시 세션 수 제한 검사 — 초과 시 409
- 세션 시작 시 OPC UA 연결 상태 확인 — 연결 안되어 있으면 400
- 앱 종료 시 Running 세션 graceful 마무리(현재 버퍼 flush 후 status=
Cancelled)
- 앱 시작 시 Running 상태 잔류 세션 →
Failed 마킹
- 단위/통합 테스트는 기존 패턴 따름(현 프로젝트엔 테스트 없음 — 수동 QA 시나리오 문서화)
Task F — 문서화
CLAUDE.md에 작업 이력 항목 추가
appsettings.json 신규 키 설명
우선순위 추천
- MVP: Task A + B(start/stop/sessions/records 엔드포인트 4개) + C(목록/시작/중지/단순 그래프) — 핵심 가치 검증
- 분석: 통계 패널 + 이상치 강조 + 임계값
- Export: xlsx + csv 스트리밍
- 운영: Task D 정리, retention/pinned, 동시성 제한, 진행률
- 고급: 템플릿, 다중 Y축, LTTB 다운샘플링 최적화