Files
ExperionCrawler/plans/roo-nodemap-undefined-fix.md
windpacer 77bdcf1f7f feat: ExperionCrawler IIoT OPC UA Data Bridge Infrastructure
Major project initialization and feature implementation:

**Core Features:**
- OPC UA client for Honeywell Experion HS R530 integration
- Real-time data streaming and history data retrieval
- Text-to-SQL query engine with TimeScaleDB
- JSON-based node configuration system
- SQLite database with migration support

**Architecture:**
- Clean architecture with Domain, Application, Infrastructure layers
- ASP.NET Core Web API frontend
- Web UI with real-time visualization
- PKI-based OPC UA authentication (TLS)

**Infrastructure Components:**
- ExperionOpcClient: OPC UA connection management
- ExperionRealtimeService: Real-time data streaming
- ExperionHistoryService: Historical data queries
- TextToSqlService: Natural language to SQL queries
- SqlValidator: SQL injection prevention

**Database:**
- TimescaleDB integration (recommended) or SQLite fallback
- Entity Framework Core with Extenstion methods
- OPCTag, KeyValue tables for data storage

**Security:**
- Certificate-based OPC UA endpoint security
- SSL/TLS encryption for database connections
- Output param binding injection prevention

**Testing:**
- Unit tests for TextToSqlService and SqlValidator
- Integration tests for Korean time range extraction

See REVIEW_REQUEST.md for detailed code review information.
2026-04-26 19:28:56 +09:00

2.8 KiB

Roo 작업 지시: 노드맵 대시보드 undefined 필드 수정

배경 및 원인

src/Web/Program.cs 에 다음 설정이 있음:

opt.JsonSerializerOptions.PropertyNamingPolicy = null;  // PascalCase 직렬화

이로 인해 C# 익명 객체 shorthand new { x.Id, x.NodeId } 등은 PascalCase로 직렬화됨. 프론트엔드(app.js)는 camelCase(r.id, r.nodeId)로 접근 → 모든 값이 undefined로 표시됨.

같은 문제를 Browse 엔드포인트에서도 확인했으며, 명시적 camelCase 익명 객체로 수정 완료:

// 수정 전
return Ok(new { success = r.Success, nodes = r.Nodes, error = r.ErrorMessage });

// 수정 후
return Ok(new {
    success = r.Success,
    error   = r.ErrorMessage,
    nodes   = r.Nodes.Select(n => new {
        nodeId      = n.NodeId,
        displayName = n.DisplayName,
        nodeClass   = n.NodeClass,
        hasChildren = n.HasChildren
    })
});

수정 대상 파일

src/Web/Controllers/ExperionControllers.cs
클래스: ExperionNodeMapController
메서드: Query() (약 571번째 줄)


현재 코드 (문제)

return Ok(new
{
    total = r.Total,
    items = r.Items.Select(x => new
    {
        x.Id, x.Level, x.Class, x.Name, x.NodeId, x.DataType
    })
});

x.Id → JSON "Id" (PascalCase) → JS r.id = undefined


수정 후 코드 (목표)

return Ok(new
{
    total = r.Total,
    items = r.Items.Select(x => new
    {
        id       = x.Id,
        level    = x.Level,
        @class   = x.Class,
        name     = x.Name,
        nodeId   = x.NodeId,
        dataType = x.DataType
    })
});

@class 는 C# 예약어 회피용이며, JSON 직렬화 시 "class" 로 정상 출력됨.


추가 확인 사항 (같은 패턴이 있는지 전수 검사)

ExperionControllers.cs 전체에서 PropertyNamingPolicy = null 환경에서 PascalCase로 직렬화될 수 있는 패턴을 모두 찾아 수정:

  1. new { x.PropertyName } 형태의 shorthand 익명 객체
  2. 직접 typed record/class 인스턴스를 Ok(...) 에 넣는 경우

단, 다음은 이미 lowercase이므로 수정 불필요:

  • new { success = ..., nodes = ... } — 명시적 소문자 키
  • new { total = ..., names = ... } — 명시적 소문자 키

빌드 검증

수정 후 반드시:

dotnet build src/Web/ExperionCrawler.csproj --no-restore -v q
  • Build succeeded 확인
  • 에러 0건 확인

클로드 코드 검수 항목

수정 완료 후 아래 내용을 검수 요청:

  1. ExperionNodeMapController.Query() 응답 필드가 모두 camelCase인지
  2. 같은 패턴({ x.Prop })이 다른 컨트롤러에도 있는지 확인 여부
  3. 빌드 성공 여부
  4. @class → JSON "class" 직렬화 정상 작동 여부