# 일일/월간/연간 생산 레포트 구현 계획 ## 현황 파악 | 항목 | 내용 | |------|------| | DB | PostgreSQL + TimescaleDB, `history_table` | | 데이터 주기 | 1분 스냅샷 | | 현재 태그 수 | 1,807개 | | 이용 가능 태그 종류 | FI, FICQ, FIC, LI, LICA, TI, TICA, PI, PIC 등 | --- ## ⚠️ 구현 전 반드시 확인해야 할 사항 (사용자 결정 필요) ### 1. 생산량 정의 어떤 태그가 "생산량"을 나타내는지 사용자가 지정해야 한다. | 질문 | 예시 | |------|------| | 주요 생산 제품은? | 예: 에틸렌, LPG, 나프타 등 | | 각 제품의 생산량 태그는? | 예: `ficq-6101.pv` = 6호기 에틸렌 출하 유량 | | 유량의 공학 단위는? | 예: ton/hr, Nm³/hr, kg/hr | | 적산 방법은? | 순간유량(PV) × 1분 → 시간적산, 또는 별도 적산 태그 존재 여부 | | 조업시간 판정 기준 태그는? | 예: 특정 태그값 > 0 이면 운전 중 | ### 2. 레포트 항목 정의 사용자가 원하는 레포트 항목을 구체화해야 한다. 아래는 일반적인 공정 플랜트 기준 초안. --- ## 레포트 구조 설계 (초안) ### 일일 레포트 (1일치) ``` ┌────────────────────────────────────────────────────────┐ │ ○○플랜트 일일 생산 레포트 2026-05-01 (목) │ ├──────────────┬─────────────────────────────────────────┤ │ 1. 생산 실적 │ 제품별 일일 생산량 (ton 또는 Nm³) │ │ │ - 각 FICQ 태그 적산값 │ │ │ - 전일 대비 증감 │ │ │ - 월 누계 │ ├──────────────┼─────────────────────────────────────────┤ │ 2. 조업 현황 │ 운전시간 (분), 가동률 (%) │ │ │ 트러블/정지 횟수 │ ├──────────────┼─────────────────────────────────────────┤ │ 3. 주요 공정 │ 핵심 온도/압력/레벨 태그 평균·최대·최소 │ │ 조건 │ (TI, PI, LI 대표 태그 선정) │ ├──────────────┼─────────────────────────────────────────┤ │ 4. 품질 지표 │ 해당 태그 존재 시 추가 │ └──────────────┴─────────────────────────────────────────┘ ``` ### 월간 레포트 (1개월치 — 일별 집계) ``` ┌────────────────────────────────────────────────────────┐ │ ○○플랜트 월간 생산 레포트 2026년 5월 │ ├──────────────┬─────────────────────────────────────────┤ │ 1. 월간 생산 │ 제품별 월 총 생산량 │ │ 실적 │ 일별 생산량 추이 (테이블 + 차트) │ │ │ 최대/최소 생산일 │ ├──────────────┼─────────────────────────────────────────┤ │ 2. 가동률 │ 월간 가동 시간 / 목표 시간 │ │ │ 일별 가동률 테이블 │ ├──────────────┼─────────────────────────────────────────┤ │ 3. 공정 조건 │ 월 평균·최대·최소 (온도, 압력, 레벨) │ │ 통계 │ 일별 평균 추이 테이블 │ └──────────────┴─────────────────────────────────────────┘ ``` ### 연간 레포트 (1년치 — 월별 집계) ``` ┌────────────────────────────────────────────────────────┐ │ ○○플랜트 연간 생산 레포트 2026년 │ ├──────────────┬─────────────────────────────────────────┤ │ 1. 월별 생산 │ 제품별 월별 생산량 (1~12월 테이블) │ │ 실적 │ 연 총 생산량 │ ├──────────────┼─────────────────────────────────────────┤ │ 2. 월별 가동률│ 월별 가동시간 / 가동률 │ ├──────────────┼─────────────────────────────────────────┤ │ 3. 공정 조건 │ 월별 평균 공정 조건 추이 │ │ 월별 통계 │ │ └──────────────┴─────────────────────────────────────────┘ ``` --- ## 핵심 SQL 설계 ### 일일 유량 적산 (1분 데이터 → 일일 합계) ```sql -- FICQ 태그 일일 적산값 (단위: 공학단위/분 × 1440분) -- 순간유량이 ton/hr 단위일 경우 × (1/60) = ton/분 SELECT recorded_at::date AS day, tagname, SUM(value::double precision / 60.0) AS daily_total, -- ton/hr → ton COUNT(*) AS data_points, ROUND(COUNT(*) / 1440.0 * 100, 1) AS data_rate_pct -- 데이터 충족률 FROM history_table WHERE tagname IN ('ficq-6101.pv', 'ficq-6113.pv', ...) -- 생산 태그 목록 AND recorded_at >= '2026-05-01+09' AND recorded_at < '2026-06-01+09' GROUP BY day, tagname ORDER BY day, tagname; ``` ### 공정 조건 일별 통계 ```sql SELECT recorded_at::date AS day, tagname, AVG(value::double precision) AS avg_val, MAX(value::double precision) AS max_val, MIN(value::double precision) AS min_val, STDDEV(value::double precision) AS stddev_val FROM history_table WHERE tagname IN ('ti-6111a.pv', 'ti-6211a.pv', ...) -- 대표 온도/압력 태그 AND recorded_at >= '2026-05-01+09' AND recorded_at < '2026-06-01+09' GROUP BY day, tagname ORDER BY day, tagname; ``` ### 조업시간 계산 (일별 가동분 집계) ```sql -- 특정 태그(기준 태그)의 값이 0 초과인 분의 수 = 가동 분 SELECT recorded_at::date AS day, COUNT(*) FILTER ( WHERE value::double precision > 0 ) AS running_minutes, COUNT(*) AS total_minutes, ROUND( COUNT(*) FILTER (WHERE value::double precision > 0) / COUNT(*)::numeric * 100, 1 ) AS availability_pct FROM history_table WHERE tagname = 'ficq-6101.pv' -- 가동 판정 기준 태그 AND recorded_at >= '2026-05-01+09' AND recorded_at < '2026-06-01+09' GROUP BY day ORDER BY day; ``` ### 월별 집계 (연간 레포트용) ```sql SELECT DATE_TRUNC('month', recorded_at AT TIME ZONE 'Asia/Seoul') AS month, tagname, SUM(value::double precision / 60.0) AS monthly_total, AVG(value::double precision) AS avg_val FROM history_table WHERE tagname IN ('ficq-6101.pv', ...) AND recorded_at >= '2026-01-01+09' AND recorded_at < '2027-01-01+09' GROUP BY month, tagname ORDER BY month, tagname; ``` --- ## 구현 구성요소 ### Backend (C# ASP.NET Core) #### 새 인터페이스 추가 (`IExperionServices.cs`) ```csharp // 레포트 서비스 인터페이스 public interface IProductionReportService { Task GetDailyReportAsync(DateOnly date, ReportConfig config); Task GetMonthlyReportAsync(int year, int month, ReportConfig config); Task GetAnnualReportAsync(int year, ReportConfig config); } // 레포트 설정 (사용자 정의 태그 목록) public record ReportConfig( List ProductionTags, // 생산량 적산 태그 List ConditionTags, // 공정 조건 태그 (온도/압력/레벨) string AvailabilityTag, // 가동 판정 기준 태그 string FlowUnit, // 유량 단위 (ton/hr, Nm³/hr 등) double FlowConvFactor // 단위 환산 계수 (예: 1/60 for ton/hr → ton/min) ); // 결과 레코드 public record DailyProductionRow(string TagName, double DailyTotal, int DataPoints, double DataRatePct); public record ConditionStatRow(string TagName, double Avg, double Max, double Min, double Stddev); public record DailyReportResult( DateOnly Date, List Production, List Conditions, int RunningMinutes, int TotalMinutes, double AvailabilityPct ); // Monthly/Annual 유사 구조 ``` #### 새 컨트롤러 (`ExperionControllers.cs`) ``` GET /api/report/daily?date=2026-05-01 GET /api/report/monthly?year=2026&month=5 GET /api/report/annual?year=2026 GET /api/report/config ← 현재 레포트 설정 조회 POST /api/report/config ← 레포트 설정 저장 (태그 목록 등) ``` #### 레포트 설정 저장 `report_config.json` 파일로 서버 디렉토리에 저장 (appsettings 또는 별도 JSON). --- ### Frontend (HTML/JS) #### 새 탭 추가 (`index.html`) 사이드바에 `09 생산레포트` 탭 추가, `#pane-report` 섹션. #### UI 구성 ``` ┌─────────────────────────────────────────────┐ │ [일일] [월간] [연간] ← 레포트 유형 선택 │ │ 날짜/월/년 선택기 │ │ [조회] [Excel 다운로드] [PDF 인쇄] │ ├─────────────────────────────────────────────┤ │ │ │ 레포트 본문 렌더링 영역 │ │ (HTML 테이블 기반, 인쇄 스타일 적용) │ │ │ └─────────────────────────────────────────────┘ ``` #### JS 함수 목록 ```javascript rptLoadDaily(date) // 일일 레포트 로드 rptLoadMonthly(y, m) // 월간 레포트 로드 rptLoadAnnual(y) // 연간 레포트 로드 rptRender(data, type) // 레포트 HTML 렌더링 rptExportExcel() // SheetJS로 Excel 출력 (기존 t2sExportExcel 패턴 재사용) rptPrint() // window.print() — 인쇄/PDF 저장 rptSaveConfig(config) // 태그 설정 저장 ``` --- ### 레포트 설정 화면 (태그 관리) 레포트 생성 전에 **어떤 태그가 무슨 의미인지** 등록해야 한다. ``` 생산량 태그 등록: 태그명 설명 단위 환산계수 ficq-6101.pv 6호기 원료 유량 ton/hr 0.01667 ficq-6113.pv 6호기 제품 유량 ton/hr 0.01667 ... 공정 조건 태그 등록: 태그명 설명 단위 ti-6111a.pv 6호기 반응온도 ℃ pi-6101.pv 6호기 반응압력 kPa li-6111.pv 6호기 레벨 % ... 가동 판정 기준 태그: ficq-6101.pv (값 > [0] 이면 운전) ``` 이 설정을 `report_config.json`으로 저장하고 API에서 읽어 SQL을 동적 생성. --- ## 수정/추가 파일 목록 | 파일 | 작업 | |------|------| | `src/Core/Application/Interfaces/IExperionServices.cs` | `IProductionReportService`, `ReportConfig`, 결과 record 추가 | | `src/Infrastructure/Database/ExperionDbContext.cs` | `ProductionReportService` 구현 (일별/월별/연간 SQL) | | `src/Web/Controllers/ExperionControllers.cs` | `ProductionReportController` 추가 (5개 엔드포인트) | | `src/Web/Program.cs` | `ProductionReportService` DI 등록 | | `src/Web/wwwroot/index.html` | `09 생산레포트` 탭 + `#pane-report` 섹션 추가 | | `src/Web/wwwroot/js/app.js` | `rptLoad*`, `rptRender`, `rptExportExcel`, `rptPrint` 구현 | | `src/Web/wwwroot/css/style.css` | 레포트 전용 스타일 + `@media print` 인쇄 스타일 | | `src/Web/report_config.json` | 생산 태그 설정 파일 (신규) | 서버 코드(Python MCP) 변경 없음. --- ## 구현 순서 권장 ``` 1단계 (필수 선행): 사용자가 생산 태그 목록 및 단위 확정 ↓ 2단계: report_config.json 스키마 설계 + ReportConfig record ↓ 3단계: DB 쿼리 레이어 (ProductionReportService) — 일별 집계부터 ↓ 4단계: API 엔드포인트 (컨트롤러) ↓ 5단계: 프론트엔드 UI + 테이블 렌더링 ↓ 6단계: Excel export + 인쇄 스타일 ↓ 7단계: 월간 → 연간으로 확장 ``` --- ## 주의 사항 - **KST 기준 집계**: `recorded_at`은 UTC 저장이므로 일별 집계 시 `AT TIME ZONE 'Asia/Seoul'` 또는 `+ INTERVAL '9 hours'` 적용 필수. 그렇지 않으면 UTC 기준으로 집계되어 날짜가 달라짐. - **유량 적산 단위**: `ficq-*.pv` 태그가 `ton/hr` 단위이면 1분 적산 시 `× (1/60)`. 단위 확인 필수. - **결측 데이터 처리**: 데이터 충족률(`data_rate_pct`)이 낮은 날은 레포트에 `*` 표시 권장. - **과거 데이터 부재**: 현재 history_table은 2026-04-22부터만 존재. 5월 데이터는 5월 이후 수집 시 자동 반영됨. - **TimescaleDB 활용**: `time_bucket()` 또는 `DATE_TRUNC()`로 일별/월별 집계 — `time_bucket_gapfill()`로 결측 구간 0 채움 가능.