UUID 문서 업데이트: Slack UUID 변환 실패 시 에러 처리 추가
- 파일명 날짜 250911 → 250924로 변경 - 의사코드 제거하여 가독성 개선 - Slack ID→UUID 변환 실패 시 403 에러 반환 방안 추가 - DB 현황과 tables.md 문서 불일치 수정 (rb_news 테이블 추가) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
4d9631b9eb
commit
98a44d1733
@ -1,7 +1,7 @@
|
|||||||
# PostgreSQL 테이블 구조
|
# PostgreSQL 테이블 구조
|
||||||
|
|
||||||
## 작성일: 2025-08-20
|
## 작성일: 2025-08-20
|
||||||
## 최종 수정일: 2025-09-15
|
## 최종 수정일: 2025-09-24
|
||||||
## 데이터베이스: main_db
|
## 데이터베이스: main_db
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -11,7 +11,6 @@
|
|||||||
### company
|
### company
|
||||||
- **용도**: 회사 정보
|
- **용도**: 회사 정보
|
||||||
- **Primary Key**: id (UUID)
|
- **Primary Key**: id (UUID)
|
||||||
- **레코드**: 2개
|
|
||||||
|
|
||||||
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|--------|------|------|--------|------|
|
|--------|------|------|--------|------|
|
||||||
@ -24,7 +23,6 @@
|
|||||||
### team
|
### team
|
||||||
- **용도**: 팀 정보
|
- **용도**: 팀 정보
|
||||||
- **Primary Key**: id (UUID)
|
- **Primary Key**: id (UUID)
|
||||||
- **레코드**: 2개
|
|
||||||
|
|
||||||
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|--------|------|------|--------|------|
|
|--------|------|------|--------|------|
|
||||||
@ -37,7 +35,6 @@
|
|||||||
### user
|
### user
|
||||||
- **용도**: 시스템 사용자 정보
|
- **용도**: 시스템 사용자 정보
|
||||||
- **Primary Key**: id (UUID)
|
- **Primary Key**: id (UUID)
|
||||||
- **레코드**: 1개
|
|
||||||
|
|
||||||
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|--------|------|------|--------|------|
|
|--------|------|------|--------|------|
|
||||||
@ -57,7 +54,6 @@
|
|||||||
### workspace_member
|
### workspace_member
|
||||||
- **용도**: 워크스페이스 멤버십
|
- **용도**: 워크스페이스 멤버십
|
||||||
- **Primary Key**: id (UUID)
|
- **Primary Key**: id (UUID)
|
||||||
- **레코드**: 0개
|
|
||||||
|
|
||||||
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|--------|------|------|--------|------|
|
|--------|------|------|--------|------|
|
||||||
@ -75,7 +71,6 @@
|
|||||||
### product
|
### product
|
||||||
- **용도**: 제품 정보
|
- **용도**: 제품 정보
|
||||||
- **Primary Key**: id (UUID)
|
- **Primary Key**: id (UUID)
|
||||||
- **레코드**: 1개
|
|
||||||
|
|
||||||
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|--------|------|------|--------|------|
|
|--------|------|------|--------|------|
|
||||||
@ -90,7 +85,6 @@
|
|||||||
### robeing
|
### robeing
|
||||||
- **용도**: 로빙 엔티티 정보
|
- **용도**: 로빙 엔티티 정보
|
||||||
- **Primary Key**: id (UUID)
|
- **Primary Key**: id (UUID)
|
||||||
- **레코드**: 2개
|
|
||||||
|
|
||||||
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|--------|------|------|--------|------|
|
|--------|------|------|--------|------|
|
||||||
@ -117,7 +111,6 @@
|
|||||||
### slack_workspace
|
### slack_workspace
|
||||||
- **용도**: Slack 워크스페이스 정보
|
- **용도**: Slack 워크스페이스 정보
|
||||||
- **Primary Key**: id (UUID)
|
- **Primary Key**: id (UUID)
|
||||||
- **레코드**: 2개
|
|
||||||
|
|
||||||
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|--------|------|------|--------|------|
|
|--------|------|------|--------|------|
|
||||||
@ -138,7 +131,6 @@
|
|||||||
### user_preference
|
### user_preference
|
||||||
- **용도**: 사용자 개인 설정
|
- **용도**: 사용자 개인 설정
|
||||||
- **Primary Key**: id (INTEGER)
|
- **Primary Key**: id (INTEGER)
|
||||||
- **레코드**: 0개
|
|
||||||
|
|
||||||
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|--------|------|------|--------|------|
|
|--------|------|------|--------|------|
|
||||||
@ -155,7 +147,6 @@
|
|||||||
### gmail_token
|
### gmail_token
|
||||||
- **용도**: Gmail OAuth 토큰
|
- **용도**: Gmail OAuth 토큰
|
||||||
- **Primary Key**: id (UUID)
|
- **Primary Key**: id (UUID)
|
||||||
- **레코드**: 0개
|
|
||||||
|
|
||||||
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|--------|------|------|--------|------|
|
|--------|------|------|--------|------|
|
||||||
@ -180,7 +171,6 @@
|
|||||||
### conversation_log
|
### conversation_log
|
||||||
- **용도**: 대화 기록
|
- **용도**: 대화 기록
|
||||||
- **Primary Key**: id (INTEGER)
|
- **Primary Key**: id (INTEGER)
|
||||||
- **레코드**: 0개
|
|
||||||
|
|
||||||
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|--------|------|------|--------|------|
|
|--------|------|------|--------|------|
|
||||||
@ -198,7 +188,6 @@
|
|||||||
### news
|
### news
|
||||||
- **용도**: 뉴스 데이터
|
- **용도**: 뉴스 데이터
|
||||||
- **Primary Key**: id (UUID)
|
- **Primary Key**: id (UUID)
|
||||||
- **레코드**: 0개
|
|
||||||
|
|
||||||
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|--------|------|------|--------|------|
|
|--------|------|------|--------|------|
|
||||||
@ -208,11 +197,32 @@
|
|||||||
| created_at | TIMESTAMPTZ | YES | CURRENT_TIMESTAMP | 생성 시각 |
|
| created_at | TIMESTAMPTZ | YES | CURRENT_TIMESTAMP | 생성 시각 |
|
||||||
| updated_at | TIMESTAMPTZ | YES | CURRENT_TIMESTAMP | 수정 시각 |
|
| updated_at | TIMESTAMPTZ | YES | CURRENT_TIMESTAMP | 수정 시각 |
|
||||||
|
|
||||||
|
### rb_news
|
||||||
|
- **용도**: 뉴스 발행 관리
|
||||||
|
- **Primary Key**: id (UUID)
|
||||||
|
|
||||||
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|
|--------|------|------|--------|------|
|
||||||
|
| id | UUID | NO | gen_random_uuid() | 뉴스 ID |
|
||||||
|
| title | TEXT | NO | | 뉴스 제목 |
|
||||||
|
| url | TEXT | NO | | 뉴스 URL (UNIQUE) |
|
||||||
|
| summary | TEXT | YES | | 뉴스 요약 |
|
||||||
|
| slack_message_ts | VARCHAR(100) | YES | | Slack 메시지 타임스탬프 |
|
||||||
|
| slack_channel_id | VARCHAR(100) | YES | | Slack 채널 ID |
|
||||||
|
| is_published | BOOLEAN | YES | false | 발행 상태 |
|
||||||
|
| published_at | TIMESTAMPTZ | YES | | 발행 시각 |
|
||||||
|
| created_at | TIMESTAMPTZ | YES | now() | 생성 시각 |
|
||||||
|
|
||||||
|
**인덱스**:
|
||||||
|
- `rb_news_pkey`: PRIMARY KEY (id)
|
||||||
|
- `rb_news_url_key`: UNIQUE (url)
|
||||||
|
- `idx_rb_news_url`: btree (url)
|
||||||
|
- `idx_rb_news_slack_message_ts`: btree (slack_message_ts)
|
||||||
|
- `idx_rb_news_created_at`: btree (created_at DESC)
|
||||||
|
|
||||||
### team_document
|
### team_document
|
||||||
- **용도**: 팀 문서 RAG 시스템
|
- **용도**: 팀 문서 RAG 시스템
|
||||||
- **Primary Key**: id (UUID)
|
- **Primary Key**: id (UUID)
|
||||||
- **레코드**: 0개
|
|
||||||
- **생성일**: 2025-09-15
|
|
||||||
|
|
||||||
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|--------|------|------|--------|------|
|
|--------|------|------|--------|------|
|
||||||
@ -238,9 +248,8 @@
|
|||||||
### naverworks_token
|
### naverworks_token
|
||||||
- **용도**: NAVER WORKS OAuth 토큰 및 Passport 정보
|
- **용도**: NAVER WORKS OAuth 토큰 및 Passport 정보
|
||||||
- **Primary Key**: id (UUID)
|
- **Primary Key**: id (UUID)
|
||||||
- **Unique**: user_id (사용자당 하나의 토큰만)
|
- **Unique**: user_id
|
||||||
- **Foreign Key**: user_id → user(id) ON DELETE CASCADE
|
- **Foreign Key**: user_id → user(id) ON DELETE CASCADE
|
||||||
- **레코드**: 1개 (2025-09-18 기준)
|
|
||||||
|
|
||||||
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
| 컬럼명 | 타입 | NULL | 기본값 | 설명 |
|
||||||
|--------|------|------|--------|------|
|
|--------|------|------|--------|------|
|
||||||
@ -304,14 +313,6 @@
|
|||||||
- **자동 갱신**: update_column_updated_at 트리거로 updated_at 자동 관리
|
- **자동 갱신**: update_column_updated_at 트리거로 updated_at 자동 관리
|
||||||
- **UUID 기반**: 주요 테이블 모두 UUID 사용
|
- **UUID 기반**: 주요 테이블 모두 UUID 사용
|
||||||
|
|
||||||
### 현재 데이터 상태 (2025-09-11)
|
|
||||||
- company: 2개
|
|
||||||
- team: 2개
|
|
||||||
- user: 1개
|
|
||||||
- product: 1개
|
|
||||||
- robeing: 2개
|
|
||||||
- slack_workspace: 2개
|
|
||||||
- 나머지 테이블: 비어있음
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
70
troubleshooting/250922_current_system_status_summary.md
Normal file
70
troubleshooting/250922_current_system_status_summary.md
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# 현재 시스템 상태 트러블슈팅 요약
|
||||||
|
|
||||||
|
## 일시: 2025-09-22
|
||||||
|
## 작성자: 51123 서버 관리자
|
||||||
|
|
||||||
|
## 🔴 긴급 수정 필요 (Quick Wins)
|
||||||
|
|
||||||
|
### 1. rb8001 EmailIntegration 버그
|
||||||
|
- **위치**: `rb8001/app/skills/email_integration.py:210`
|
||||||
|
- **문제**: NaverWorks 토큰 조회 시 미정의 변수 `user_uuid` 사용
|
||||||
|
- **수정**: `user_uuid` → `slack_id` 또는 `user_id`로 변경
|
||||||
|
- **영향**: NaverWorks 이메일 기능 오류
|
||||||
|
|
||||||
|
### 2. UUID↔Slack ID 조회 엔드포인트 불일치
|
||||||
|
- **문제**: gateway는 `/api/slack/{slack_id}/uuid`, 다른 서비스는 `/api/slack/mapping/{identifier}` 사용
|
||||||
|
- **위치**: `robeing-gateway/app/main.py:468-515`
|
||||||
|
- **수정**: 하나의 엔드포인트로 통일 필요
|
||||||
|
|
||||||
|
### 3. 하드코딩 URL 제거
|
||||||
|
- **위치**: `rb8001/app/skills/email_integration.py:39-47`
|
||||||
|
- **문제**: `http://192.168.219.45:9000` 하드코딩
|
||||||
|
- **수정**: 환경변수로 교체 필요
|
||||||
|
|
||||||
|
## 🟠 시스템 로그 분석 결과
|
||||||
|
|
||||||
|
### nginx 문제점
|
||||||
|
- 9월 16일 로그 권한 오류 (logrotate 시점)
|
||||||
|
- SSL handshake 오류 지속 (외부 스캔봇)
|
||||||
|
- upstream 연결 실패 (8000 vs 8100 포트 혼재)
|
||||||
|
|
||||||
|
### 서비스 상태
|
||||||
|
- **auth-server**: 정상 (불필요한 "default_value" 로그 출력)
|
||||||
|
- **robeing-gateway**: 정상 (과도한 헬스체크 빈도)
|
||||||
|
- **skill-news**: JSON 파일 수집 정상, DB 영속화 미동작
|
||||||
|
|
||||||
|
### 보안 이슈
|
||||||
|
- Git 저장소 무단 접근 시도 (220.85.143.195)
|
||||||
|
- PHPUnit 취약점 스캔 지속
|
||||||
|
- Slack webhook 이벤트 처리 간헐적 실패
|
||||||
|
|
||||||
|
## 🟡 DB 및 데이터 상태
|
||||||
|
|
||||||
|
### rb_news 테이블
|
||||||
|
- 테이블 생성됨
|
||||||
|
- skill-news JSON 파일에 데이터 있음 (컴퍼니엑스 뉴스 1건)
|
||||||
|
- DB 저장 로직 미동작 확인 필요
|
||||||
|
|
||||||
|
### robeing_stats
|
||||||
|
- robeing-monitor로 일원화 완료
|
||||||
|
- rb8001 중복 구현 제거됨
|
||||||
|
|
||||||
|
### system_metrics
|
||||||
|
- 테이블 미존재로 수집 비활성화
|
||||||
|
- frontend-base에서 early return 처리
|
||||||
|
|
||||||
|
## ✅ 완료된 항목 (검증됨)
|
||||||
|
|
||||||
|
1. **GmailProvider 메서드 매핑**: `list_messages→get_recent_messages` 래핑 구현
|
||||||
|
2. **Stats API 일원화**: robeing-monitor 도입 및 사용
|
||||||
|
3. **RAG 파일 스킬**: 포트 8508, 컬렉션 명명 규칙 적용 완료
|
||||||
|
4. **NaverWorks 통합**: skill-email에서 provider=naverworks 지원
|
||||||
|
5. **Slack 봇 설치 플로우**: passport/install/callback 엔드포인트 구현
|
||||||
|
6. **GEMINI CLI 타임아웃**: GEMINI_USE_CLI=False 기본값
|
||||||
|
|
||||||
|
## 📊 현재 운영 상태
|
||||||
|
|
||||||
|
- **51123 서버**: nginx, auth-server, gateway 정상 운영
|
||||||
|
- **51124 서버**: rb8001, skill 서비스들 정상 운영
|
||||||
|
- **포트 상태**: 8100(gateway), 9000(auth) 정상 리스닝
|
||||||
|
- **Docker 컨테이너**: 모든 서비스 healthy 상태
|
||||||
@ -1,6 +1,7 @@
|
|||||||
# UUID 체계 전환 및 대화 저장 오류 해결
|
# UUID 체계 전환 및 대화 저장 오류 해결
|
||||||
|
|
||||||
## 작성일: 2025-09-11
|
## 작성일: 2025-09-11
|
||||||
|
## 최종 수정일: 2025-09-24
|
||||||
## 작성자: happybell80
|
## 작성자: happybell80
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -22,39 +23,16 @@
|
|||||||
## 해결 과정
|
## 해결 과정
|
||||||
|
|
||||||
### 1. rb8001 UUID 체계 전환
|
### 1. rb8001 UUID 체계 전환
|
||||||
```python
|
- app/router/router.py: X-User-Id 헤더 우선 사용 처리
|
||||||
# app/router/router.py - X-User-Id 헤더 우선 사용
|
|
||||||
if request and hasattr(request, 'headers'):
|
|
||||||
x_user_id = request.headers.get('X-User-Id')
|
|
||||||
if x_user_id and self.is_valid_uuid(x_user_id):
|
|
||||||
final_uuid = x_user_id
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. conversation_log id 자동증가 해결
|
### 2. conversation_log id 자동증가 해결
|
||||||
```python
|
- 테이블에 SERIAL 없어 MAX(id)+1로 수동 생성
|
||||||
# 테이블에 SERIAL 없어서 명시적 생성
|
|
||||||
max_id_result = db.execute(text("SELECT COALESCE(MAX(id), 0) FROM conversation_log"))
|
|
||||||
next_id = max_id_result.scalar() + 1
|
|
||||||
conversation_log = ConversationLog(id=next_id, ...)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Gateway Slack ID→UUID 변환
|
### 3. Gateway Slack ID→UUID 변환
|
||||||
```sql
|
- oauth_id와 oauth_provider='slack' 조건으로 조회
|
||||||
-- 잘못된 쿼리 (username 사용)
|
|
||||||
WHERE u.username = :slack_user_id
|
|
||||||
|
|
||||||
-- 올바른 쿼리 (oauth_id 사용)
|
|
||||||
WHERE u.oauth_id = :slack_user_id AND u.oauth_provider = 'slack'
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Slack Handler UUID 처리
|
### 4. Slack Handler UUID 처리
|
||||||
```python
|
- X-User-Id 헤더에서 UUID 추출 및 context 저장
|
||||||
# X-User-Id 헤더에서 UUID 추출
|
|
||||||
user_uuid = request.headers.get("X-User-Id")
|
|
||||||
if user_uuid:
|
|
||||||
context["user_uuid"] = user_uuid
|
|
||||||
context["original_slack_id"] = user_id # 원본 보존
|
|
||||||
```
|
|
||||||
|
|
||||||
## 데이터 흐름 정리
|
## 데이터 흐름 정리
|
||||||
|
|
||||||
@ -82,19 +60,47 @@ if user_uuid:
|
|||||||
|
|
||||||
## 추가 수정 사항
|
## 추가 수정 사항
|
||||||
### 뉴스 중복 방지
|
### 뉴스 중복 방지
|
||||||
```python
|
- skill-news fallback 제거: 새 뉴스 없을 때 API 호출 제거
|
||||||
# skill-news fallback 제거 - dm_skill.py
|
|
||||||
# 새 뉴스 없을 때 /api/news/latest 호출 제거
|
|
||||||
return ("오늘의 새로운 뉴스가 없습니다.", [])
|
|
||||||
```
|
|
||||||
|
|
||||||
### 헬스체크 로그 레벨 조정
|
### 헬스체크 로그 레벨 조정
|
||||||
```python
|
- DEBUG 레벨로 변경하여 로그 노이즈 감소
|
||||||
# DEBUG 레벨로 변경 - main.py
|
|
||||||
logger.debug(f"Health check passed for {settings.ROBEING_ID}")
|
|
||||||
```
|
|
||||||
|
|
||||||
## 교훈
|
## 교훈
|
||||||
- DB 스키마와 코드 모델 일치 필수
|
- DB 스키마와 코드 모델 일치 필수
|
||||||
- UUID 체계 전환 시 모든 경로 점검
|
- UUID 체계 전환 시 모든 경로 점검
|
||||||
- 헤더 기반 인증 정보는 일관된 위치에서 처리
|
- 헤더 기반 인증 정보는 일관된 위치에서 처리
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2025-09-24 추가 수정: Slack UUID 변환 실패 시 에러 처리
|
||||||
|
|
||||||
|
### 문제 상황
|
||||||
|
- Gateway에서 Slack ID를 UUID로 변환 실패 시 경고만 출력하고 요청 계속 진행
|
||||||
|
- rb8001에서 X-User-Id 헤더 없을 때 Slack ID를 UUID로 저장 시도하여 타입 오류 발생
|
||||||
|
|
||||||
|
### 해결 방안
|
||||||
|
|
||||||
|
#### 1. /home/admin/robeing-gateway/app/main.py 수정
|
||||||
|
|
||||||
|
**라인 526-532** - `/slack/events` 엔드포인트:
|
||||||
|
- 현재: 경고만 출력
|
||||||
|
- 수정: UUID 없으면 403 에러 반환
|
||||||
|
|
||||||
|
**라인 583-585** - `/slack/interactive` 엔드포인트:
|
||||||
|
- 동일하게 UUID 변환 실패 시 403 에러 반환
|
||||||
|
|
||||||
|
#### 2. /home/admin/robeing-gateway/app/database.py 수정 (선택사항)
|
||||||
|
|
||||||
|
**라인 376-381** - `slack_user_to_uuid` 함수:
|
||||||
|
- 현재: None 반환
|
||||||
|
- 선택적 수정: ValueError 예외 발생
|
||||||
|
|
||||||
|
### 기대 효과
|
||||||
|
- Slack 사용자가 시스템에 등록되지 않은 경우 명확한 에러 메시지 반환
|
||||||
|
- 잘못된 UUID로 인한 데이터 오염 방지
|
||||||
|
- 디버깅 시간 단축 (명확한 에러로 원인 파악 용이)
|
||||||
|
|
||||||
|
### 관련 문제
|
||||||
|
- Slack 요청은 OAuth 인증 없이 직접 `/slack/events`로 전송
|
||||||
|
- JWT 토큰 없이 Slack 웹훅이 직접 호출
|
||||||
|
- DB에서 oauth_id로 UUID 조회 시 oauth_provider='slack' 조건 필수
|
||||||
Loading…
x
Reference in New Issue
Block a user