# GLM-4.7-Flash 코드 작업 규칙 (ExperionCrawler)

## 필수 준수 사항

### 작업 전
- 반드시 `task_state.md`를 먼저 읽어 진행 상태 파악
- 파일 수정 전 반드시 `read_file`로 전체 내용 확인 후 수정

### 코드 수정 원칙
- 요청된 범위만 수정 — 관련 없는 코드 리팩토링 금지
- 빌드 검증: 각 파일 수정 후 `dotnet build src/Web/ExperionCrawler.csproj --no-restore -v q` 실행
- 빌드 실패 시 즉시 원인 수정 후 재빌드, 다음 항목으로 넘어가지 않음

### issues.md 작성 형식
```
| # | 파일 | 심각도 | 분류 | 내용 | 상태 |
|---|------|--------|------|------|------|
| 1 | src/... | HIGH/MED/LOW | bug/perf/quality/security | 설명 | pending/fixed |
```
심각도 기준:
- HIGH: 런타임 예외, 데이터 손실, 보안 취약점
- MED: 성능 저하, 잘못된 동작, 예외 미처리
- LOW: 코드 품질, 불필요한 코드, 명명 불일치

### 클로드 검수를 위한 커밋 규칙
- 각 이슈 수정 완료 시: `git add -p` 후 이슈 번호 포함 커밋
  예: `fix(#3): ExperionDbContext null 참조 예외 방어 처리`
- 전체 완료 후 `REVIEW_REQUEST.md` 생성하여 검수 요청

### MCP 도구 활용
- `search_codebase`: 관련 코드 패턴 검색에 적극 활용
- `ask_iiot_llm`: IIoT/OPC UA 도메인 판단이 필요할 때 사용

---

## [CRITICAL] ASP.NET Core 컨트롤러 JSON 직렬화 규칙

### 배경 (반드시 숙지)

`src/Web/Program.cs`에 다음 설정이 있다:
```csharp
opt.JsonSerializerOptions.PropertyNamingPolicy = null;  // PascalCase 그대로 직렬화
```

이로 인해 C# 속성명이 **그대로** JSON 키가 된다.  
프론트엔드(`app.js`)는 **모든 JSON 필드를 camelCase**로 접근하므로,  
PascalCase 키가 오면 **모든 값이 `undefined`** 가 된다.

### 금지 패턴 (절대 사용 금지)

```csharp
// ❌ shorthand 익명 객체 — C# 속성명(PascalCase)이 JSON 키로 그대로 사용됨
return Ok(new { x.Id, x.TagName, x.NodeId, x.LiveValue });

// ❌ typed 객체를 Ok()에 직접 전달 — PascalCase 직렬화됨
return Ok(result);
return Ok(new MyDto { Id = 1, TagName = "abc" });
```

### 올바른 패턴 (항상 명시적 camelCase 매핑)

```csharp
// ✅ 항상 명시적으로 소문자 키 지정
return Ok(new
{
    id        = x.Id,
    tagName   = x.TagName,
    nodeId    = x.NodeId,
    liveValue = x.LiveValue,
    timestamp = x.Timestamp
});

// ✅ 컬렉션 포함 응답
return Ok(new
{
    total = r.Total,
    items = r.Items.Select(x => new
    {
        id       = x.Id,
        tagName  = x.TagName,
        nodeId   = x.NodeId
    })
});
```

### C# 예약어 처리

`class`는 C# 예약어이므로 `@class`를 사용한다. System.Text.Json이 `"class"`로 정상 직렬화한다:

```csharp
// ✅ @class → JSON "class"
return Ok(new { id = x.Id, @class = x.Class, name = x.Name });
```

### 점검 체크리스트

컨트롤러에서 `Ok(...)` 또는 `return` 사용 시:
- [ ] 익명 객체의 모든 키가 소문자(camelCase)인가?
- [ ] `new { x.SomeProp }` 형태(shorthand)가 없는가?
- [ ] typed record/class를 그대로 반환하지 않는가?
- [ ] C# 예약어(`class`, `string` 등)에 `@` 접두사를 붙였는가?
