feat: P&ID 연결 분석, LLM 에이전트 모드, KB 확장, MCP 서버 리팩토링

- P&ID: 연결 분석 API, Prefix 규칙 관리, 카테고리 분류, DXF 그래프 빌드
- LLM: 대화 요약, tool card 영구 보존, 시계열 차트(uPlot), 에이전트 모드
- KB: 청크 미리보기, Field Instrument Inference, 인증/Qdrant 클라이언트
- MCP: 서버 기능 확장, 파이프라인 수정, timeout 개선
- Frontend: P&ID UI, LLM UI, KB UI, OPC UA Write 탭 추가
- 설정: AGENTS.md, plant_context, README, opencode.json 업데이트
- 정리: 진단 체크리스트 문서 삭제
This commit is contained in:
windpacer
2026-05-21 23:36:57 +09:00
parent 960bda4a3c
commit 302183c97e
142 changed files with 2432231 additions and 1082 deletions

View File

@@ -26,6 +26,23 @@ All controllers are in `src/Web/Controllers/ExperionControllers.cs` (single file
**PostgreSQL** (NOT SQLite — README is stale). Connection strings in `src/Web/appsettings.json`. TimescaleDB extension may be enabled on `history_table` via DDL only; no app code changes needed.
### ⚠️ Critical — `duration_seconds` semantics
`event_history_table.duration_seconds` = **직전 상태의 지속 시간(초)**. 현재 이벤트의 지속 시간이 아니다.
- `DigitalEventDetectorService`가 이전 상태를 처음 관측한 시점부터 값이 바뀔 때까지의 경과 시간(wall-clock)을 기록
- 예: `prev=R-RUN, curr=R-TRIP, duration_seconds=1423`**R-RUN 상태가 1423초간 유지되다가** R-TRIP으로 전환된 것. TRIP이 1423초간 지속된 게 아님
- MCP 툴(`query_events`, `active_alarms`) JSON 출력 시 `prev_state_duration_s` 필드명으로 변환하여 반환하므로 LLM이 필드명만 보고 의미를 알 수 있음
- LLM 프롬프트에 이벤트 데이터를 넘길 때는 `(직전상태유지={duration}s)` 형식으로 전달
### ⏰ Timezone — KST
DB는 UTC 저장, LLM에는 **KST(UTC+9) 변환**해서 전달.
- `server.py``_kst_str()` 함수로 UTC ISO 문자열 → KST ISO 문자열 변환
- 모든 시스템 프롬프트에 "모든 시각은 KST"라고 명시
- MCP 서버 재기동 필요 시 `uv run server.py --http`
## Critical Convention — JSON camelCase
`PropertyNamingPolicy = null` in Program.cs means C# PascalCase becomes JSON keys. **Frontend expects camelCase**. Every controller `Ok(...)` response MUST use explicit anonymous objects with camelCase keys: