# 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 형태) ``` fast_session (메타) id, name, started_at, ended_at, status, sampling_ms, duration_sec, tag_list (jsonb), row_count, retention_days, pinned fast_record (TimescaleDB hypertable) session_id, recorded_at, tagname, value → hypertable on recorded_at, chunk_time_interval = 1 day → index (session_id, tagname, recorded_at) ``` - **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. 세션 상태 머신 ``` Pending → Running → Completed ↘ Cancelled (사용자 중지) ↘ Failed (OPC 연결 끊김 등) ↘ RowLimitReached ``` - 동시 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] [삭제] [고정/해제] 버튼, 통계 패널, 줌/팬 --- ## 구현 플랜 ### 전체 구조 ``` [OPC UA Server] │ ├──(기존) Subscription 1 → realtime_table → history_table (60s) │ └──(신규) Subscription per fastSession ├── 콜백 → ConcurrentDictionary 버퍼 └── 2s 배치 → fast_record (TimescaleDB hypertable) ``` ### Task A — DB 스키마 + 엔티티 | 파일 | 작업 | |------|------| | `ExperionEntities.cs` | `FastSession`, `FastRecord` 엔티티 추가 | | `ExperionDbContext.cs` | `DbSet`, `DbSet`, 테이블 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)`, `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` 신규 키 설명 --- ## 우선순위 추천 1. **MVP**: Task A + B(start/stop/sessions/records 엔드포인트 4개) + C(목록/시작/중지/단순 그래프) — 핵심 가치 검증 2. **분석**: 통계 패널 + 이상치 강조 + 임계값 3. **Export**: xlsx + csv 스트리밍 4. **운영**: Task D 정리, retention/pinned, 동시성 제한, 진행률 5. **고급**: 템플릿, 다중 Y축, LTTB 다운샘플링 최적화