# Gateway 필드 변환 및 보안 문제 해결

## 오전 10:58

### 문제 1: 헬스체크 엔드포인트 표준화

**상황**:
- 각 서비스마다 다른 헬스체크 엔드포인트
- nginx/k8s 표준인 `/healthz` 필요

**해결**:
```python
# rb10508_micro/app/main.py
@app.get("/healthz")
async def healthz():
    """단순 헬스체크 - 서비스 생존 확인만"""
    return {"status": "ok"}
```
- 루트 레벨에 `/healthz` 추가
- API 프리픽스 없이 접근 가능
- 빠른 응답 (< 100ms)

### 문제 2: UUID 형식 오류

**원인**:
- Frontend가 username(`happybell80`) 전송
- Gateway가 UUID 형식 기대
- `invalid UUID 'happybell80': length must be between 32..36 characters`

**해결**:
```python
# robeing-gateway/app/database.py
async def get_robeing_info(username: str):
    """username으로 직접 조회"""
    query = text("""
        SELECT ... 
        FROM workspace_member wm
        JOIN user u ON wm.user_id = u.id
        WHERE u.username = :username
    """)
```
- users 테이블 JOIN으로 username → UUID 변환
- UUID 체크 로직 제거 (Frontend는 항상 username 사용)

### 문제 3: nginx 직접 프록시 vs Gateway 라우팅

**현재 구조 분석**:
```
# 원래 설계 (문서)
Frontend → nginx(/gateway/) → Gateway(8100) → rb10508_micro

# 실제 nginx 설정
location ^~ /rb10508/ {
    proxy_pass http://192.168.219.52:10508/;  # 직접 프록시
}
location ^~ /gateway/ {
    proxy_pass http://localhost:8100/;  # Gateway 서비스
}
```

**문제점**:
- `/rb10508/`는 Gateway 우회
- `message` → `text` 필드 변환 안됨
- 422 Unprocessable Entity 에러

**해결 방안 검토**:
1. nginx 모든 요청을 Gateway로 → **Gateway 부하 문제**
2. rb10508_micro가 두 필드 모두 지원 → **실용적**

### 문제 4: 사용자 인증 검증 부재 (보안 위험)

**현재 상황**:
```javascript
// 누구나 헤더 조작 가능
fetch('/gateway/api/chat', {
  headers: {'X-User-Id': 'admin'}  // 위장 가능!
})
```

**위험**:
- 사용자 위장 가능
- 로빙 접근 권한 우회
- 데이터 유출 위험

**필요한 조치**:
- JWT 토큰 검증 로직 추가
- auth-server와 연동
- 실제 사용자 확인 필수

## 교훈

### 1. **헬스체크 설계**
- 표준 엔드포인트 사용 (`/healthz`)
- 빠른 응답 우선 (복잡한 체크는 별도 엔드포인트)
- 루트 레벨 배치로 프리픽스 문제 회피

### 2. **식별자 설계**
- Frontend는 사용자가 이해하는 값 사용 (username)
- Backend에서 내부 ID 변환
- UUID는 내부용으로만 사용

### 3. **Gateway 아키텍처**
- 모든 요청을 Gateway로 보내면 병목 발생
- 실용적 접근: 서비스가 유연하게 처리
- 점진적 마이그레이션 전략 필요

### 4. **보안 최우선**
- 헤더 기반 인증은 위험
- JWT 토큰 검증 필수
- 신뢰 경계 명확히 설정

## 현업 패턴

### Gateway 부하 해결:
1. **Service Mesh**: 각 서비스에 Sidecar 프록시
2. **Gateway 클러스터링**: 여러 Gateway 인스턴스
3. **하이브리드**: 중요 요청만 Gateway, 나머지 직접

### 실용적 해결:
```python
class MessageRequest(BaseModel):
    text: Optional[str] = None
    message: Optional[str] = None
    
    def get_text(self):
        return self.text or self.message
```
- 두 경로 모두 지원
- Gateway 유무와 관계없이 작동
- 마이그레이션 유연성 확보

## 다음 작업

1. **즉시**: rb10508_micro에 message 필드 지원 추가
2. **긴급**: JWT 토큰 검증 구현
3. **계획**: Gateway 스케일링 전략 수립
4. **장기**: Service Mesh 도입 검토

---

## 오후 9:42

### 문제 5: Frontend 빌드 시 환경변수 미적용

**증상**:
- .env 파일에 `VITE_ROBEING_API_URL=https://ro-being.com/gateway` 설정됨
- 하지만 빌드된 JS 파일에는 하드코딩 기본값 `/rb10508` 사용
- 결과: nginx가 Gateway 우회하여 직접 프록시

**원인 발견**:
```yaml
# .gitea/workflows/deploy.yml
- name: Build application
  run: |
    export VITE_API_URL=http://localhost:8001
    # VITE_ROBEING_API_URL 누락!
    npm run build
```

**해결**:
```yaml
export VITE_API_URL=http://localhost:8001
export VITE_ROBEING_API_URL=https://ro-being.com/gateway  # 추가
npm run build
```

### 교훈

1. **빌드 환경변수 체크**
   - CI/CD 스크립트에서 모든 환경변수 설정 확인
   - .env 파일이 있어도 빌드 시점에 로드되는지 검증
   - 빌드된 결과물에서 실제 값 확인

2. **기본값 함정**
   - 하드코딩 기본값은 디버깅을 어렵게 만듦
   - 환경변수 미설정 시 명확한 에러가 낫다

3. **근본 원인 vs 임시방편**
   - rb10508_micro 수정은 임시방편
   - Gitea Actions 수정이 근본 해결
   - 구조적으로 올바른 해결 우선

4. **서버 관리자 관점**
   - Gateway가 이미 모든 기능 제공
   - 직접 프록시는 필드 변환 누락
   - Gateway 경유가 정석