Files
ExperionCrawler/monthly-report-plan.md

328 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 일일/월간/연간 생산 레포트 구현 계획
## 현황 파악
| 항목 | 내용 |
|------|------|
| 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<DailyReportResult> GetDailyReportAsync(DateOnly date, ReportConfig config);
Task<MonthlyReportResult> GetMonthlyReportAsync(int year, int month, ReportConfig config);
Task<AnnualReportResult> GetAnnualReportAsync(int year, ReportConfig config);
}
// 레포트 설정 (사용자 정의 태그 목록)
public record ReportConfig(
List<string> ProductionTags, // 생산량 적산 태그
List<string> 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<DailyProductionRow> Production,
List<ConditionStatRow> 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 채움 가능.