Fix incorrect table names in documentation
- gmail_tokens → gmail_token (33 files) - companies → company (17 files) - conversation_logs → conversation_log (27 files) - workspace_members → workspace_member (28 files) All table names now match the actual PostgreSQL schema
This commit is contained in:
parent
58153a49a0
commit
8c02b80359
@ -91,7 +91,7 @@
|
||||
users: id(UUID), username, email, name, created_at
|
||||
|
||||
-- Gmail 토큰 (아이템)
|
||||
gmail_tokens: id, user_id, email, is_equipped, equipped_to
|
||||
gmail_token: id, user_id, email, is_equipped, equipped_to
|
||||
|
||||
-- Gmail 감사 로그
|
||||
gmail_audit_logs: id, user_id, robeing_id, action, created_at
|
||||
|
||||
@ -213,7 +213,7 @@ async def show_typing(channel: str):
|
||||
-- 대신 users 테이블에서 직접 관리
|
||||
|
||||
-- 대화 로그
|
||||
CREATE TABLE conversation_logs (
|
||||
CREATE TABLE conversation_log (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID, -- slack_user_mapping에서 조회한 UUID
|
||||
robeing_id VARCHAR(50),
|
||||
|
||||
@ -61,7 +61,7 @@
|
||||
- PRIMARY KEY (slack_user_id, slack_workspace_id)
|
||||
```
|
||||
|
||||
#### gmail_tokens 테이블
|
||||
#### gmail_token 테이블
|
||||
```sql
|
||||
- id: UUID
|
||||
- user_id: UUID (FK → users.id)
|
||||
@ -114,7 +114,7 @@ sequenceDiagram
|
||||
- Slack도 임시 코드 방식으로 맞춤
|
||||
|
||||
2. **DB 스키마 불일치**
|
||||
- companies vs workspaces 테이블 공존
|
||||
- company vs workspaces 테이블 공존
|
||||
- relationship 주석 처리
|
||||
|
||||
3. **하드코딩된 값**
|
||||
@ -138,7 +138,7 @@ sequenceDiagram
|
||||
### 특징
|
||||
- **원페이지 복귀**: OAuth 인증 후 원래 있던 페이지로 자동 복귀
|
||||
- **상태 관리**: state 파라미터에 return_url 포함하여 전달
|
||||
- **토큰 저장**: gmail_tokens 테이블에 암호화 저장
|
||||
- **토큰 저장**: gmail_token 테이블에 암호화 저장
|
||||
|
||||
## 보안 고려사항
|
||||
|
||||
@ -185,7 +185,7 @@ DATABASE_URL=postgresql://robeings:password@localhost/main_db
|
||||
## 향후 개선 계획
|
||||
|
||||
### 단기 (1-2주)
|
||||
1. DB 스키마 통일 (companies → workspaces)
|
||||
1. DB 스키마 통일 (company → workspaces)
|
||||
2. Frontend 인증 방식 통일
|
||||
3. 환경변수 정리
|
||||
|
||||
|
||||
@ -83,7 +83,7 @@ psql -h localhost -p 5432 -U robeings -d main_db
|
||||
\dt
|
||||
|
||||
-- 특정 테이블 구조 보기
|
||||
\d gmail_tokens
|
||||
\d gmail_token
|
||||
\d users
|
||||
|
||||
-- 데이터베이스 목록
|
||||
@ -160,9 +160,9 @@ CREATE TABLE users (
|
||||
);
|
||||
```
|
||||
|
||||
### 2. gmail_tokens 테이블
|
||||
### 2. gmail_token 테이블
|
||||
```sql
|
||||
CREATE TABLE gmail_tokens (
|
||||
CREATE TABLE gmail_token (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id UUID REFERENCES users(id),
|
||||
slack_id VARCHAR(100), -- Slack 사용자 ID (새로 추가)
|
||||
@ -184,9 +184,9 @@ CREATE TABLE gmail_tokens (
|
||||
);
|
||||
```
|
||||
|
||||
### 3. conversation_logs 테이블
|
||||
### 3. conversation_log 테이블
|
||||
```sql
|
||||
CREATE TABLE conversation_logs (
|
||||
CREATE TABLE conversation_log (
|
||||
id SERIAL PRIMARY KEY,
|
||||
robeing_id VARCHAR,
|
||||
channel_id VARCHAR,
|
||||
@ -235,7 +235,7 @@ query = """
|
||||
g.robeing_id,
|
||||
g.token_data,
|
||||
g.scopes
|
||||
FROM gmail_tokens g
|
||||
FROM gmail_token g
|
||||
JOIN users u ON g.user_id = u.id
|
||||
ORDER BY g.created_at DESC
|
||||
"""
|
||||
@ -308,7 +308,7 @@ def add_gmail_token(slack_user_id, email, access_token, refresh_token):
|
||||
ON CONFLICT (id) DO UPDATE SET email = EXCLUDED.email
|
||||
""", (user_uuid, email, slack_user_id))
|
||||
|
||||
# 2. gmail_tokens 추가 또는 업데이트
|
||||
# 2. gmail_token 추가 또는 업데이트
|
||||
token_data = {
|
||||
"access_token": access_token,
|
||||
"refresh_token": refresh_token,
|
||||
@ -316,7 +316,7 @@ def add_gmail_token(slack_user_id, email, access_token, refresh_token):
|
||||
}
|
||||
|
||||
cur.execute("""
|
||||
INSERT INTO gmail_tokens (user_id, token_data, is_equipped, robeing_id, created_at)
|
||||
INSERT INTO gmail_token (user_id, token_data, is_equipped, robeing_id, created_at)
|
||||
VALUES (%s, %s::jsonb, true, 'rb8001', NOW())
|
||||
ON CONFLICT (user_id) DO UPDATE
|
||||
SET token_data = EXCLUDED.token_data,
|
||||
|
||||
@ -42,8 +42,8 @@ psql postgresql://robeings:robeings@localhost:5433/main_db
|
||||
```
|
||||
|
||||
## 최근 변경사항
|
||||
- 2025-08-26: conversation_logs에 slack_user_id 추가
|
||||
- 2025-08-23: gmail_tokens 구조 변경
|
||||
- 2025-08-26: conversation_log에 slack_user_id 추가
|
||||
- 2025-08-23: gmail_token 구조 변경
|
||||
- 2025-08-20: auth_db → main_db 마이그레이션
|
||||
|
||||
## 최종 업데이트
|
||||
|
||||
@ -8,22 +8,22 @@
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
users ||--o{ workspace_members : "has many"
|
||||
users ||--o{ workspace_member : "has many"
|
||||
users ||--o{ slack_user_mapping : "has many"
|
||||
users ||--o{ gmail_tokens : "has"
|
||||
users ||--o{ gmail_token : "has"
|
||||
users ||--o{ robeing_stats : "has"
|
||||
users ||--o{ conversation_logs : "has many"
|
||||
users ||--o{ conversation_log : "has many"
|
||||
|
||||
workspaces ||--o{ workspace_members : "has many"
|
||||
workspaces }o--|| companies : "belongs to"
|
||||
workspaces ||--o{ workspace_member : "has many"
|
||||
workspaces }o--|| company : "belongs to"
|
||||
|
||||
slack_workspaces ||--o{ slack_user_mapping : "has many"
|
||||
|
||||
workspace_members ||--o{ slack_user_mapping : "references"
|
||||
workspace_member ||--o{ slack_user_mapping : "references"
|
||||
|
||||
gmail_tokens }o--|| users : "belongs to"
|
||||
gmail_token }o--|| users : "belongs to"
|
||||
robeing_stats }o--|| users : "belongs to"
|
||||
conversation_logs }o--|| users : "belongs to"
|
||||
conversation_log }o--|| users : "belongs to"
|
||||
```
|
||||
|
||||
---
|
||||
@ -32,11 +32,11 @@ erDiagram
|
||||
|
||||
### 1. User 중심 관계
|
||||
```
|
||||
users (1) ─────┬──── (*) workspace_members
|
||||
users (1) ─────┬──── (*) workspace_member
|
||||
├──── (*) slack_user_mapping
|
||||
├──── (0..1) gmail_tokens
|
||||
├──── (0..1) gmail_token
|
||||
├──── (0..1) robeing_stats
|
||||
└──── (*) conversation_logs
|
||||
└──── (*) conversation_log
|
||||
```
|
||||
|
||||
- 한 사용자는 여러 워크스페이스의 멤버가 될 수 있음
|
||||
@ -47,8 +47,8 @@ users (1) ─────┬──── (*) workspace_members
|
||||
|
||||
### 2. Workspace 관계
|
||||
```
|
||||
companies (1) ──── (*) workspaces
|
||||
workspaces (1) ──── (*) workspace_members
|
||||
company (1) ──── (*) workspaces
|
||||
workspaces (1) ──── (*) workspace_member
|
||||
```
|
||||
|
||||
- 한 회사는 여러 워크스페이스를 가질 수 있음
|
||||
@ -58,11 +58,11 @@ workspaces (1) ──── (*) workspace_members
|
||||
```
|
||||
slack_workspaces (1) ──── (*) slack_user_mapping
|
||||
slack_user_mapping (*) ──── (1) users
|
||||
slack_user_mapping (*) ──── (0..1) workspace_members
|
||||
slack_user_mapping (*) ──── (0..1) workspace_member
|
||||
```
|
||||
|
||||
- Slack 사용자 ID를 시스템 UUID로 변환하는 브릿지 역할
|
||||
- workspace_members와 선택적 연결
|
||||
- workspace_member와 선택적 연결
|
||||
|
||||
---
|
||||
|
||||
@ -79,9 +79,9 @@ SELECT
|
||||
sum.slack_user_id,
|
||||
gt.is_equipped as gmail_equipped
|
||||
FROM users u
|
||||
LEFT JOIN workspace_members wm ON u.id = wm.user_id
|
||||
LEFT JOIN workspace_member wm ON u.id = wm.user_id
|
||||
LEFT JOIN slack_user_mapping sum ON u.id = sum.user_id
|
||||
LEFT JOIN gmail_tokens gt ON u.id = gt.user_id
|
||||
LEFT JOIN gmail_token gt ON u.id = gt.user_id
|
||||
WHERE u.username = 'happybell80';
|
||||
```
|
||||
|
||||
@ -108,7 +108,7 @@ SELECT
|
||||
rs.level,
|
||||
gt.scopes
|
||||
FROM users u
|
||||
JOIN gmail_tokens gt ON u.id = gt.user_id
|
||||
JOIN gmail_token gt ON u.id = gt.user_id
|
||||
LEFT JOIN robeing_stats rs ON u.id = rs.user_id
|
||||
WHERE gt.is_equipped = true;
|
||||
```
|
||||
@ -122,7 +122,7 @@ SELECT
|
||||
wm.role,
|
||||
wm.robeing_id
|
||||
FROM workspaces w
|
||||
JOIN workspace_members wm ON w.id = wm.workspace_id
|
||||
JOIN workspace_member wm ON w.id = wm.workspace_id
|
||||
JOIN users u ON wm.user_id = u.id
|
||||
WHERE w.name = 'Ivada Robeing';
|
||||
```
|
||||
@ -148,7 +148,7 @@ user_id (UUID) 획득
|
||||
```
|
||||
User 요청
|
||||
↓
|
||||
user_id (UUID)로 gmail_tokens 조회
|
||||
user_id (UUID)로 gmail_token 조회
|
||||
↓
|
||||
is_equipped 확인
|
||||
↓
|
||||
@ -202,10 +202,10 @@ BEGIN;
|
||||
SELECT level FROM robeing_stats WHERE user_id = ?;
|
||||
|
||||
-- 2. 소유권 확인
|
||||
SELECT id FROM gmail_tokens WHERE user_id = ?;
|
||||
SELECT id FROM gmail_token WHERE user_id = ?;
|
||||
|
||||
-- 3. 장착 처리
|
||||
UPDATE gmail_tokens
|
||||
UPDATE gmail_token
|
||||
SET is_equipped = true, equipped_to = ?
|
||||
WHERE user_id = ?;
|
||||
|
||||
@ -223,8 +223,8 @@ BEGIN;
|
||||
INSERT INTO users (id, email, name, username)
|
||||
VALUES (?, ?, ?, ?);
|
||||
|
||||
-- 2. workspace_members 추가
|
||||
INSERT INTO workspace_members (user_id, workspace_id, role)
|
||||
-- 2. workspace_member 추가
|
||||
INSERT INTO workspace_member (user_id, workspace_id, role)
|
||||
VALUES (?, ?, 'member');
|
||||
|
||||
-- 3. robeing_stats 초기화
|
||||
|
||||
@ -315,7 +315,7 @@ stateDiagram-v2
|
||||
- username (사용자 정의 또는 자동 생성)
|
||||
|
||||
관계:
|
||||
- users.id (UUID) ← gmail_tokens.user_id
|
||||
- users.id (UUID) ← gmail_token.user_id
|
||||
- users.id (UUID) ← slack_user_mapping.user_id
|
||||
- users.id (UUID) ← robeing_stats.user_id
|
||||
|
||||
|
||||
@ -20,10 +20,10 @@ sequenceDiagram
|
||||
F->>G: GET /gateway/api/history?limit=30<br/>Authorization: Bearer {JWT}
|
||||
G->>G: JWT 검증 (서명, 만료시간)
|
||||
G->>G: JWT에서 sub(UUID) 추출
|
||||
G->>G: workspace_members 테이블 조회<br/>robeing_id 확인 (rb8001)
|
||||
G->>G: workspace_member 테이블 조회<br/>robeing_id 확인 (rb8001)
|
||||
G->>R: GET /api/history?limit=30<br/>Authorization: Bearer {JWT}<br/>X-User-Id: {UUID}
|
||||
R->>R: JWT 검증 및 user_id 추출
|
||||
R->>DB: SELECT * FROM conversation_logs<br/>WHERE user_id = (:user_id)::uuid
|
||||
R->>DB: SELECT * FROM conversation_log<br/>WHERE user_id = (:user_id)::uuid
|
||||
DB-->>R: 대화 기록 반환
|
||||
R->>R: DB row를 Frontend 형식으로 변환<br/>(user/robeing 메시지 분리)
|
||||
R-->>G: {"messages": [...], "has_more": true}
|
||||
@ -66,8 +66,8 @@ def verify_jwt_token(token: str):
|
||||
|
||||
### 3.2 robeing 라우팅
|
||||
```python
|
||||
# workspace_members 테이블 조회
|
||||
SELECT robeing_id FROM workspace_members
|
||||
# workspace_member 테이블 조회
|
||||
SELECT robeing_id FROM workspace_member
|
||||
WHERE user_id = :user_id
|
||||
|
||||
# 결과: rb8001 또는 rb10508_micro
|
||||
@ -100,7 +100,7 @@ async def get_current_user(authorization: str = Header(None)):
|
||||
async def get_paginated_conversations(user_id: str, before: float = None, limit: int = 30):
|
||||
query = """
|
||||
SELECT id, message, response, timestamp
|
||||
FROM conversation_logs
|
||||
FROM conversation_log
|
||||
WHERE user_id = (:user_id)::uuid
|
||||
AND robeing_id = 'rb8001'
|
||||
AND (:before::timestamp IS NULL OR timestamp < :before)
|
||||
@ -175,18 +175,18 @@ CREATE TABLE users (
|
||||
);
|
||||
```
|
||||
|
||||
### 6.2 workspace_members 테이블
|
||||
### 6.2 workspace_member 테이블
|
||||
```sql
|
||||
CREATE TABLE workspace_members (
|
||||
CREATE TABLE workspace_member (
|
||||
user_id UUID REFERENCES users(id),
|
||||
workspace_id UUID,
|
||||
robeing_id VARCHAR(50) -- rb8001, rb10508_micro 등
|
||||
);
|
||||
```
|
||||
|
||||
### 6.3 conversation_logs 테이블
|
||||
### 6.3 conversation_log 테이블
|
||||
```sql
|
||||
CREATE TABLE conversation_logs (
|
||||
CREATE TABLE conversation_log (
|
||||
id INTEGER PRIMARY KEY,
|
||||
robeing_id VARCHAR,
|
||||
message VARCHAR,
|
||||
|
||||
@ -64,13 +64,13 @@ sequenceDiagram
|
||||
DM->>Email: GET /messages<br/>?user_id={slack_id}<br/>&limit=5<br/>&query=category:primary
|
||||
|
||||
%% 토큰 체크 및 갱신
|
||||
Email->>DB: SELECT * FROM gmail_tokens<br/>WHERE user_id = ?
|
||||
Email->>DB: SELECT * FROM gmail_token<br/>WHERE user_id = ?
|
||||
DB-->>Email: token_data, refresh_token
|
||||
|
||||
alt 토큰 만료
|
||||
Email->>Auth: POST /api/gmail/refresh<br/>Body: {user_id, refresh_token}
|
||||
Auth->>Auth: Google OAuth 토큰 갱신
|
||||
Auth->>DB: UPDATE gmail_tokens
|
||||
Auth->>DB: UPDATE gmail_token
|
||||
Auth-->>Email: 새 access_token
|
||||
end
|
||||
|
||||
@ -127,7 +127,7 @@ sequenceDiagram
|
||||
rect rgb(255, 230, 230)
|
||||
Note over DM,Email: 이메일 수집 실패
|
||||
DM->>Email: GET /messages
|
||||
Email->>DB: SELECT gmail_tokens
|
||||
Email->>DB: SELECT gmail_token
|
||||
DB-->>Email: token_data: NULL ❌
|
||||
Email-->>DM: 500 Internal Server Error
|
||||
Note over DM: 이메일 데이터 = []
|
||||
@ -199,7 +199,7 @@ docker logs rb8001 --tail 100 | grep daily-summary
|
||||
docker logs skill-email --tail 50 | grep ERROR
|
||||
|
||||
# DB 토큰 상태
|
||||
psql -U robeings -d main_db -c "SELECT user_id, token_data IS NOT NULL as has_token FROM gmail_tokens;"
|
||||
psql -U robeings -d main_db -c "SELECT user_id, token_data IS NOT NULL as has_token FROM gmail_token;"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@ -53,7 +53,7 @@ sequenceDiagram
|
||||
Auth->>Google: 토큰 교환 요청
|
||||
Google-->>Auth: access_token, refresh_token
|
||||
|
||||
Auth->>DB: gmail_tokens 테이블 저장
|
||||
Auth->>DB: gmail_token 테이블 저장
|
||||
Note over DB: user_id, email,<br/>tokens (암호화),<br/>scopes, metadata
|
||||
|
||||
Auth->>Auth: 리다이렉트 URL 결정
|
||||
@ -121,7 +121,7 @@ sequenceDiagram
|
||||
|
||||
Gateway->>Monitor: 아이템 목록 요청
|
||||
Note over Monitor: X-User-Id 헤더로<br/>UUID 전달
|
||||
Monitor->>DB: gmail_tokens 조회
|
||||
Monitor->>DB: gmail_token 조회
|
||||
Note over DB: user_id로 필터링
|
||||
|
||||
Monitor->>DB: robeing_stats 조회
|
||||
@ -153,7 +153,7 @@ sequenceDiagram
|
||||
Gateway-->>Front: 레벨 부족 에러
|
||||
Front->>Front: "레벨 5가 되면<br/>사용 가능해요!" 표시
|
||||
else 레벨 >= 5
|
||||
Monitor->>DB: gmail_tokens 업데이트
|
||||
Monitor->>DB: gmail_token 업데이트
|
||||
Note over DB: is_equipped = true<br/>equipped_to = "rb10508_micro"
|
||||
|
||||
Monitor->>DB: gmail_audit_logs 기록
|
||||
@ -203,7 +203,7 @@ sequenceDiagram
|
||||
|
||||
RB->>Monitor: GET /api/items/gmail/status
|
||||
Note over Monitor: 장착 상태 확인
|
||||
Monitor->>DB: gmail_tokens 조회
|
||||
Monitor->>DB: gmail_token 조회
|
||||
DB-->>Monitor: 장착 정보
|
||||
|
||||
alt Gmail 아이템 미장착
|
||||
@ -216,7 +216,7 @@ sequenceDiagram
|
||||
RB->>Skill: POST /send-email
|
||||
Note over Skill: user_id, to,<br/>subject, body
|
||||
|
||||
Skill->>DB: gmail_tokens 조회
|
||||
Skill->>DB: gmail_token 조회
|
||||
Note over DB: user_id와 is_equipped 확인
|
||||
DB-->>Skill: access_token (복호화)
|
||||
|
||||
@ -232,7 +232,7 @@ sequenceDiagram
|
||||
Gmail-->>Skill: 발송 성공 (message_id)
|
||||
|
||||
Skill->>DB: 발송 로그 저장
|
||||
Note over DB: conversation_logs 또는<br/>email_send_history
|
||||
Note over DB: conversation_log 또는<br/>email_send_history
|
||||
|
||||
Skill-->>RB: 발송 결과
|
||||
RB->>DB: robeing_stats 경험치 증가
|
||||
@ -273,7 +273,7 @@ sequenceDiagram
|
||||
DB-->>RB: user_id, name: "김종태"
|
||||
|
||||
RB->>Monitor: Gmail 아이템 상태 확인
|
||||
Monitor->>DB: gmail_tokens 조회
|
||||
Monitor->>DB: gmail_token 조회
|
||||
|
||||
alt 아이템 미장착
|
||||
DB-->>Monitor: is_equipped = false
|
||||
@ -293,7 +293,7 @@ sequenceDiagram
|
||||
RB->>Skill: POST /send-email
|
||||
Note over Skill: to: goeun2dc@gmail.com<br/>subject: "회의 일정 안내"<br/>body: LLM 생성 내용
|
||||
|
||||
Skill->>DB: gmail_tokens 조회
|
||||
Skill->>DB: gmail_token 조회
|
||||
DB-->>Skill: access_token
|
||||
|
||||
Skill->>Gmail: 이메일 발송
|
||||
@ -302,7 +302,7 @@ sequenceDiagram
|
||||
Skill-->>RB: 발송 완료
|
||||
|
||||
RB->>DB: 대화 로그 저장
|
||||
Note over DB: conversation_logs에<br/>이메일 발송 기록
|
||||
Note over DB: conversation_log에<br/>이메일 발송 기록
|
||||
|
||||
RB-->>Slack: "종태님께 회의 일정 메일을<br/>발송했습니다."
|
||||
end
|
||||
@ -345,7 +345,7 @@ sequenceDiagram
|
||||
Auth->>Google: 토큰 교환
|
||||
Google-->>Auth: 새 access_token, refresh_token
|
||||
|
||||
Auth->>DB: gmail_tokens 업데이트
|
||||
Auth->>DB: gmail_token 업데이트
|
||||
Note over DB: 새 토큰으로 교체<br/>updated_at 갱신
|
||||
|
||||
Auth->>DB: gmail_audit_logs 기록
|
||||
@ -372,7 +372,7 @@ sequenceDiagram
|
||||
Slack->>RB: 이메일 요청
|
||||
|
||||
RB->>Monitor: Gmail 아이템 확인
|
||||
Monitor->>DB: gmail_tokens 조회
|
||||
Monitor->>DB: gmail_token 조회
|
||||
|
||||
DB-->>Monitor: 결과
|
||||
|
||||
@ -417,7 +417,7 @@ sequenceDiagram
|
||||
RB->>Skill: GET /list-emails
|
||||
Note over Skill: maxResults: 10<br/>q: "is:unread"
|
||||
|
||||
Skill->>DB: gmail_tokens 조회
|
||||
Skill->>DB: gmail_token 조회
|
||||
DB-->>Skill: access_token
|
||||
|
||||
Skill->>Gmail: GET /gmail/v1/users/me/messages
|
||||
@ -510,7 +510,7 @@ sequenceDiagram
|
||||
|
||||
## 데이터베이스 테이블
|
||||
|
||||
### gmail_tokens
|
||||
### gmail_token
|
||||
- id: UUID
|
||||
- user_id: UUID (users 테이블 참조)
|
||||
- robeing_id: VARCHAR (통일된 컬럼명)
|
||||
|
||||
@ -41,7 +41,7 @@ graph TB
|
||||
|
||||
subgraph Database
|
||||
PG[(PostgreSQL)]
|
||||
GT[gmail_tokens]
|
||||
GT[gmail_token]
|
||||
RS[robeing_stats]
|
||||
end
|
||||
|
||||
@ -87,7 +87,7 @@ sequenceDiagram
|
||||
Note over Gateway: JWT 토큰 검증
|
||||
Gateway->>Monitor: GET /api/items/gmail<br/>Header: X-User-Id
|
||||
|
||||
Monitor->>DB: SELECT * FROM gmail_tokens<br/>WHERE user_id = ?
|
||||
Monitor->>DB: SELECT * FROM gmail_token<br/>WHERE user_id = ?
|
||||
DB-->>Monitor: 토큰 데이터
|
||||
|
||||
Monitor->>Monitor: 아이템 상태 계산
|
||||
@ -152,7 +152,7 @@ sequenceDiagram
|
||||
Auth->>Google: 코드 → 토큰 교환
|
||||
Google-->>Auth: Access Token + Refresh Token
|
||||
|
||||
Auth->>DB: INSERT INTO gmail_tokens
|
||||
Auth->>DB: INSERT INTO gmail_token
|
||||
Note over DB: token_data, scopes,<br/>metadata (email 등)
|
||||
|
||||
Auth->>Front: 리다이렉트 /inventory?success=true
|
||||
@ -192,7 +192,7 @@ sequenceDiagram
|
||||
Monitor->>DB: 토큰 소유권 확인
|
||||
DB-->>Monitor: 토큰 존재 확인
|
||||
|
||||
Monitor->>DB: UPDATE gmail_tokens<br/>SET is_equipped = true,<br/>equipped_to = 'rb10508_micro'
|
||||
Monitor->>DB: UPDATE gmail_token<br/>SET is_equipped = true,<br/>equipped_to = 'rb10508_micro'
|
||||
DB-->>Monitor: 업데이트 완료
|
||||
|
||||
Monitor->>DB: INSERT INTO gmail_audit_logs
|
||||
@ -222,11 +222,11 @@ sequenceDiagram
|
||||
DB-->>Monitor: level: 3
|
||||
Monitor-->>Front: {error: "레벨 5 이상 필요"}
|
||||
else 토큰 없음
|
||||
Monitor->>DB: SELECT * FROM gmail_tokens
|
||||
Monitor->>DB: SELECT * FROM gmail_token
|
||||
DB-->>Monitor: null
|
||||
Monitor-->>Front: {error: "Gmail 연결 필요"}
|
||||
else 이미 장착됨
|
||||
Monitor->>DB: SELECT is_equipped FROM gmail_tokens
|
||||
Monitor->>DB: SELECT is_equipped FROM gmail_token
|
||||
DB-->>Monitor: is_equipped: true
|
||||
Monitor-->>Front: {error: "이미 장착됨"}
|
||||
end
|
||||
@ -254,7 +254,7 @@ sequenceDiagram
|
||||
RB->>Monitor: GET /api/items/gmail
|
||||
Note over Monitor: Header: X-User-Id
|
||||
|
||||
Monitor->>DB: SELECT * FROM gmail_tokens<br/>WHERE user_id = ?
|
||||
Monitor->>DB: SELECT * FROM gmail_token<br/>WHERE user_id = ?
|
||||
DB-->>Monitor: 토큰 데이터
|
||||
|
||||
Monitor-->>RB: {equipped: {is_equipped: true,<br/>capabilities: {send: true, read: true}}}
|
||||
@ -263,7 +263,7 @@ sequenceDiagram
|
||||
RB->>SE: POST /process
|
||||
Note over SE: message: "최근 이메일 확인"
|
||||
|
||||
SE->>DB: SELECT token_data FROM gmail_tokens
|
||||
SE->>DB: SELECT token_data FROM gmail_token
|
||||
DB-->>SE: OAuth 토큰
|
||||
|
||||
SE->>SE: Gmail API 호출
|
||||
@ -314,7 +314,7 @@ sequenceDiagram
|
||||
User->>Front: "해제" 버튼 클릭
|
||||
Front->>Monitor: POST /api/items/gmail/{userId}/unequip
|
||||
|
||||
Monitor->>DB: UPDATE gmail_tokens<br/>SET is_equipped = false,<br/>equipped_to = null
|
||||
Monitor->>DB: UPDATE gmail_token<br/>SET is_equipped = false,<br/>equipped_to = null
|
||||
DB-->>Monitor: 업데이트 완료
|
||||
|
||||
Monitor->>DB: INSERT INTO gmail_audit_logs
|
||||
@ -367,7 +367,7 @@ sequenceDiagram
|
||||
Note over Front: 페이지 새로고침
|
||||
|
||||
Front->>Monitor: GET /api/items/gmail
|
||||
Monitor->>DB: SELECT * FROM gmail_tokens
|
||||
Monitor->>DB: SELECT * FROM gmail_token
|
||||
DB-->>Monitor: is_equipped: true
|
||||
|
||||
Monitor-->>Front: 장착 상태 반환
|
||||
@ -384,14 +384,14 @@ sequenceDiagram
|
||||
participant Auth as auth-server
|
||||
participant Google as Google OAuth
|
||||
|
||||
SE->>DB: SELECT token_data FROM gmail_tokens
|
||||
SE->>DB: SELECT token_data FROM gmail_token
|
||||
DB-->>SE: 토큰 (만료됨)
|
||||
|
||||
SE->>Auth: 토큰 갱신 요청
|
||||
Auth->>Google: Refresh Token 사용
|
||||
Google-->>Auth: 새 Access Token
|
||||
|
||||
Auth->>DB: UPDATE gmail_tokens<br/>SET token_data = ?
|
||||
Auth->>DB: UPDATE gmail_token<br/>SET token_data = ?
|
||||
DB-->>Auth: 업데이트 완료
|
||||
|
||||
Auth-->>SE: 새 토큰
|
||||
|
||||
@ -221,20 +221,20 @@ for slack_id, name in slack_ids.items():
|
||||
|
||||
```sql
|
||||
-- 1. 임시 컬럼 추가
|
||||
ALTER TABLE gmail_tokens ADD COLUMN user_uuid UUID;
|
||||
ALTER TABLE gmail_token ADD COLUMN user_uuid UUID;
|
||||
|
||||
-- 2. UUID 매핑
|
||||
UPDATE gmail_tokens gt
|
||||
UPDATE gmail_token gt
|
||||
SET user_uuid = u.id
|
||||
FROM users u
|
||||
WHERE gt.user_id = u.username;
|
||||
|
||||
-- 3. 기존 컬럼 제거 및 이름 변경
|
||||
ALTER TABLE gmail_tokens DROP COLUMN user_id;
|
||||
ALTER TABLE gmail_tokens RENAME COLUMN user_uuid TO user_id;
|
||||
ALTER TABLE gmail_token DROP COLUMN user_id;
|
||||
ALTER TABLE gmail_token RENAME COLUMN user_uuid TO user_id;
|
||||
|
||||
-- 4. 외래키 제약 추가
|
||||
ALTER TABLE gmail_tokens
|
||||
ALTER TABLE gmail_token
|
||||
ADD CONSTRAINT fk_user_id
|
||||
FOREIGN KEY (user_id) REFERENCES users(id);
|
||||
```
|
||||
|
||||
@ -10,10 +10,10 @@ auth-server는 개별 사용자 인증보다는 **회사별 Slack 봇 인증 및
|
||||
|
||||
## 테이블 구조
|
||||
|
||||
### 1. companies (회사/조직 관리)
|
||||
### 1. company (회사/조직 관리)
|
||||
|
||||
```sql
|
||||
CREATE TABLE companies (
|
||||
CREATE TABLE company (
|
||||
id uuid PRIMARY KEY,
|
||||
name varchar(255) NOT NULL,
|
||||
subdomain varchar(100) NOT NULL UNIQUE,
|
||||
@ -41,7 +41,7 @@ CREATE TABLE companies (
|
||||
```sql
|
||||
CREATE TABLE slack_workspaces (
|
||||
id uuid PRIMARY KEY,
|
||||
company_id uuid NOT NULL REFERENCES companies(id),
|
||||
company_id uuid NOT NULL REFERENCES company(id),
|
||||
team_id varchar(100) NOT NULL UNIQUE,
|
||||
team_name varchar(255),
|
||||
bot_token text,
|
||||
@ -71,7 +71,7 @@ CREATE TABLE slack_workspaces (
|
||||
**인덱스**:
|
||||
- Primary Key: `id`
|
||||
- Unique: `team_id`
|
||||
- Foreign Key: `company_id` → `companies(id)`
|
||||
- Foreign Key: `company_id` → `company(id)`
|
||||
|
||||
## 현재 데이터 현황
|
||||
|
||||
|
||||
@ -88,7 +88,7 @@
|
||||
```sql
|
||||
-- PostgreSQL@51123:5432
|
||||
├── main_db (기존)
|
||||
│ ├── companies
|
||||
│ ├── company
|
||||
│ └── slack_workspaces
|
||||
│
|
||||
└── robbing_db (신규 제안)
|
||||
@ -117,7 +117,7 @@ WS /ws/robbing/realtime # 실시간 상태 업데이트
|
||||
|
||||
**위치**: auth-server 내장 또는 별도 React 앱
|
||||
**데이터 저장**:
|
||||
- 회사 정보: PostgreSQL `main_db.companies`
|
||||
- 회사 정보: PostgreSQL `main_db.company`
|
||||
- 세션 관리: JWT 토큰
|
||||
- OAuth 토큰: 파일시스템 `/tokens/`
|
||||
|
||||
|
||||
@ -119,7 +119,7 @@ async def level_up_user(user_id: str, stat: str, points: int):
|
||||
|
||||
```sql
|
||||
-- PostgreSQL 스키마
|
||||
CREATE TABLE companies (
|
||||
CREATE TABLE company (
|
||||
id UUID PRIMARY KEY,
|
||||
name VARCHAR(255),
|
||||
slack_workspace_id VARCHAR(50) UNIQUE,
|
||||
@ -132,7 +132,7 @@ CREATE TABLE companies (
|
||||
|
||||
CREATE TABLE users (
|
||||
id UUID PRIMARY KEY,
|
||||
company_id UUID REFERENCES companies(id),
|
||||
company_id UUID REFERENCES company(id),
|
||||
slack_user_id VARCHAR(50),
|
||||
stats JSONB DEFAULT '{"연산": 0, "기억": 0, "공감": 0, "통솔": 0, "반응": 0}',
|
||||
level INTEGER DEFAULT 1,
|
||||
|
||||
@ -299,7 +299,7 @@ email ↔ slack_id ↔ username
|
||||
##### 현재 테이블 구조 (5개)
|
||||
- **users**: 사용자 기본 정보 (email, username)
|
||||
- **workspaces**: 워크스페이스 정보 (로빙 할당)
|
||||
- **workspace_members**: 사용자-워크스페이스 연결
|
||||
- **workspace_member**: 사용자-워크스페이스 연결
|
||||
- **slack_workspaces**: Slack 워크스페이스 정보
|
||||
- **slack_user_mapping**: Slack ID ↔ User ID 매핑 (3개만 존재)
|
||||
|
||||
|
||||
@ -298,16 +298,16 @@ class SlackItem(APIItem):
|
||||
- 워크스페이스 정보 (robeing_id, robeing_port, robeing_url 포함)
|
||||
- 현재 1개 워크스페이스: ivada-robeing (rb10508_micro 사용)
|
||||
|
||||
3. **workspace_members 테이블**
|
||||
3. **workspace_member 테이블**
|
||||
- 사용자와 워크스페이스 연결
|
||||
- robeing_id 필드로 각 멤버가 사용할 로빙 지정 가능
|
||||
|
||||
4. **slack_workspaces 테이블**
|
||||
- Slack 워크스페이스 정보 (team_id, bot_token, bot_user_id 등)
|
||||
- 2개 Slack 워크스페이스 등록됨 (GoodGang Labs, test)
|
||||
- companies 테이블과 연결됨
|
||||
- company 테이블과 연결됨
|
||||
|
||||
5. **companies 테이블**
|
||||
5. **company 테이블**
|
||||
- 회사 정보 관리
|
||||
- slack_workspaces와 1:N 관계
|
||||
|
||||
@ -329,7 +329,7 @@ CREATE TABLE slack_user_mapping (
|
||||
slack_user_id VARCHAR(100) NOT NULL,
|
||||
slack_workspace_id INTEGER REFERENCES slack_workspaces(id),
|
||||
user_id UUID REFERENCES users(id),
|
||||
workspace_member_id UUID REFERENCES workspace_members(id),
|
||||
workspace_member_id UUID REFERENCES workspace_member(id),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(slack_user_id, slack_workspace_id)
|
||||
@ -345,7 +345,7 @@ slack_user_mapping 조회
|
||||
↓
|
||||
user_id 획득
|
||||
↓
|
||||
workspace_members에서 robeing_id 확인
|
||||
workspace_member에서 robeing_id 확인
|
||||
↓
|
||||
해당 로빙으로 라우팅
|
||||
↓
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# conversation_logs 및 robeing_stats 테이블 활용 계획
|
||||
# conversation_log 및 robeing_stats 테이블 활용 계획
|
||||
|
||||
작성일: 2025년 8월 18일
|
||||
작성자: Claude (51123 서버)
|
||||
@ -9,7 +9,7 @@
|
||||
### 1.1 미사용 테이블 현황
|
||||
```sql
|
||||
-- main_db에 존재하지만 전혀 사용되지 않는 테이블들
|
||||
conversation_logs: 0 records (0 KB)
|
||||
conversation_log: 0 records (0 KB)
|
||||
robeing_stats: 0 records (0 KB)
|
||||
robeing_settings: 0 records (0 KB)
|
||||
```
|
||||
@ -25,11 +25,11 @@ robeing_settings: 0 records (0 KB)
|
||||
3. **개인화 불가**: 사용자별 설정이 저장되지 않음
|
||||
4. **분석 불가**: 사용 패턴, 성능 지표 추적 불가
|
||||
|
||||
## 2. conversation_logs 테이블 활용 방안
|
||||
## 2. conversation_log 테이블 활용 방안
|
||||
|
||||
### 2.1 테이블 구조 (현재)
|
||||
```sql
|
||||
CREATE TABLE conversation_logs (
|
||||
CREATE TABLE conversation_log (
|
||||
id INTEGER PRIMARY KEY (auto-increment),
|
||||
robeing_id VARCHAR,
|
||||
channel_id VARCHAR,
|
||||
@ -70,7 +70,7 @@ class ConversationLogger:
|
||||
"""대화 내용을 DB에 저장"""
|
||||
async with asyncpg.connect(self.db_url) as conn:
|
||||
await conn.execute("""
|
||||
INSERT INTO conversation_logs
|
||||
INSERT INTO conversation_log
|
||||
(id, robeing_id, user_id, message, response, created_at, metadata)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
""",
|
||||
@ -307,7 +307,7 @@ skill_settings = {
|
||||
## 5. 구현 우선순위
|
||||
|
||||
### Phase 1: 즉시 구현 (1주일)
|
||||
1. **conversation_logs 저장 기능**
|
||||
1. **conversation_log 저장 기능**
|
||||
- 모든 대화를 DB에 저장
|
||||
- 메타데이터 포함 (채널, 시간 등)
|
||||
|
||||
@ -337,12 +337,12 @@ skill_settings = {
|
||||
|
||||
### 6.1 인덱스 추가 필요
|
||||
```sql
|
||||
-- conversation_logs 빠른 조회
|
||||
-- conversation_log 빠른 조회
|
||||
CREATE INDEX idx_conversation_user_time
|
||||
ON conversation_logs(user_id, created_at DESC);
|
||||
ON conversation_log(user_id, created_at DESC);
|
||||
|
||||
CREATE INDEX idx_conversation_robeing_time
|
||||
ON conversation_logs(robeing_id, created_at DESC);
|
||||
ON conversation_log(robeing_id, created_at DESC);
|
||||
|
||||
-- robeing_stats 빠른 조회
|
||||
CREATE INDEX idx_robeing_stats_robeing
|
||||
@ -363,7 +363,7 @@ ON robeing_stats(robeing_id);
|
||||
```sql
|
||||
-- 일일 대화량
|
||||
SELECT DATE(created_at), COUNT(*)
|
||||
FROM conversation_logs
|
||||
FROM conversation_log
|
||||
GROUP BY DATE(created_at);
|
||||
|
||||
-- 로빙별 활동
|
||||
@ -396,7 +396,7 @@ FROM robeing_stats;
|
||||
## 9. 주의사항
|
||||
|
||||
### 9.1 개인정보 보호
|
||||
- conversation_logs에 민감 정보 마스킹
|
||||
- conversation_log에 민감 정보 마스킹
|
||||
- GDPR 준수 (삭제 요청 처리)
|
||||
- 암호화 고려
|
||||
|
||||
|
||||
@ -217,7 +217,7 @@ flowchart TD
|
||||
## 3.4 시간 인식 의도 처리 (신규 추가 2025-09-09)
|
||||
|
||||
### 3.4.1 실제 대화 로그 분석 결과
|
||||
2025년 9월 9일 PostgreSQL conversation_logs 테이블 분석 결과, 로빙의 가장 심각한 문제는 **시간 인식 부재**입니다.
|
||||
2025년 9월 9일 PostgreSQL conversation_log 테이블 분석 결과, 로빙의 가장 심각한 문제는 **시간 인식 부재**입니다.
|
||||
|
||||
```
|
||||
실제 사례:
|
||||
@ -250,7 +250,7 @@ CONTEXT_RETRIEVAL_PATTERNS = {
|
||||
|
||||
# DB에서 과거 대화 조회 필수
|
||||
if pattern_matches(CONTEXT_RETRIEVAL_PATTERNS):
|
||||
past_logs = await fetch_conversation_logs(
|
||||
past_logs = await fetch_conversation_log(
|
||||
user_id=user_id,
|
||||
time_range="-2 hours",
|
||||
limit=5
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
1. **실시간 동기화** - WebSocket/폴링 미구현 (영향도 재평가 필요) (2주) [→250827](../troubleshooting/250827_frontend_backend_preferences_API_연동_완료.md)
|
||||
2. **PKCE 적용** - OAuth 보안 강화 미구현 (1주) [→380](../300_architecture/380_authentication_system.md)
|
||||
3. **Refresh Token** - 토큰 재발급 체계 미구현 (1주) [→380](../300_architecture/380_authentication_system.md)
|
||||
4. **DB 스키마 통일** - companies→workspaces 미구현 (2주) [→250831](250831_todo_and_tech_debt.md)
|
||||
4. **DB 스키마 통일** - company→workspaces 미구현 (2주) [→250831](250831_todo_and_tech_debt.md)
|
||||
5. **스킬 라우팅 고도화** - Decision Engine 미구현 (3주) [→250811](../ideas/250811_claude_rb10408_vs_rb10508_비교분석.md)
|
||||
6. **IntentAnalyzer 활성화** - 현재 미사용, LLM 기반 의도분석기 미연동 (1주) [→250914](../troubleshooting/250914_happybell80_IntentAnalyzer_미사용_문제.md)
|
||||
7. **전역 ENV 감사** - 레포 전반 미사용/중복 ENV 정리 미구현 (2주)
|
||||
|
||||
@ -16,12 +16,12 @@
|
||||
|
||||
### 2. DB 스키마 불일치
|
||||
**문제**:
|
||||
- companies vs workspaces 테이블 공존
|
||||
- company vs workspaces 테이블 공존
|
||||
- SlackWorkspace 모델 FK 오류 (company_id를 workspace_id로 참조)
|
||||
|
||||
**해결 계획**:
|
||||
1. 데이터 백업
|
||||
2. companies → workspaces 마이그레이션
|
||||
2. company → workspaces 마이그레이션
|
||||
3. FK 관계 재설정
|
||||
4. 모델 파일 통일
|
||||
|
||||
@ -99,7 +99,7 @@ fetch('https://auth.ro-being.com/auth/verify')
|
||||
|
||||
## 체크리스트
|
||||
- [ ] 하드코딩 URL 환경변수화
|
||||
- [ ] DB 스키마 통일 (companies → workspaces)
|
||||
- [ ] DB 스키마 통일 (company → workspaces)
|
||||
- [ ] 임시 코드 방식 제거
|
||||
- [ ] UserIdentityService 구현
|
||||
- [ ] Refresh Token 구현
|
||||
|
||||
@ -50,9 +50,9 @@ SET user_uuid = (
|
||||
AND sum.team_id = gp.team_id
|
||||
);
|
||||
|
||||
-- workspace_members UUID 확인
|
||||
ALTER TABLE workspace_members
|
||||
ADD CONSTRAINT fk_workspace_members_user_id
|
||||
-- workspace_member UUID 확인
|
||||
ALTER TABLE workspace_member
|
||||
ADD CONSTRAINT fk_workspace_member_user_id
|
||||
FOREIGN KEY (user_id) REFERENCES users(id);
|
||||
```
|
||||
|
||||
@ -406,4 +406,4 @@ if not uuid_mapping:
|
||||
|
||||
- [250828_slack_auth_integration_completed.md](../troubleshooting/250828_slack_auth_integration_completed.md)
|
||||
- [250828_slack_integration_level3_plan.md](./250828_slack_integration_level3_plan.md)
|
||||
- [250828_conversation_logs_channel_구분_개선.md](../troubleshooting/250828_conversation_logs_channel_구분_개선.md)
|
||||
- [250828_conversation_log_channel_구분_개선.md](../troubleshooting/250828_conversation_log_channel_구분_개선.md)
|
||||
@ -3,21 +3,21 @@
|
||||
## 작성일: 2025년 8월 31일
|
||||
|
||||
## 🎯 목표
|
||||
`companies` 테이블과 `workspaces` 테이블을 `workspaces`로 통합하여 DB 스키마 일관성 확보
|
||||
`company` 테이블과 `workspaces` 테이블을 `workspaces`로 통합하여 DB 스키마 일관성 확보
|
||||
|
||||
## 📊 현재 상황
|
||||
|
||||
### 테이블 구조 비교
|
||||
| 구분 | companies | workspaces |
|
||||
| 구분 | company | workspaces |
|
||||
|------|-----------|------------|
|
||||
| **포트 컬럼** | `container_port` | `robeing_port` |
|
||||
| **FK 참조** | `slack_workspaces.company_id` | `workspace_members.workspace_id` |
|
||||
| **FK 참조** | `slack_workspaces.company_id` | `workspace_member.workspace_id` |
|
||||
| **추가 컬럼** | - | `robeing_id`, `robeing_url`, `max_members`, `workspace_type` |
|
||||
| **데이터** | 4개 레코드 | 2개 레코드 |
|
||||
|
||||
### 문제점
|
||||
1. 중복 데이터 (Company-X가 양쪽 테이블에 존재)
|
||||
2. FK 관계 불일치 (slack_workspaces → companies, workspace_members → workspaces)
|
||||
2. FK 관계 불일치 (slack_workspaces → company, workspace_member → workspaces)
|
||||
3. 코드에서 잘못된 참조 (`workspace.workspace`, `workspace.robeing_port`)
|
||||
|
||||
## 🔧 작업 계획
|
||||
@ -25,15 +25,15 @@
|
||||
### Phase 1: DB 백업 및 준비
|
||||
```bash
|
||||
# 백업 생성
|
||||
sudo -u postgres pg_dump -t companies -t workspaces -t slack_workspaces main_db > /home/admin/backup_workspace_$(date +%Y%m%d_%H%M%S).sql
|
||||
sudo -u postgres pg_dump -t company -t workspaces -t slack_workspaces main_db > /home/admin/backup_workspace_$(date +%Y%m%d_%H%M%S).sql
|
||||
```
|
||||
|
||||
### Phase 2: DB 스키마 변경
|
||||
```sql
|
||||
-- 1. companies 데이터를 workspaces로 이동
|
||||
-- 1. company 데이터를 workspaces로 이동
|
||||
INSERT INTO workspaces (id, name, subdomain, robeing_port, status, created_at, updated_at)
|
||||
SELECT id, name, subdomain, container_port, status, created_at, updated_at
|
||||
FROM companies
|
||||
FROM company
|
||||
WHERE id NOT IN (SELECT id FROM workspaces);
|
||||
|
||||
-- 2. slack_workspaces 테이블 수정
|
||||
@ -48,8 +48,8 @@ ALTER TABLE slack_workspaces
|
||||
ADD CONSTRAINT slack_workspaces_workspace_id_fkey
|
||||
FOREIGN KEY (workspace_id) REFERENCES workspaces(id);
|
||||
|
||||
-- 3. companies 테이블 제거
|
||||
DROP TABLE companies CASCADE;
|
||||
-- 3. company 테이블 제거
|
||||
DROP TABLE company CASCADE;
|
||||
```
|
||||
|
||||
### Phase 3: 코드 수정
|
||||
@ -123,7 +123,7 @@ curl -X POST https://auth.ro-being.com/slack/events/router \
|
||||
```bash
|
||||
cd /home/admin/auth-server
|
||||
git add -A
|
||||
git commit -m "refactor: companies 테이블을 workspaces로 통합"
|
||||
git commit -m "refactor: company 테이블을 workspaces로 통합"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
@ -154,9 +154,9 @@ sudo -u postgres psql main_db < /home/admin/backup_workspace_YYYYMMDD_HHMMSS.sql
|
||||
## 📝 체크리스트
|
||||
|
||||
- [ ] DB 백업 완료
|
||||
- [ ] companies → workspaces 데이터 이동
|
||||
- [ ] company → workspaces 데이터 이동
|
||||
- [ ] slack_workspaces FK 변경
|
||||
- [ ] companies 테이블 삭제
|
||||
- [ ] company 테이블 삭제
|
||||
- [ ] workspace.py 모델 수정
|
||||
- [ ] slack_router.py 수정
|
||||
- [ ] slack.py provider 수정
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
### main_db3 (삭제 예정)
|
||||
- 총 13개 테이블, 614개 레코드
|
||||
- 주요 데이터: users(17), companies(4), conversation_logs(555)
|
||||
- 주요 데이터: users(17), company(4), conversation_log(555)
|
||||
- Slack/Gmail 연동 데이터 보유
|
||||
|
||||
### main_db (운영 DB)
|
||||
@ -22,14 +22,14 @@
|
||||
|
||||
| main_db3 | main_db | 비고 |
|
||||
|----------|---------|------|
|
||||
| companies | company | 2개 중복 확인 필요 |
|
||||
| company | company | 2개 중복 확인 필요 |
|
||||
| users | user | team_id 필수 추가 |
|
||||
| workspaces | team | 구조 변환 필요 |
|
||||
| workspace_members | workspace_member | user_id 매핑 |
|
||||
| workspace_member | workspace_member | user_id 매핑 |
|
||||
| slack_workspaces | slack_workspace | team_id 매핑 |
|
||||
| user_preferences | user_preference | slack_user_id 제거됨 |
|
||||
| conversation_logs | conversation_log | robeing_id 컬럼 없음 |
|
||||
| gmail_tokens | gmail_token | 구조 동일 |
|
||||
| conversation_log | conversation_log | robeing_id 컬럼 없음 |
|
||||
| gmail_token | gmail_token | 구조 동일 |
|
||||
| robeing_stats | robeing | product_id, team_id 추가 |
|
||||
| slack_user_mapping | - | workspace_member로 통합 |
|
||||
|
||||
@ -39,10 +39,10 @@
|
||||
|
||||
### Phase 1: 조직 구조 (필수 선행)
|
||||
```sql
|
||||
-- 1. companies → company (중복 제외)
|
||||
-- 1. company → company (중복 제외)
|
||||
INSERT INTO company (id, name, url, created_at, updated_at)
|
||||
SELECT id, name, domain, created_at, updated_at
|
||||
FROM main_db3.companies
|
||||
FROM main_db3.company
|
||||
WHERE id NOT IN ('28f17b47-33f8-47ac-b1ae-100e77b37edb', '99d22d6b-d327-4fa4-bd2f-d228c11056e2');
|
||||
|
||||
-- 2. workspaces → team 변환
|
||||
@ -58,11 +58,11 @@ SELECT u.id,
|
||||
COALESCE(wm.workspace_id, '38bdc27d-cb01-4960-867e-41733d2f3529'), -- 기본 팀
|
||||
u.email, u.name, u.username, u.oauth_provider, u.oauth_id, u.is_active
|
||||
FROM main_db3.users u
|
||||
LEFT JOIN main_db3.workspace_members wm ON u.id = wm.user_id;
|
||||
LEFT JOIN main_db3.workspace_member wm ON u.id = wm.user_id;
|
||||
|
||||
-- 4. workspace_members → workspace_member (slack_user_id 추가 예정)
|
||||
-- 4. workspace_member → workspace_member (slack_user_id 추가 예정)
|
||||
INSERT INTO workspace_member (id, user_id, role, is_active, joined_at)
|
||||
SELECT id, user_id, role::user_role, is_active, joined_at FROM main_db3.workspace_members;
|
||||
SELECT id, user_id, role::user_role, is_active, joined_at FROM main_db3.workspace_member;
|
||||
```
|
||||
|
||||
### Phase 3: 통합 데이터
|
||||
@ -75,16 +75,16 @@ SELECT id, workspace_id, team_id, bot_token, is_active FROM main_db3.slack_works
|
||||
INSERT INTO user_preference (user_id, news_keywords, email_filter, briefing_enabled)
|
||||
SELECT user_id, news_keywords, email_filter, briefing_enabled FROM main_db3.user_preferences;
|
||||
|
||||
-- 7. gmail_tokens → gmail_token
|
||||
INSERT INTO gmail_token SELECT * FROM main_db3.gmail_tokens;
|
||||
-- 7. gmail_token → gmail_token
|
||||
INSERT INTO gmail_token SELECT * FROM main_db3.gmail_token;
|
||||
```
|
||||
|
||||
### Phase 4: 대화 기록
|
||||
```sql
|
||||
-- 8. conversation_logs → conversation_log (컬럼 매핑 주의)
|
||||
-- 8. conversation_log → conversation_log (컬럼 매핑 주의)
|
||||
INSERT INTO conversation_log (user_id, channel_id, message, response, intent, confidence, timestamp)
|
||||
SELECT user_id, channel_id, message, response, intent, confidence, timestamp
|
||||
FROM main_db3.conversation_logs WHERE user_id IS NOT NULL;
|
||||
FROM main_db3.conversation_log WHERE user_id IS NOT NULL;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@ -9,23 +9,23 @@
|
||||
### 1.1 현재 테이블 (5개)
|
||||
- **users**: 사용자 기본 정보
|
||||
- **workspaces**: 워크스페이스 정보 (로빙 할당)
|
||||
- **workspace_members**: 사용자-워크스페이스 연결
|
||||
- **companies**: 회사 정보
|
||||
- **workspace_member**: 사용자-워크스페이스 연결
|
||||
- **company**: 회사 정보
|
||||
- **slack_workspaces**: Slack 워크스페이스 정보
|
||||
|
||||
### 1.2 현재 구조의 문제점
|
||||
|
||||
#### 복잡도 문제
|
||||
1. **과도한 관계 분리**
|
||||
- companies ↔ slack_workspaces ↔ workspaces 3단계 관계
|
||||
- company ↔ slack_workspaces ↔ workspaces 3단계 관계
|
||||
- 실제로는 1개 workspace만 사용 중
|
||||
|
||||
2. **중복 데이터**
|
||||
- robeing_id가 workspaces와 workspace_members 양쪽에 존재
|
||||
- robeing_id가 workspaces와 workspace_member 양쪽에 존재
|
||||
- robeing_url도 중복 저장
|
||||
|
||||
3. **불명확한 개념**
|
||||
- companies의 실제 필요성 불분명
|
||||
- company의 실제 필요성 불분명
|
||||
- workspaces가 실제로 무엇을 나타내는지 모호
|
||||
|
||||
4. **누락된 기능**
|
||||
@ -36,8 +36,8 @@
|
||||
```
|
||||
users: 3명 (happybell80, eagle0914, hhyong91)
|
||||
workspaces: 1개 (ivada-robeing)
|
||||
workspace_members: 3개 (모두 rb10508_micro 사용)
|
||||
companies: 2개 (테스트 회사)
|
||||
workspace_member: 3개 (모두 rb10508_micro 사용)
|
||||
company: 2개 (테스트 회사)
|
||||
slack_workspaces: 2개 (GoodGang Labs, test)
|
||||
```
|
||||
|
||||
@ -197,8 +197,8 @@ CREATE TABLE slack_config (
|
||||
```sql
|
||||
-- 기존 데이터 백업
|
||||
CREATE TABLE backup_workspaces AS SELECT * FROM workspaces;
|
||||
CREATE TABLE backup_workspace_members AS SELECT * FROM workspace_members;
|
||||
CREATE TABLE backup_companies AS SELECT * FROM companies;
|
||||
CREATE TABLE backup_workspace_member AS SELECT * FROM workspace_member;
|
||||
CREATE TABLE backup_company AS SELECT * FROM company;
|
||||
```
|
||||
|
||||
#### Phase 2: 새 테이블 생성
|
||||
@ -217,7 +217,7 @@ SELECT
|
||||
'192.168.219.52' as robeing_host,
|
||||
true as is_primary,
|
||||
joined_at as created_at
|
||||
FROM workspace_members;
|
||||
FROM workspace_member;
|
||||
|
||||
-- slack_users 테이블 생성 (빈 테이블)
|
||||
CREATE TABLE slack_users (
|
||||
@ -238,9 +238,9 @@ CREATE TABLE slack_users (
|
||||
ALTER TABLE slack_workspaces DROP CONSTRAINT slack_workspaces_company_id_fkey;
|
||||
ALTER TABLE slack_workspaces DROP COLUMN company_id;
|
||||
|
||||
DROP TABLE workspace_members;
|
||||
DROP TABLE workspace_member;
|
||||
DROP TABLE workspaces;
|
||||
DROP TABLE companies;
|
||||
DROP TABLE company;
|
||||
```
|
||||
|
||||
### 3.3 새로운 데이터 흐름
|
||||
@ -272,11 +272,11 @@ ChromaDB에 user_id 기반 저장
|
||||
- 기존 테이블 영향 없음
|
||||
|
||||
2. **단계적 마이그레이션**: user_robeings 테이블
|
||||
- workspace_members 데이터 이전
|
||||
- workspace_member 데이터 이전
|
||||
- 테스트 후 기존 테이블 제거
|
||||
|
||||
3. **정리 작업**: 불필요한 테이블 제거
|
||||
- companies, workspaces 제거
|
||||
- company, workspaces 제거
|
||||
- slack_workspaces 단순화
|
||||
|
||||
## 5. API 변경사항
|
||||
@ -284,7 +284,7 @@ ChromaDB에 user_id 기반 저장
|
||||
### 5.1 사용자-로빙 조회
|
||||
```python
|
||||
# 기존
|
||||
SELECT * FROM workspace_members WHERE user_id = ?
|
||||
SELECT * FROM workspace_member WHERE user_id = ?
|
||||
|
||||
# 변경
|
||||
SELECT * FROM user_robeings WHERE user_id = ? AND is_primary = true
|
||||
|
||||
@ -115,7 +115,7 @@ async def get_user_mapping(
|
||||
wm.robeing_id
|
||||
FROM slack_user_mapping sum
|
||||
JOIN users u ON sum.user_id = u.id
|
||||
LEFT JOIN workspace_members wm ON u.id = wm.user_id
|
||||
LEFT JOIN workspace_member wm ON u.id = wm.user_id
|
||||
WHERE sum.slack_user_id = :slack_user_id
|
||||
"""
|
||||
|
||||
@ -230,7 +230,7 @@ CREATE TABLE IF NOT EXISTS slack_user_mapping (
|
||||
slack_user_id VARCHAR(100) NOT NULL,
|
||||
slack_workspace_id INTEGER REFERENCES slack_workspaces(id),
|
||||
user_id UUID REFERENCES users(id) NOT NULL,
|
||||
workspace_member_id UUID REFERENCES workspace_members(id),
|
||||
workspace_member_id UUID REFERENCES workspace_member(id),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(slack_user_id, slack_workspace_id)
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
- [x] 기본 데이터 삽입 (rb8001, level=5)
|
||||
- [x] 생성 확인 쿼리 실행
|
||||
|
||||
### 1.2 gmail_tokens 테이블 수정
|
||||
### 1.2 gmail_token 테이블 수정
|
||||
- [x] is_equipped 컬럼 추가
|
||||
- [x] equipped_to 컬럼 추가
|
||||
- [x] 기존 데이터 is_equipped=false로 초기화
|
||||
@ -232,7 +232,7 @@
|
||||
- [x] Auth 서버 API 호출
|
||||
- [x] 5분 캐싱 구현
|
||||
- [ ] Gmail용 이메일 매핑 추가
|
||||
- [ ] workspace_members 테이블에서 email 조회
|
||||
- [ ] workspace_member 테이블에서 email 조회
|
||||
- [ ] "종태님" → goeun2dc@gmail.com 변환
|
||||
|
||||
### 4-1.6 테스트 시나리오
|
||||
|
||||
@ -19,7 +19,7 @@ Gmail 자격증명을 "API 아이템"으로 정의하고, robeing의 장착형
|
||||
|
||||
### 관련 문서
|
||||
- `/250817_email_skill_integration_status.md` - 현황 분석
|
||||
- `/250818_gmail_tokens_database_setup.md` - DB 구성 완료
|
||||
- `/250818_gmail_token_database_setup.md` - DB 구성 완료
|
||||
- `/ideas/250818_claude_robeing_레벨업_체감_시스템_설계.md` - 아이템 시스템 설계
|
||||
|
||||
---
|
||||
@ -40,9 +40,9 @@ Gmail 자격증명을 "API 아이템"으로 정의하고, robeing의 장착형
|
||||
### 데이터 모델
|
||||
```typescript
|
||||
type GmailCredentialItem = {
|
||||
id: string; // gmail_tokens.id
|
||||
userId: string; // gmail_tokens.user_id
|
||||
robeing_id?: string; // gmail_tokens.robeing_id (통일)
|
||||
id: string; // gmail_token.id
|
||||
userId: string; // gmail_token.user_id
|
||||
robeing_id?: string; // gmail_token.robeing_id (통일)
|
||||
type: 'accessory';
|
||||
slot: 'passport_gmail';
|
||||
name: string; // metadata.display_name || email
|
||||
@ -75,14 +75,14 @@ rb8001:8001 (메인 robeing)
|
||||
skill-email:8501 robeing-monitor:9024
|
||||
(이메일 발송) (아이템 상태 관리)
|
||||
↓ ↓
|
||||
PostgreSQL (gmail_tokens 테이블)
|
||||
PostgreSQL (gmail_token 테이블)
|
||||
```
|
||||
|
||||
### 서비스별 역할
|
||||
|
||||
#### auth-server
|
||||
- Gmail OAuth 플로우 처리
|
||||
- gmail_tokens 테이블 관리
|
||||
- gmail_token 테이블 관리
|
||||
- 토큰 갱신 로직
|
||||
|
||||
#### robeing-monitor (9024)
|
||||
@ -125,14 +125,14 @@ sequenceDiagram
|
||||
Gateway-->>Front: UNAUTHORIZED
|
||||
else 인증 성공
|
||||
Gateway->>Monitor: 장착 요청 전달
|
||||
Monitor->>DB: gmail_tokens 소유권 확인
|
||||
Monitor->>DB: gmail_token 소유권 확인
|
||||
Monitor->>DB: robeing_stats 조회 (레벨 체크)
|
||||
DB-->>Monitor: 레벨 정보
|
||||
|
||||
alt 레벨 < 5
|
||||
Monitor-->>Front: INSUFFICIENT_LEVEL
|
||||
else 레벨 >= 5
|
||||
Monitor->>DB: gmail_tokens 업데이트
|
||||
Monitor->>DB: gmail_token 업데이트
|
||||
Note over DB: is_equipped=true<br/>equipped_to=robeing_id
|
||||
Monitor->>DB: gmail_audit_logs 기록
|
||||
Monitor-->>RB: 장착 완료 알림
|
||||
@ -155,7 +155,7 @@ sequenceDiagram
|
||||
User->>Front: "이메일 보내줘" 요청
|
||||
Front->>RB: 메시지 전달
|
||||
RB->>Monitor: Gmail 아이템 장착 확인
|
||||
Monitor->>DB: gmail_tokens 조회
|
||||
Monitor->>DB: gmail_token 조회
|
||||
DB-->>Monitor: 장착 상태 & 토큰 정보
|
||||
|
||||
alt 아이템 미장착
|
||||
@ -195,7 +195,7 @@ sequenceDiagram
|
||||
Google->>Auth: 인증 코드 콜백
|
||||
Auth->>Google: 토큰 교환
|
||||
Google-->>Auth: access_token, refresh_token
|
||||
Auth->>DB: gmail_tokens 업데이트
|
||||
Auth->>DB: gmail_token 업데이트
|
||||
Auth-->>Front: 인증 완료
|
||||
Front->>Front: 아이템 상태 갱신
|
||||
```
|
||||
@ -285,7 +285,7 @@ CREATE TABLE gmail_audit_logs (
|
||||
- [x] 필요 테이블 생성
|
||||
- robeing_stats 테이블 (레벨 관리)
|
||||
- gmail_audit_logs 테이블 (감사 로그)
|
||||
- gmail_tokens에 is_equipped, equipped_to 컬럼 추가
|
||||
- gmail_token에 is_equipped, equipped_to 컬럼 추가
|
||||
- [x] skill-email DB 연결 코드 작성 (희재)
|
||||
- FileCredentialsProvider → DBCredentialsProvider 전환
|
||||
- PostgreSQL 연결 설정 추가 (localhost:5433 SSH 터널)
|
||||
@ -361,11 +361,11 @@ DATABASE_URL=postgresql://robeings:robeings@192.168.219.45:5432/main_db
|
||||
## 8. 데이터 매핑 (추후 구현)
|
||||
|
||||
### Slack User ID ↔ Gmail 계정 매핑
|
||||
- 위치: 추후 결정 (workspace_members 또는 별도 테이블)
|
||||
- 위치: 추후 결정 (workspace_member 또는 별도 테이블)
|
||||
- 구조:
|
||||
```sql
|
||||
-- 옵션 1: workspace_members 확장
|
||||
ALTER TABLE workspace_members
|
||||
-- 옵션 1: workspace_member 확장
|
||||
ALTER TABLE workspace_member
|
||||
ADD COLUMN gmail_account VARCHAR(255);
|
||||
|
||||
-- 옵션 2: 별도 매핑 테이블
|
||||
@ -443,7 +443,7 @@ CREATE TABLE user_gmail_mapping (
|
||||
## 12. 참고사항
|
||||
|
||||
### 현재 상태 (2025-08-19)
|
||||
- gmail_tokens 테이블 생성 완료
|
||||
- gmail_token 테이블 생성 완료
|
||||
- rb8001 정상 작동 (GEMINI_USE_CLI=false)
|
||||
- skill-email 파일 기반 동작 중 (DB 전환 필요)
|
||||
- 프론트 인벤토리 UI 미구현
|
||||
|
||||
@ -45,11 +45,11 @@ Gmail 스킬 통합을 담당하는 핵심 모듈
|
||||
# PostgreSQL에서 직접 장착 상태 확인
|
||||
# 5분 캐싱으로 성능 최적화
|
||||
cur.execute("""
|
||||
SELECT COUNT(*) FROM gmail_tokens
|
||||
SELECT COUNT(*) FROM gmail_token
|
||||
WHERE user_id = %s AND is_equipped = true
|
||||
""", (user_id,))
|
||||
```
|
||||
- gmail_tokens 테이블의 is_equipped 확인
|
||||
- gmail_token 테이블의 is_equipped 확인
|
||||
- 캐시 TTL: 300초 (5분)
|
||||
- DB 연결 실패 시 False 반환
|
||||
|
||||
@ -372,7 +372,7 @@ python3 -c "
|
||||
import psycopg2
|
||||
conn = psycopg2.connect('postgresql://robeings:robeings@localhost:5433/main_db')
|
||||
cur = conn.cursor()
|
||||
cur.execute('SELECT user_id, is_equipped FROM gmail_tokens')
|
||||
cur.execute('SELECT user_id, is_equipped FROM gmail_token')
|
||||
for row in cur.fetchall():
|
||||
print(f'{row[0]}: equipped={row[1]}')
|
||||
"
|
||||
|
||||
@ -13,7 +13,7 @@ skill-email 서비스가 Gmail OAuth 토큰을 파일이 아닌 PostgreSQL 데
|
||||
|
||||
### 배경
|
||||
- 기존: 파일 기반 토큰 관리 (FileCredentialsProvider)
|
||||
- 변경: PostgreSQL gmail_tokens 테이블 기반 관리 (DBCredentialsProvider)
|
||||
- 변경: PostgreSQL gmail_token 테이블 기반 관리 (DBCredentialsProvider)
|
||||
- 이유: 중앙집중식 토큰 관리, 보안 강화, 다중 서비스 통합
|
||||
|
||||
---
|
||||
@ -56,12 +56,12 @@ LOG_LEVEL=INFO
|
||||
2. **get_credentials() 메서드**
|
||||
```python
|
||||
def get_credentials(self, user_id: str) -> Optional[Credentials]:
|
||||
# gmail_tokens 테이블에서 조회
|
||||
# gmail_token 테이블에서 조회
|
||||
# is_equipped=true인 토큰만 조회
|
||||
# token_data + oauth_config 컬럼 모두 활용
|
||||
```
|
||||
|
||||
- gmail_tokens 테이블 조회
|
||||
- gmail_token 테이블 조회
|
||||
- token_data 컬럼: access_token, refresh_token
|
||||
- oauth_config 컬럼: client_id, client_secret, token_uri
|
||||
- Google Credentials 객체로 변환
|
||||
@ -117,9 +117,9 @@ def get_gmail_service() -> GmailService:
|
||||
|
||||
## 3. 데이터베이스 구조
|
||||
|
||||
### gmail_tokens 테이블
|
||||
### gmail_token 테이블
|
||||
```sql
|
||||
CREATE TABLE gmail_tokens (
|
||||
CREATE TABLE gmail_token (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id VARCHAR(100),
|
||||
robeing_id VARCHAR(50),
|
||||
@ -161,7 +161,7 @@ CREATE TABLE gmail_tokens (
|
||||
cd /home/heejae/skill-email && python3 test_db.py
|
||||
```
|
||||
- ✅ PostgreSQL 연결 성공
|
||||
- ✅ gmail_tokens 테이블 접근 가능
|
||||
- ✅ gmail_token 테이블 접근 가능
|
||||
- ✅ 3개 토큰 확인 (heejae, test, unknown)
|
||||
|
||||
### 4.2 Provider 테스트
|
||||
@ -212,7 +212,7 @@ sshpass -p "19800508" ssh -f -N -L 5433:localhost:5432 admin@124.55.18.179 -p 51
|
||||
- **문제**: 모든 토큰이 is_equipped=false 상태
|
||||
- **해결**:
|
||||
```sql
|
||||
UPDATE gmail_tokens SET is_equipped=true WHERE user_id='heejae'
|
||||
UPDATE gmail_token SET is_equipped=true WHERE user_id='heejae'
|
||||
```
|
||||
|
||||
### 6.3 oauth_config 누락
|
||||
@ -221,7 +221,7 @@ sshpass -p "19800508" ssh -f -N -L 5433:localhost:5432 admin@124.55.18.179 -p 51
|
||||
```python
|
||||
cur.execute("""
|
||||
SELECT token_data, oauth_config
|
||||
FROM gmail_tokens
|
||||
FROM gmail_token
|
||||
WHERE user_id = %s AND is_equipped = true
|
||||
""")
|
||||
```
|
||||
@ -299,7 +299,7 @@ sshpass -p "19800508" ssh -f -N -L 5433:localhost:5432 admin@124.55.18.179 -p 51
|
||||
## 12. 검증 체크리스트
|
||||
|
||||
- [x] PostgreSQL 연결 성공
|
||||
- [x] gmail_tokens 테이블 조회
|
||||
- [x] gmail_token 테이블 조회
|
||||
- [x] 토큰 데이터 파싱
|
||||
- [x] Credentials 객체 생성
|
||||
- [x] oauth_config 통합
|
||||
@ -328,7 +328,7 @@ python3 -c "
|
||||
import psycopg2
|
||||
conn = psycopg2.connect('postgresql://robeings:robeings@localhost:5433/main_db')
|
||||
cur = conn.cursor()
|
||||
cur.execute('SELECT user_id, is_equipped FROM gmail_tokens')
|
||||
cur.execute('SELECT user_id, is_equipped FROM gmail_token')
|
||||
for row in cur.fetchall():
|
||||
print(f'{row[0]}: equipped={row[1]}')
|
||||
"
|
||||
|
||||
@ -114,7 +114,7 @@ sequenceDiagram
|
||||
|
||||
loop 각 사용자별 처리
|
||||
Scheduler->>Monitor: Gmail 토큰 확인<br/>(X-User-Id)
|
||||
Monitor->>DB: gmail_tokens 조회
|
||||
Monitor->>DB: gmail_token 조회
|
||||
DB-->>Monitor: token_data
|
||||
|
||||
alt 토큰 유효
|
||||
|
||||
@ -55,7 +55,7 @@ Frontend(Slack 아이템 획득) → auth-server → OAuth 2.0 → 봇 토큰
|
||||
- `GET /auth/slack/passport/install?user_id={user_id}` - 봇 설치 OAuth 시작
|
||||
- 파일: `/home/admin/auth-server/app/providers/slack.py:104`
|
||||
- 변경: workspace_id → user_id 파라미터
|
||||
- 처리: user_id로 workspace_members 테이블에서 workspace_id 조회
|
||||
- 처리: user_id로 workspace_member 테이블에서 workspace_id 조회
|
||||
- `GET /auth/slack/passport/callback` - bot_token 저장
|
||||
- `GET /auth/slack/passport/status/{workspace_id}` - 아이템 상태 확인
|
||||
- `DELETE /auth/slack/passport/uninstall/{workspace_id}` - 아이템 취소
|
||||
@ -91,7 +91,7 @@ Slack Event → rb8001 → DB → SSE/WebSocket → Frontend
|
||||
- 이벤트: `message.channels`, `message.groups`, `message.im`, `message.mpim`, `app_mention`
|
||||
- 쓰레드: `message.message_replied` 이벤트 존재하나 `thread_ts` 확인 권장
|
||||
2. 채널 타입: C(공개), G(비공개/그룹), D(DM)
|
||||
3. conversation_logs 저장: team_id, channel_id, thread_ts
|
||||
3. conversation_log 저장: team_id, channel_id, thread_ts
|
||||
4. 초기 동기화: `conversations.history`로 백필
|
||||
|
||||
### Phase 4: 명령 처리
|
||||
@ -116,14 +116,14 @@ Slack → @robeing 또는 /robeing → rb8001 → 응답
|
||||
- **users**: id(UUID), email, slack_user_id, slack_team_id
|
||||
- **slack_workspaces**: team_id, team_name, bot_token(암호화), installed_by_user_id, scopes, installed_at
|
||||
- **slack_user_mapping**: team_id + slack_user_id 복합키, user_id(UUID)
|
||||
- **conversation_logs**: team_id, channel_id, channel_type, user_id, text, ts, thread_ts
|
||||
- **conversation_log**: team_id, channel_id, channel_type, user_id, text, ts, thread_ts
|
||||
|
||||
### 필요 컬럼 추가
|
||||
```sql
|
||||
ALTER TABLE users ADD COLUMN slack_user_id VARCHAR(50);
|
||||
ALTER TABLE users ADD COLUMN slack_team_id VARCHAR(50);
|
||||
ALTER TABLE conversation_logs ADD COLUMN thread_ts VARCHAR(20);
|
||||
ALTER TABLE conversation_logs ADD COLUMN channel_type VARCHAR(20);
|
||||
ALTER TABLE conversation_log ADD COLUMN thread_ts VARCHAR(20);
|
||||
ALTER TABLE conversation_log ADD COLUMN channel_type VARCHAR(20);
|
||||
```
|
||||
|
||||
---
|
||||
@ -182,4 +182,4 @@ ALTER TABLE conversation_logs ADD COLUMN channel_type VARCHAR(20);
|
||||
### 내부 문서
|
||||
- [auth_login_sequences.md](../300_architecture/sequences/auth_login_sequences.md)
|
||||
- [tables.md](../300_architecture/database/tables.md)
|
||||
- [250828_conversation_logs_channel_구분_개선.md](../troubleshooting/250828_conversation_logs_channel_구분_개선.md)
|
||||
- [250828_conversation_log_channel_구분_개선.md](../troubleshooting/250828_conversation_log_channel_구분_개선.md)
|
||||
@ -190,7 +190,7 @@ Claude가 세션 시작 시 규칙을 제대로 따르지 않음. CLAUDE.md 재
|
||||
- JWT/OAuth 키 관리 상태 점검
|
||||
|
||||
2. **PostgreSQL main_db 스키마 분석**:
|
||||
- `companies` 테이블: 회사별 서브도메인 관리 (2개 회사 등록)
|
||||
- `company` 테이블: 회사별 서브도메인 관리 (2개 회사 등록)
|
||||
- `slack_workspaces` 테이블: Slack 봇 토큰 관리 (2개 워크스페이스 활성)
|
||||
- 멀티테넌트 B2B SaaS 구조 확인
|
||||
|
||||
|
||||
@ -69,8 +69,8 @@
|
||||
|
||||
**필요한 DB 확장**:
|
||||
1. `users` 테이블: 개별 사용자 정보
|
||||
2. `workspace_members` 테이블: 사용자-워크스페이스-로빙 매핑
|
||||
3. `workspaces` 테이블: companies 테이블 이름 변경
|
||||
2. `workspace_member` 테이블: 사용자-워크스페이스-로빙 매핑
|
||||
3. `workspaces` 테이블: company 테이블 이름 변경
|
||||
|
||||
**개발 우선순위**:
|
||||
1. auth-server 데이터 모델 확장
|
||||
@ -103,8 +103,8 @@ CREATE TABLE users (
|
||||
...
|
||||
);
|
||||
|
||||
-- workspace_members 테이블
|
||||
CREATE TABLE workspace_members (
|
||||
-- workspace_member 테이블
|
||||
CREATE TABLE workspace_member (
|
||||
workspace_id UUID REFERENCES workspaces(id),
|
||||
user_id UUID REFERENCES users(id),
|
||||
role VARCHAR(50),
|
||||
@ -118,7 +118,7 @@ CREATE TABLE workspace_members (
|
||||
### Company → Workspace 변환 작업
|
||||
|
||||
**Sequential Design 분석으로 영향받는 파일 파악**:
|
||||
1. `app/api/companies.py` → `app/api/workspaces.py`
|
||||
1. `app/api/company.py` → `app/api/workspaces.py`
|
||||
2. `app/providers/slack.py` - OAuth 처리
|
||||
3. `app/api/slack_router.py` - Slack 이벤트 라우팅
|
||||
4. `app/db/init_db.py` - DB 초기화
|
||||
@ -132,9 +132,9 @@ CREATE TABLE workspace_members (
|
||||
|
||||
**API 엔드포인트 변경**:
|
||||
```
|
||||
/api/companies → /api/workspaces
|
||||
/api/companies/{company_id} → /api/workspaces/{workspace_id}
|
||||
/api/companies/subdomain/{subdomain} → /api/workspaces/subdomain/{subdomain}
|
||||
/api/company → /api/workspaces
|
||||
/api/company/{company_id} → /api/workspaces/{workspace_id}
|
||||
/api/company/subdomain/{subdomain} → /api/workspaces/subdomain/{subdomain}
|
||||
```
|
||||
|
||||
## 교훈
|
||||
|
||||
@ -170,7 +170,7 @@ const ROBEING_API_URL = import.meta.env.VITE_ROBEING_API_URL || 'https://ro-bein
|
||||
|
||||
3. **auth-server DB 구축 필요**:
|
||||
- users 테이블
|
||||
- workspace_members 테이블 (user_id, robeing_id 매핑)
|
||||
- workspace_member 테이블 (user_id, robeing_id 매핑)
|
||||
- 로빙 할당 API 엔드포인트
|
||||
|
||||
4. **ChatInterface 수정**:
|
||||
|
||||
@ -41,7 +41,7 @@ git pull
|
||||
```
|
||||
|
||||
**주요 변경 내용**:
|
||||
- `companies.py` → `workspaces.py`로 이름 변경
|
||||
- `company.py` → `workspaces.py`로 이름 변경
|
||||
- 새로운 마이그레이션 파일 추가 (`add_user_workspace_tables.sql`)
|
||||
- 사용자 모델 추가 (`user.py`)
|
||||
- Slack 통합 개선
|
||||
|
||||
@ -32,14 +32,14 @@ robeing-gateway/
|
||||
**핵심 기능**:
|
||||
1. 사용자-로빙 매핑 관리
|
||||
2. 메모리 캐시로 성능 최적화
|
||||
3. 기존 main_db 테이블 활용 (workspaces, workspace_members)
|
||||
3. 기존 main_db 테이블 활용 (workspaces, workspace_member)
|
||||
4. 헬스체크 및 모니터링 엔드포인트
|
||||
|
||||
### 23서버팀 피드백
|
||||
|
||||
**중요 변경사항 - 새 테이블 불필요**:
|
||||
- 기존 main_db의 workspaces, workspace_members 테이블 활용
|
||||
- workspace_members에서 user_id로 robeing 정보 조회
|
||||
- 기존 main_db의 workspaces, workspace_member 테이블 활용
|
||||
- workspace_member에서 user_id로 robeing 정보 조회
|
||||
- JOIN 쿼리로 사용자 → 워크스페이스 → 로빙 매핑
|
||||
|
||||
## 오전 11시 00분 - 배포 문제 해결
|
||||
@ -144,7 +144,7 @@ fetch('http://localhost:8100/api/chat', {
|
||||
### 2. 워크스페이스 할당 테스트
|
||||
```sql
|
||||
-- 사용자를 워크스페이스에 할당
|
||||
INSERT INTO workspace_members (
|
||||
INSERT INTO workspace_member (
|
||||
id, user_id, workspace_id, role, robeing_id, is_active
|
||||
) VALUES (
|
||||
gen_random_uuid(),
|
||||
@ -244,8 +244,8 @@ INSERT INTO users (id, ...) VALUES ('user-happybell80', ...);
|
||||
**두 번째 시도 - role 값 오류**:
|
||||
```sql
|
||||
-- role은 대문자여야 함
|
||||
INSERT INTO workspace_members (..., role, ...) VALUES (..., 'owner', ...); -- X
|
||||
INSERT INTO workspace_members (..., role, ...) VALUES (..., 'OWNER', ...); -- O
|
||||
INSERT INTO workspace_member (..., role, ...) VALUES (..., 'owner', ...); -- X
|
||||
INSERT INTO workspace_member (..., role, ...) VALUES (..., 'OWNER', ...); -- O
|
||||
```
|
||||
|
||||
**최종 수정 버전**:
|
||||
@ -259,7 +259,7 @@ INSERT INTO users (id, email, name) VALUES
|
||||
('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'::uuid, '0914eagle@gmail.com', '전희재'),
|
||||
('cccccccc-cccc-cccc-cccc-cccccccccccc'::uuid, 'hhyong91@gmail.com', '황한용');
|
||||
|
||||
INSERT INTO workspace_members (..., role, ...) VALUES
|
||||
INSERT INTO workspace_member (..., role, ...) VALUES
|
||||
(..., 'OWNER', ...), -- 김종태
|
||||
(..., 'MEMBER', ...); -- 전희재, 황한용
|
||||
```
|
||||
@ -269,7 +269,7 @@ INSERT INTO workspace_members (..., role, ...) VALUES
|
||||
**데이터베이스 상태**:
|
||||
- workspaces: 1개 (ivada-robeing)
|
||||
- users: 3개 (김종태, 전희재, 황한용)
|
||||
- workspace_members: 3개 (모두 rb10508_micro 할당)
|
||||
- workspace_member: 3개 (모두 rb10508_micro 할당)
|
||||
|
||||
**통합 테스트 성공 (오후 2:13)**:
|
||||
1. **인증 흐름**:
|
||||
@ -278,7 +278,7 @@ INSERT INTO workspace_members (..., role, ...) VALUES
|
||||
|
||||
2. **Gateway 라우팅**:
|
||||
- X-User-Id 헤더로 사용자 식별
|
||||
- DB 조회: workspace_members → robeing_id 확인
|
||||
- DB 조회: workspace_member → robeing_id 확인
|
||||
- rb10508_micro (192.168.219.52:10508)로 라우팅
|
||||
|
||||
3. **개인화된 응답**:
|
||||
@ -289,7 +289,7 @@ INSERT INTO workspace_members (..., role, ...) VALUES
|
||||
```
|
||||
Frontend → nginx(/gateway/) → Gateway(8100) → DB 조회
|
||||
↓
|
||||
workspace_members
|
||||
workspace_member
|
||||
↓
|
||||
rb10508_micro → 맞춤 응답
|
||||
```
|
||||
|
||||
@ -99,7 +99,7 @@ npm run build
|
||||
async def get_robeing_info(username: str):
|
||||
query = text("""
|
||||
SELECT ...
|
||||
FROM workspace_members wm
|
||||
FROM workspace_member wm
|
||||
JOIN users u ON wm.user_id = u.id
|
||||
WHERE u.username = :username
|
||||
""")
|
||||
|
||||
@ -34,7 +34,7 @@ async def get_robeing_info(username: str):
|
||||
"""username으로 직접 조회"""
|
||||
query = text("""
|
||||
SELECT ...
|
||||
FROM workspace_members wm
|
||||
FROM workspace_member wm
|
||||
JOIN users u ON wm.user_id = u.id
|
||||
WHERE u.username = :username
|
||||
""")
|
||||
|
||||
@ -29,7 +29,7 @@ CREATE TABLE slack_user_mapping (
|
||||
slack_user_id VARCHAR(100) NOT NULL,
|
||||
slack_workspace_id UUID REFERENCES slack_workspaces(id),
|
||||
user_id UUID REFERENCES users(id) NOT NULL,
|
||||
workspace_member_id UUID REFERENCES workspace_members(id),
|
||||
workspace_member_id UUID REFERENCES workspace_member(id),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(slack_user_id, slack_workspace_id)
|
||||
@ -57,7 +57,7 @@ CREATE TABLE slack_user_mapping (
|
||||
**해결**:
|
||||
```sql
|
||||
GRANT ALL PRIVILEGES ON TABLE slack_user_mapping TO robeings;
|
||||
GRANT SELECT ON users, workspace_members TO robeings;
|
||||
GRANT SELECT ON users, workspace_member TO robeings;
|
||||
ALTER TABLE slack_user_mapping OWNER TO robeings;
|
||||
```
|
||||
|
||||
|
||||
@ -63,7 +63,7 @@ User → rb8001 → skill-email → Gmail API
|
||||
### 2.2 제안: PostgreSQL 기반 관리
|
||||
```sql
|
||||
-- Gmail 토큰 테이블
|
||||
CREATE TABLE gmail_tokens (
|
||||
CREATE TABLE gmail_token (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id VARCHAR(100) UNIQUE NOT NULL,
|
||||
robeing_id VARCHAR(50),
|
||||
@ -268,7 +268,7 @@ class DBCredentialsProvider:
|
||||
async def get_credentials(self, user_id: str):
|
||||
# PostgreSQL에서 토큰 조회
|
||||
token = await db.query(
|
||||
"SELECT * FROM gmail_tokens WHERE user_id = %s",
|
||||
"SELECT * FROM gmail_token WHERE user_id = %s",
|
||||
user_id
|
||||
)
|
||||
return Credentials(**token)
|
||||
|
||||
@ -118,14 +118,14 @@ pgrep -f "ssh.*5433:localhost:5432"
|
||||
### PostgreSQL 접속
|
||||
```bash
|
||||
# SSH를 통한 원격 실행
|
||||
sshpass -p "19800508" ssh -o StrictHostKeyChecking=no admin@124.55.18.179 -p 51123 "PGPASSWORD=robeings psql -h localhost -U robeings -d main_db -c 'SELECT * FROM gmail_tokens'"
|
||||
sshpass -p "19800508" ssh -o StrictHostKeyChecking=no admin@124.55.18.179 -p 51123 "PGPASSWORD=robeings psql -h localhost -U robeings -d main_db -c 'SELECT * FROM gmail_token'"
|
||||
|
||||
# 로컬 터널을 통한 접속 (psql 클라이언트 필요)
|
||||
PGPASSWORD=robeings psql -h localhost -p 5433 -U robeings -d main_db
|
||||
```
|
||||
|
||||
### 주요 테이블
|
||||
- `gmail_tokens`: Gmail OAuth 토큰 저장
|
||||
- `gmail_token`: Gmail OAuth 토큰 저장
|
||||
- `gmail_audit_logs`: Gmail 작업 감사 로그
|
||||
- `robeing_stats`: Robeing 레벨 정보
|
||||
- `slack_user_mapping`: Slack-UUID 매핑 (현재 미사용)
|
||||
|
||||
@ -16,10 +16,10 @@ User: robeings
|
||||
Password: robeings
|
||||
```
|
||||
|
||||
### 1.2 생성된 테이블: `gmail_tokens`
|
||||
### 1.2 생성된 테이블: `gmail_token`
|
||||
|
||||
```sql
|
||||
CREATE TABLE gmail_tokens (
|
||||
CREATE TABLE gmail_token (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id VARCHAR(100) UNIQUE NOT NULL,
|
||||
robeing_id VARCHAR(50),
|
||||
@ -83,12 +83,12 @@ CREATE TABLE gmail_tokens (
|
||||
|
||||
```sql
|
||||
-- 기본 인덱스
|
||||
CREATE INDEX idx_gmail_tokens_user_id ON gmail_tokens(user_id);
|
||||
CREATE INDEX idx_gmail_tokens_robeing_id ON gmail_tokens(robeing_id);
|
||||
CREATE INDEX idx_gmail_token_user_id ON gmail_token(user_id);
|
||||
CREATE INDEX idx_gmail_token_robeing_id ON gmail_token(robeing_id);
|
||||
|
||||
-- JSON 검색용 GIN 인덱스
|
||||
CREATE INDEX idx_gmail_tokens_token_data ON gmail_tokens USING GIN (token_data);
|
||||
CREATE INDEX idx_gmail_tokens_oauth_config ON gmail_tokens USING GIN (oauth_config);
|
||||
CREATE INDEX idx_gmail_token_token_data ON gmail_token USING GIN (token_data);
|
||||
CREATE INDEX idx_gmail_token_oauth_config ON gmail_token USING GIN (oauth_config);
|
||||
```
|
||||
|
||||
---
|
||||
@ -106,8 +106,8 @@ END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- 트리거 생성
|
||||
CREATE TRIGGER update_gmail_tokens_updated_at
|
||||
BEFORE UPDATE ON gmail_tokens
|
||||
CREATE TRIGGER update_gmail_token_updated_at
|
||||
BEFORE UPDATE ON gmail_token
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
```
|
||||
@ -144,19 +144,19 @@ EXECUTE FUNCTION update_updated_at_column();
|
||||
```sql
|
||||
-- 특정 사용자 토큰 조회
|
||||
SELECT token_data->>'access_token' as access_token
|
||||
FROM gmail_tokens
|
||||
FROM gmail_token
|
||||
WHERE user_id = 'test';
|
||||
|
||||
-- 이메일 발송 가능한 사용자 찾기
|
||||
SELECT user_id, robeing_id
|
||||
FROM gmail_tokens
|
||||
FROM gmail_token
|
||||
WHERE scopes @> '["https://www.googleapis.com/auth/gmail.send"]';
|
||||
```
|
||||
|
||||
### 6.2 토큰 업데이트
|
||||
```sql
|
||||
-- 액세스 토큰 갱신
|
||||
UPDATE gmail_tokens
|
||||
UPDATE gmail_token
|
||||
SET token_data = jsonb_set(
|
||||
token_data,
|
||||
'{access_token}',
|
||||
@ -165,7 +165,7 @@ SET token_data = jsonb_set(
|
||||
WHERE user_id = 'test';
|
||||
|
||||
-- 스코프 추가
|
||||
UPDATE gmail_tokens
|
||||
UPDATE gmail_token
|
||||
SET scopes = scopes || '["https://www.googleapis.com/auth/gmail.send"]'::jsonb
|
||||
WHERE user_id = 'heejae';
|
||||
```
|
||||
@ -173,12 +173,12 @@ WHERE user_id = 'heejae';
|
||||
### 6.3 메타데이터 활용
|
||||
```sql
|
||||
-- Slack 사용자와 매핑
|
||||
SELECT * FROM gmail_tokens
|
||||
SELECT * FROM gmail_token
|
||||
WHERE metadata->>'slack_user_id' = 'U091UNVE41M';
|
||||
|
||||
-- 특정 로빙의 Gmail 계정 찾기
|
||||
SELECT user_id, metadata->>'email' as gmail_account
|
||||
FROM gmail_tokens
|
||||
FROM gmail_token
|
||||
WHERE robeing_id = 'rb8001';
|
||||
```
|
||||
|
||||
@ -207,7 +207,7 @@ with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||||
token_data->>'refresh_token' as refresh_token,
|
||||
oauth_config,
|
||||
scopes
|
||||
FROM gmail_tokens
|
||||
FROM gmail_token
|
||||
WHERE user_id = %s
|
||||
""", ('test',))
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
- `AttributeError: 'str' object has no attribute 'get'` 에러 발생
|
||||
|
||||
#### 원인 분석
|
||||
- gmail_tokens 테이블의 metadata 컬럼이 JSONB 타입이지만, asyncpg가 string으로 반환하는 경우 발생
|
||||
- gmail_token 테이블의 metadata 컬럼이 JSONB 타입이지만, asyncpg가 string으로 반환하는 경우 발생
|
||||
- 또는 데이터 저장 시 JSON string으로 저장된 경우
|
||||
|
||||
#### 해결 과정
|
||||
|
||||
@ -139,7 +139,7 @@ GMAIL_API_SCOPES = [
|
||||
|
||||
# PostgreSQL 직접 연동
|
||||
await conn.execute("""
|
||||
INSERT INTO gmail_tokens (...) VALUES (...)
|
||||
INSERT INTO gmail_token (...) VALUES (...)
|
||||
ON CONFLICT (user_id) DO UPDATE SET ...
|
||||
""")
|
||||
```
|
||||
@ -299,7 +299,7 @@ useEffect(() => {
|
||||
2. "Gmail 연결" 버튼 클릭
|
||||
3. auth-server/auth/gmail/passport/ OAuth 시작
|
||||
4. Google 인증 완료
|
||||
5. PostgreSQL gmail_tokens 저장 (is_equipped = true)
|
||||
5. PostgreSQL gmail_token 저장 (is_equipped = true)
|
||||
6. Frontend로 리다이렉트 (?gmail=success)
|
||||
7. 자동 새로고침 및 성공 메시지
|
||||
```
|
||||
|
||||
@ -101,7 +101,7 @@ CREATE INDEX idx_conversations_robeing ON robeing.conversations(robeing_id);
|
||||
1. 51123 서버에서 서비스 재배포 확인
|
||||
2. main_db에 robeing 스키마 및 테이블 생성
|
||||
3. rb10508_micro에 이름→이메일 변환 로직 구현
|
||||
4. workspace_members + robeing.contacts 조합 조회
|
||||
4. workspace_member + robeing.contacts 조합 조회
|
||||
|
||||
## 교훈
|
||||
- 데이터베이스 이름은 용도를 명확히 반영해야 함
|
||||
|
||||
@ -169,7 +169,7 @@ on:
|
||||
```
|
||||
사용자 → rb10508_micro → skill-email(DB 연동) → Gmail API
|
||||
↓ ↓
|
||||
PostgreSQL (gmail_tokens 테이블)
|
||||
PostgreSQL (gmail_token 테이블)
|
||||
↑
|
||||
robeing-monitor (아이템 관리)
|
||||
```
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
↓
|
||||
users 테이블 (UUID)
|
||||
↓
|
||||
workspace_members 테이블
|
||||
workspace_member 테이블
|
||||
(robeing_id 할당)
|
||||
↓
|
||||
로빙 컨테이너
|
||||
@ -35,7 +35,7 @@ workspace_members 테이블
|
||||
|
||||
#### 핵심 테이블 관계
|
||||
- **users**: 사용자 UUID 저장
|
||||
- **workspace_members**: user_id → robeing_id 매핑
|
||||
- **workspace_member**: user_id → robeing_id 매핑
|
||||
- **robeing_stats**: 각 로빙의 레벨, 경험치, 스탯
|
||||
|
||||
#### 서비스 구조
|
||||
@ -74,7 +74,7 @@ export async function getUserRobeing(): Promise<{
|
||||
robeing_id: string;
|
||||
robeing_url: string;
|
||||
} | null> {
|
||||
// workspace_members에서 사용자의 로빙 조회
|
||||
// workspace_member에서 사용자의 로빙 조회
|
||||
}
|
||||
|
||||
export async function getRobeingStats(robeingId: string): Promise<{
|
||||
@ -177,7 +177,7 @@ async def get_stats(robeing_id: str):
|
||||
|
||||
### 1. 시스템 구조 이해의 중요성
|
||||
- 단순한 레벨 표시 문제가 아닌 전체 아키텍처 이해 필요
|
||||
- users → workspace_members → robeing_stats 관계 파악 필수
|
||||
- users → workspace_member → robeing_stats 관계 파악 필수
|
||||
- 다중 로빙 체계와 사용자 매핑 구조 이해
|
||||
|
||||
### 2. 하드코딩 제거의 필요성
|
||||
|
||||
@ -21,12 +21,12 @@ Gmail OAuth 토큰의 자동 갱신 기능을 auth-server에 구현하여, 만
|
||||
### 2.1 현재 DB 정보
|
||||
```
|
||||
Database: main_db (auth_db 아님 주의!)
|
||||
Table: gmail_tokens
|
||||
Table: gmail_token
|
||||
```
|
||||
|
||||
### 2.2 gmail_tokens 테이블 구조
|
||||
### 2.2 gmail_token 테이블 구조
|
||||
```sql
|
||||
CREATE TABLE gmail_tokens (
|
||||
CREATE TABLE gmail_token (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id UUID UNIQUE NOT NULL,
|
||||
robeing_id VARCHAR(50),
|
||||
@ -222,6 +222,6 @@ docker compose down && docker compose up -d --build
|
||||
---
|
||||
|
||||
## 10. 관련 문서
|
||||
- `/home/heejae/DOCS/250818_gmail_tokens_database_setup.md`
|
||||
- `/home/heejae/DOCS/250818_gmail_token_database_setup.md`
|
||||
- `/home/heejae/DOCS/robeing-monitor-integration.md`
|
||||
- `/home/heejae/DOCS/250817_slack_user_mapping_troubleshooting.md`
|
||||
@ -36,7 +36,7 @@ asyncpg.exceptions.DataError: invalid input for query argument $1: 'U091UNVE41M'
|
||||
|
||||
#### 원인
|
||||
- robeing-monitor가 Slack user_id를 UUID로 변환하지 않고 직접 DB 조회
|
||||
- PostgreSQL gmail_tokens 테이블의 user_id 컬럼은 UUID 타입
|
||||
- PostgreSQL gmail_token 테이블의 user_id 컬럼은 UUID 타입
|
||||
|
||||
### 2.2 Gateway 프록시 문제
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
|
||||
### 2.1 테이블 구조 파악
|
||||
```sql
|
||||
gmail_tokens 테이블:
|
||||
gmail_token 테이블:
|
||||
- 구조 혼재: 신규 컬럼(access_token, refresh_token)과 기존 컬럼(token_data, oauth_config)
|
||||
- 두 가지 형식 모두 지원 필요
|
||||
```
|
||||
@ -77,7 +77,7 @@ async def refresh_gmail_token(user_id: str):
|
||||
cur.execute('''
|
||||
SELECT access_token, refresh_token, expires_at,
|
||||
token_data, oauth_config, metadata, expiry
|
||||
FROM gmail_tokens
|
||||
FROM gmail_token
|
||||
WHERE user_id = %s::uuid
|
||||
''', (user_id,))
|
||||
|
||||
@ -90,7 +90,7 @@ async def refresh_gmail_token(user_id: str):
|
||||
|
||||
# 4. 새 토큰으로 DB 업데이트
|
||||
cur.execute('''
|
||||
UPDATE gmail_tokens
|
||||
UPDATE gmail_token
|
||||
SET access_token = %s, expires_at = %s, ...
|
||||
''')
|
||||
```
|
||||
@ -108,7 +108,7 @@ oauth_config = {
|
||||
|
||||
# INSERT 쿼리에 oauth_config 추가
|
||||
await conn.execute("""
|
||||
INSERT INTO gmail_tokens (
|
||||
INSERT INTO gmail_token (
|
||||
..., oauth_config, ...
|
||||
) VALUES (..., $8, ...)
|
||||
""", ..., json.dumps(oauth_config), ...)
|
||||
@ -122,7 +122,7 @@ await conn.execute("""
|
||||
**문제**: `token_data` NOT NULL 제약으로 INSERT 실패
|
||||
**해결**: 51123 서버에서 직접 컬럼 제약 제거
|
||||
```sql
|
||||
ALTER TABLE gmail_tokens ALTER COLUMN token_data DROP NOT NULL;
|
||||
ALTER TABLE gmail_token ALTER COLUMN token_data DROP NOT NULL;
|
||||
```
|
||||
|
||||
### 4.2 UUID 타입 오류
|
||||
@ -144,14 +144,14 @@ database_url = os.getenv("DATABASE_URL", "postgresql://robeings:robeings@192.168
|
||||
**문제**: `access_token` 컬럼 누락으로 "column does not exist" 에러
|
||||
**해결**: 필요한 컬럼들 추가
|
||||
```sql
|
||||
ALTER TABLE gmail_tokens
|
||||
ALTER TABLE gmail_token
|
||||
ADD COLUMN IF NOT EXISTS access_token TEXT,
|
||||
ADD COLUMN IF NOT EXISTS refresh_token TEXT,
|
||||
ADD COLUMN IF NOT EXISTS token_type VARCHAR DEFAULT 'Bearer',
|
||||
ADD COLUMN IF NOT EXISTS expires_at FLOAT;
|
||||
|
||||
-- 기존 token_data에서 새 컬럼으로 데이터 마이그레이션
|
||||
UPDATE gmail_tokens
|
||||
UPDATE gmail_token
|
||||
SET
|
||||
access_token = token_data->>'access_token',
|
||||
refresh_token = token_data->>'refresh_token'
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
-- 현재 DB 상태: 모든 사용자 토큰 만료
|
||||
SELECT username, access_token IS NOT NULL as has_token,
|
||||
expires_at < extract(epoch from now()) as is_expired
|
||||
FROM gmail_tokens;
|
||||
FROM gmail_token;
|
||||
|
||||
결과:
|
||||
happybell80 | t (있음) | t (만료됨)
|
||||
@ -49,7 +49,7 @@ sequenceDiagram
|
||||
|
||||
Cron->>RB: POST /api/cron/daily-summary
|
||||
RB->>Email: GET /messages?user_id={slack_id}
|
||||
Email->>DB: SELECT token_data FROM gmail_tokens
|
||||
Email->>DB: SELECT token_data FROM gmail_token
|
||||
DB-->>Email: access_token: expired ❌
|
||||
Email-->>RB: 500 Internal Server Error
|
||||
RB->>Slack: 불완전한 브리핑 전송<br/>(이메일 없이 뉴스만)
|
||||
@ -73,7 +73,7 @@ sequenceDiagram
|
||||
Google->>Auth: Callback with code
|
||||
Auth->>Google: Exchange code for tokens
|
||||
Google-->>Auth: access_token, refresh_token
|
||||
Auth->>DB: UPDATE gmail_tokens<br/>SET access_token, refresh_token
|
||||
Auth->>DB: UPDATE gmail_token<br/>SET access_token, refresh_token
|
||||
Auth-->>Front: 인증 완료
|
||||
```
|
||||
|
||||
@ -95,7 +95,7 @@ curl -X GET "http://localhost:9000/api/gmail/auth?user_id=1e16e9d5-59f3-54da-a66
|
||||
# 4. 토큰 저장 확인
|
||||
export PGPASSWORD=robeings
|
||||
psql -h localhost -U robeings -d main_db -c \
|
||||
"SELECT user_id, access_token IS NOT NULL FROM gmail_tokens WHERE user_id = '1e16e9d5-59f3-54da-a661-8abeabff4230';"
|
||||
"SELECT user_id, access_token IS NOT NULL FROM gmail_token WHERE user_id = '1e16e9d5-59f3-54da-a661-8abeabff4230';"
|
||||
|
||||
# 5. 브리핑 수동 테스트
|
||||
curl -X POST http://192.168.219.52:8001/api/cron/daily-summary \
|
||||
@ -123,7 +123,7 @@ psql -h localhost -U robeings -d main_db -c \
|
||||
gt.expires_at < extract(epoch from now()) as is_expired,
|
||||
gt.metadata->>'email' as email
|
||||
FROM users u
|
||||
LEFT JOIN gmail_tokens gt ON u.id = gt.user_id
|
||||
LEFT JOIN gmail_token gt ON u.id = gt.user_id
|
||||
WHERE u.username IN ('happybell80', '0914eagle', 'cdctfm');"
|
||||
```
|
||||
|
||||
@ -141,7 +141,7 @@ curl -s "http://localhost:9000/api/gmail/auth?user_id=1e16e9d5-59f3-54da-a661-8a
|
||||
# 4. 인증 성공 확인
|
||||
psql -h localhost -U robeings -d main_db -c \
|
||||
"SELECT access_token IS NOT NULL as success
|
||||
FROM gmail_tokens
|
||||
FROM gmail_token
|
||||
WHERE user_id = '1e16e9d5-59f3-54da-a661-8abeabff4230';"
|
||||
```
|
||||
|
||||
@ -190,7 +190,7 @@ curl -s "http://localhost:9000/api/gmail/auth?user_id=69ae4ea9-a15f-5110-9f5d-65
|
||||
### 7.1 문제 상황
|
||||
- **증상**: Slack DM 대화가 PostgreSQL에 저장 안됨
|
||||
- **ChromaDB**: ✅ 정상 저장
|
||||
- **PostgreSQL**: ❌ 저장 실패 (conversation_logs 테이블 0 rows)
|
||||
- **PostgreSQL**: ❌ 저장 실패 (conversation_log 테이블 0 rows)
|
||||
|
||||
### 7.2 대화 저장 플로우 (현재: State Service 사용 안 함)
|
||||
```mermaid
|
||||
@ -207,7 +207,7 @@ sequenceDiagram
|
||||
RB->>Chroma: store_memory()
|
||||
Chroma-->>RB: ✅ 저장 성공<br/>ID: 2a776b26...
|
||||
|
||||
RB->>PG: 직접 INSERT INTO conversation_logs
|
||||
RB->>PG: 직접 INSERT INTO conversation_log
|
||||
PG-->>RB: ✅ 저장 성공
|
||||
|
||||
Note over RB: State Service 없이<br/>직접 DB 연결
|
||||
|
||||
@ -22,7 +22,7 @@ username: happybell80
|
||||
email: goeun2dc@gmail.com
|
||||
UUID: 1e16e9d5-59f3-54da-a661-8abeabff4230
|
||||
|
||||
-- workspace_members 테이블
|
||||
-- workspace_member 테이블
|
||||
happybell80 → rb8001 (포트 8001)
|
||||
eagle0914 → rb10508_micro (포트 10508)
|
||||
```
|
||||
|
||||
@ -203,7 +203,7 @@ WHERE robeing_id = 'rb8001';
|
||||
|
||||
- **DB 테이블**:
|
||||
- `robeing_stats` - 실제 스탯 저장
|
||||
- `workspace_members` - 사용자-로빙 매핑
|
||||
- `workspace_member` - 사용자-로빙 매핑
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -142,7 +142,7 @@ Stats request from user: happybell80 for robeing: undefined
|
||||
|
||||
### 4.3 대화 저장 확인 ❌
|
||||
```sql
|
||||
SELECT COUNT(*) FROM conversation_logs; -- 0건
|
||||
SELECT COUNT(*) FROM conversation_log; -- 0건
|
||||
-- rb8001에서 DB 저장 로직 미구현
|
||||
```
|
||||
|
||||
|
||||
@ -100,7 +100,7 @@ async def message_endpoint(request: MessageRequest):
|
||||
user_id=request.user_id or "web_user",
|
||||
task_type="chat",
|
||||
context=request.context,
|
||||
channel="web" # ⚠️ Slack DM과 동일 (개선: 250828_conversation_logs_channel_구분_개선.md)
|
||||
channel="web" # ⚠️ Slack DM과 동일 (개선: 250828_conversation_log_channel_구분_개선.md)
|
||||
)
|
||||
|
||||
# Frontend가 기대하는 응답 형식
|
||||
@ -195,7 +195,7 @@ rb8001(8001) → /api/message 처리
|
||||
- Gateway 로그: 라우팅 성공
|
||||
- rb8001 로그: 메시지 처리
|
||||
- ChromaDB: 대화 저장
|
||||
- PostgreSQL: conversation_logs 기록
|
||||
- PostgreSQL: conversation_log 기록
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@ grep -r "save_conversation\|store_memory" rb8001/
|
||||
PGPASSWORD=robeings psql -h 192.168.219.45 -U robeings -d main_db -c "\dt"
|
||||
|
||||
# 결과:
|
||||
# - conversation_logs 테이블 존재 ✅
|
||||
# - conversation_log 테이블 존재 ✅
|
||||
# - robeing_stats 테이블 존재 ✅
|
||||
# - 직접 연결 가능
|
||||
```
|
||||
@ -158,18 +158,18 @@ graph LR
|
||||
```
|
||||
|
||||
2. **원인 분석**
|
||||
- conversation_logs 테이블의 user_id가 UUID 타입
|
||||
- conversation_log 테이블의 user_id가 UUID 타입
|
||||
- rb8001은 Slack user ID (문자열) 전송
|
||||
- UUID 변환 불가능한 값으로 저장 실패
|
||||
|
||||
### DB 스키마 수정 (51123 서버)
|
||||
```sql
|
||||
-- slack_user_id 컬럼 추가
|
||||
ALTER TABLE conversation_logs
|
||||
ALTER TABLE conversation_log
|
||||
ADD COLUMN slack_user_id VARCHAR(255);
|
||||
|
||||
-- user_id를 nullable로 변경
|
||||
ALTER TABLE conversation_logs
|
||||
ALTER TABLE conversation_log
|
||||
ALTER COLUMN user_id DROP NOT NULL;
|
||||
```
|
||||
|
||||
@ -191,7 +191,7 @@ conversation_log = ConversationLog(
|
||||
```python
|
||||
class ConversationLog(Base):
|
||||
"""대화 로그 테이블"""
|
||||
__tablename__ = "conversation_logs"
|
||||
__tablename__ = "conversation_log"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
robeing_id = Column(String, index=True)
|
||||
@ -223,13 +223,13 @@ docker logs rb8001 --tail 100 | grep -E "ChromaDB|PostgreSQL|saved"
|
||||
### DB 확인
|
||||
```sql
|
||||
-- PostgreSQL 저장 확인
|
||||
SELECT COUNT(*) FROM conversation_logs
|
||||
SELECT COUNT(*) FROM conversation_log
|
||||
WHERE robeing_id = 'rb8001'
|
||||
AND timestamp > NOW() - INTERVAL '1 hour';
|
||||
|
||||
-- 최근 대화 확인
|
||||
SELECT user_id, message, response, timestamp
|
||||
FROM conversation_logs
|
||||
FROM conversation_log
|
||||
WHERE robeing_id = 'rb8001'
|
||||
ORDER BY timestamp DESC
|
||||
LIMIT 5;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# ID 체계 정리 및 conversation_logs 저장 문제 해결
|
||||
# ID 체계 정리 및 conversation_log 저장 문제 해결
|
||||
|
||||
## 작성일: 2025-08-26 (수정: 2025-08-28)
|
||||
## 작성자: 서버 관리자
|
||||
@ -12,12 +12,12 @@
|
||||
|
||||
### 1.1 발견된 문제들
|
||||
1. **user_id UUID 타입 문제**
|
||||
- PostgreSQL의 conversation_logs 테이블에서 user_id가 UUID 타입
|
||||
- PostgreSQL의 conversation_log 테이블에서 user_id가 UUID 타입
|
||||
- "system"이나 Slack user_id (예: U0925SXQFDK)는 UUID가 아님
|
||||
- UUID 변환 시도 시 오류 발생
|
||||
|
||||
2. **대화 저장 전혀 안됨**
|
||||
- conversation_logs 테이블 완전히 비어있음 (0 rows)
|
||||
- conversation_log 테이블 완전히 비어있음 (0 rows)
|
||||
- 게이트웨이 로그에 저장 API 호출 없음
|
||||
- DB 설정 오류 (auth_db → main_db)
|
||||
|
||||
@ -27,28 +27,28 @@
|
||||
|
||||
### 2.1 문제점
|
||||
#### 다양한 ID 타입 혼재
|
||||
- **UUID**: users.id, workspace_members.id, slack_user_mapping.user_id
|
||||
- **UUID**: users.id, workspace_member.id, slack_user_mapping.user_id
|
||||
- **VARCHAR**: robeing_id, slack_user_id, slack_id, channel_id
|
||||
- **INTEGER**: conversation_logs.id, gmail_tokens.id
|
||||
- **INTEGER**: conversation_log.id, gmail_token.id
|
||||
|
||||
#### 2025-08-28 확인
|
||||
- gmail_tokens.slack_user_id: VARCHAR(100)
|
||||
- gmail_tokens.user_id: UUID (FK → users.id)
|
||||
- gmail_token.slack_user_id: VARCHAR(100)
|
||||
- gmail_token.user_id: UUID (FK → users.id)
|
||||
- Slack ID와 UUID 동시 저장
|
||||
|
||||
#### 변환 문제
|
||||
- UUID ↔ Slack ID 변환 로직 불일치
|
||||
- conversation_logs의 user_id(UUID)에 Slack ID 저장 시도로 실패
|
||||
- conversation_log의 user_id(UUID)에 Slack ID 저장 시도로 실패
|
||||
|
||||
### 2.2 테이블별 ID 현황
|
||||
|
||||
| 테이블 | Primary Key | 외래 키/참조 ID |
|
||||
|--------|------------|---------------|
|
||||
| **users** | id (UUID) | oauth_id (VARCHAR) |
|
||||
| **workspace_members** | id (UUID) | user_id (UUID), workspace_id (UUID), robeing_id (VARCHAR) |
|
||||
| **gmail_tokens** | id (INT) | user_id (UUID), slack_id (VARCHAR), robeing_id (VARCHAR) |
|
||||
| **workspace_member** | id (UUID) | user_id (UUID), workspace_id (UUID), robeing_id (VARCHAR) |
|
||||
| **gmail_token** | id (INT) | user_id (UUID), slack_id (VARCHAR), robeing_id (VARCHAR) |
|
||||
| **slack_user_mapping** | id (UUID) | user_id (UUID), slack_user_id (VARCHAR), workspace_member_id (UUID) |
|
||||
| **conversation_logs** | id (INT) | user_id (UUID), slack_user_id (VARCHAR)*, robeing_id (VARCHAR) |
|
||||
| **conversation_log** | id (INT) | user_id (UUID), slack_user_id (VARCHAR)*, robeing_id (VARCHAR) |
|
||||
|
||||
*slack_user_id는 이 문제 해결을 위해 새로 추가한 컬럼
|
||||
|
||||
@ -60,13 +60,13 @@
|
||||
```
|
||||
[Slack ID] ──┬──> [slack_user_mapping] ──> [users.id (UUID)]
|
||||
│
|
||||
├──> [gmail_tokens.slack_id]
|
||||
├──> [gmail_token.slack_id]
|
||||
│
|
||||
└──> [conversation_logs.slack_user_id]
|
||||
└──> [conversation_log.slack_user_id]
|
||||
|
||||
[users.id] ──┬──> [workspace_members.user_id]
|
||||
├──> [gmail_tokens.user_id]
|
||||
├──> [conversation_logs.user_id]
|
||||
[users.id] ──┬──> [workspace_member.user_id]
|
||||
├──> [gmail_token.user_id]
|
||||
├──> [conversation_log.user_id]
|
||||
└──> [robeing_stats.user_id]
|
||||
```
|
||||
|
||||
@ -86,10 +86,10 @@ U092F7FQ55L | cdctfm
|
||||
### 4.1 단기 해결책 (즉시 적용) ✅ 완료
|
||||
```sql
|
||||
-- 1. user_id를 nullable로 변경
|
||||
ALTER TABLE conversation_logs ALTER COLUMN user_id DROP NOT NULL;
|
||||
ALTER TABLE conversation_log ALTER COLUMN user_id DROP NOT NULL;
|
||||
|
||||
-- 2. slack_user_id 컬럼 추가
|
||||
ALTER TABLE conversation_logs ADD COLUMN slack_user_id VARCHAR(100);
|
||||
ALTER TABLE conversation_log ADD COLUMN slack_user_id VARCHAR(100);
|
||||
```
|
||||
|
||||
### 4.2 중기 해결책 (표준화)
|
||||
@ -100,8 +100,8 @@ ALTER TABLE conversation_logs ADD COLUMN slack_user_id VARCHAR(100);
|
||||
|
||||
**작업 필요**:
|
||||
```sql
|
||||
-- gmail_tokens 테이블 컬럼명 변경
|
||||
ALTER TABLE gmail_tokens RENAME COLUMN slack_id TO slack_user_id;
|
||||
-- gmail_token 테이블 컬럼명 변경
|
||||
ALTER TABLE gmail_token RENAME COLUMN slack_id TO slack_user_id;
|
||||
```
|
||||
|
||||
### 4.3 장기 해결책 (구조 개선)
|
||||
@ -124,7 +124,7 @@ SELECT DISTINCT
|
||||
wm.robeing_id
|
||||
FROM users u
|
||||
LEFT JOIN slack_user_mapping sum ON u.id = sum.user_id
|
||||
LEFT JOIN workspace_members wm ON u.id = wm.user_id;
|
||||
LEFT JOIN workspace_member wm ON u.id = wm.user_id;
|
||||
```
|
||||
|
||||
---
|
||||
@ -163,8 +163,8 @@ DATABASE_URL=postgresql://robeings:robeings@localhost:5433/main_db
|
||||
|
||||
## 6. 작업 완료 현황
|
||||
|
||||
1. ✅ conversation_logs에 slack_user_id 추가 (완료)
|
||||
2. ✅ gmail_tokens의 slack_user_id 컬럼 확인 (이미 존재, slack_id 컬럼 없음 - 2025-08-27 확인)
|
||||
1. ✅ conversation_log에 slack_user_id 추가 (완료)
|
||||
2. ✅ gmail_token의 slack_user_id 컬럼 확인 (이미 존재, slack_id 컬럼 없음 - 2025-08-27 확인)
|
||||
3. ✅ **뉴스 키워드 하드코딩 제거** (2025-08-26 21:00 완료)
|
||||
- rb8001/app/skills/dm_skill.py 수정 (커밋: aed931e)
|
||||
- user_preferences 테이블 활용
|
||||
@ -180,7 +180,7 @@ DATABASE_URL=postgresql://robeings:robeings@localhost:5433/main_db
|
||||
### 7.1 대화 저장 확인
|
||||
```sql
|
||||
-- 저장된 대화 확인
|
||||
SELECT COUNT(*) FROM conversation_logs;
|
||||
SELECT COUNT(*) FROM conversation_log;
|
||||
|
||||
-- 최근 대화 로그
|
||||
SELECT
|
||||
@ -189,7 +189,7 @@ SELECT
|
||||
cl.message,
|
||||
cl.response,
|
||||
cl.timestamp
|
||||
FROM conversation_logs cl
|
||||
FROM conversation_log cl
|
||||
ORDER BY cl.timestamp DESC
|
||||
LIMIT 5;
|
||||
```
|
||||
@ -204,7 +204,7 @@ SELECT
|
||||
wm.robeing_id
|
||||
FROM slack_user_mapping sum
|
||||
JOIN users u ON sum.user_id = u.id
|
||||
LEFT JOIN workspace_members wm ON u.id = wm.user_id;
|
||||
LEFT JOIN workspace_member wm ON u.id = wm.user_id;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
## 작성일: 2025-08-26
|
||||
## 작성자: 51124 서버 담당
|
||||
## 상태: ✅ 완전 해결 (ChromaDB ✅, PostgreSQL ✅, Foreign key ✅)
|
||||
## 영향: PostgreSQL conversation_logs 정상 저장
|
||||
## 영향: PostgreSQL conversation_log 정상 저장
|
||||
## 최종 업데이트: 2025-08-26 19:30
|
||||
|
||||
---
|
||||
@ -51,12 +51,12 @@ LINE 1: ... VALUES ('rb8001', 'test_user_123', 'web', ...
|
||||
|
||||
### 2.3 PostgreSQL 스키마 문제
|
||||
```sql
|
||||
-- conversation_logs 테이블 스키마
|
||||
-- conversation_log 테이블 스키마
|
||||
user_id UUID -- 문제: UUID 타입만 허용
|
||||
slack_user_id VARCHAR(100) -- 추가됨 (250826 문서)
|
||||
|
||||
-- 실제 저장 시도
|
||||
INSERT INTO conversation_logs (user_id, ...)
|
||||
INSERT INTO conversation_log (user_id, ...)
|
||||
VALUES ('test_user_123', ...) -- 실패: UUID 형식 아님
|
||||
```
|
||||
|
||||
@ -168,7 +168,7 @@ curl -X POST http://localhost:8001/api/message \
|
||||
|
||||
# PostgreSQL 확인
|
||||
psql -h localhost -p 5433 -U robeings -d main_db \
|
||||
-c "SELECT * FROM conversation_logs ORDER BY timestamp DESC LIMIT 1;"
|
||||
-c "SELECT * FROM conversation_log ORDER BY timestamp DESC LIMIT 1;"
|
||||
|
||||
# ChromaDB 확인 (수정 후)
|
||||
docker exec rb8001 python -c "
|
||||
@ -204,7 +204,7 @@ print('Collections:', client.list_collections())
|
||||
|
||||
### 데이터 위치
|
||||
- ChromaDB: `/home/admin/ivada_project/rb8001/chroma_db/`
|
||||
- PostgreSQL: `main_db.conversation_logs` 테이블
|
||||
- PostgreSQL: `main_db.conversation_log` 테이블
|
||||
|
||||
---
|
||||
|
||||
@ -231,7 +231,7 @@ print('Collections:', client.list_collections())
|
||||
|
||||
### 12.2 ⚠️ 남은 문제
|
||||
1. **51124 서버 rb8001**:
|
||||
- conversation_logs 저장 안됨 (최근 데이터 14시간 전)
|
||||
- conversation_log 저장 안됨 (최근 데이터 14시간 전)
|
||||
- UUID 타입 에러로 PostgreSQL 저장 실패 중
|
||||
- ChromaDB만 저장되고 PostgreSQL은 실패
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
|--------|------------|------------|------|
|
||||
| slack_user_mapping | slack_user_id | slack_user_id | VARCHAR(100) |
|
||||
| gmail_token | ~~slack_id~~ ❌ | **slack_user_id** ✅ | VARCHAR(100) |
|
||||
| conversation_logs | slack_user_id | slack_user_id | VARCHAR(100) |
|
||||
| conversation_log | slack_user_id | slack_user_id | VARCHAR(100) |
|
||||
|
||||
### ✅ 적용 완료
|
||||
|
||||
|
||||
@ -83,7 +83,7 @@ const userId = localStorage.getItem('user_id') || 'default_user';
|
||||
|
||||
### 2.5 Database
|
||||
```sql
|
||||
-- conversation_logs 테이블
|
||||
-- conversation_log 테이블
|
||||
user_id UUID -- UUID 타입 요구
|
||||
slack_user_id VARCHAR(100) -- username이 여기 저장됨
|
||||
|
||||
@ -179,14 +179,14 @@ SELECT id, username FROM users WHERE username='happybell80';
|
||||
# database.py:184: SELECT id::text as user_id
|
||||
# username → UUID 변환 정상 작동
|
||||
|
||||
# conversation_logs 확인 (51124 보고)
|
||||
# conversation_log 확인 (51124 보고)
|
||||
# user_id: NULL, slack_user_id: 'happybell80'
|
||||
# "Non-UUID user_id" 에러 발생
|
||||
```
|
||||
|
||||
### 5.2 수정 후 검증
|
||||
- JWT `sub` 필드가 UUID 형식 (36자)
|
||||
- conversation_logs.user_id에 UUID 저장
|
||||
- conversation_log.user_id에 UUID 저장
|
||||
- ChromaDB metadata.user_id가 UUID
|
||||
|
||||
---
|
||||
@ -204,7 +204,7 @@ SELECT id, username FROM users WHERE username='happybell80';
|
||||
|
||||
## 7. 관련 문서
|
||||
|
||||
- [ID 체계 정리 (250826)](./250826_id_체계_정리_및_conversation_logs_문제_해결.md)
|
||||
- [ID 체계 정리 (250826)](./250826_id_체계_정리_및_conversation_log_문제_해결.md)
|
||||
- [JWT 인증 구현 (250827)](./250827_JWT_인증_구현_COMPLETED.md)
|
||||
- [Slack ID 표준화 (250826)](./250826_slack_id_column_standardization.md)
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ const activities: ActivityLog[] = [...]; // 하드코딩
|
||||
const scheduledTasks: ScheduledTask[] = [...]; // 하드코딩
|
||||
```
|
||||
- 실제 데이터 조회 API 없음
|
||||
- conversation_logs 테이블 조회 엔드포인트 필요
|
||||
- conversation_log 테이블 조회 엔드포인트 필요
|
||||
|
||||
### 3.4 ✅ 해결됨: API 구현
|
||||
- **robeing-monitor**: preferences API 완전 구현
|
||||
|
||||
@ -148,7 +148,7 @@ rb8001이 모든 사용자 대화를 하나의 ChromaDB 컬렉션에 저장:
|
||||
- 자동 갱신 실패 시 알림
|
||||
|
||||
2. **DB 컬럼명 표준화**
|
||||
- gmail_tokens.slack_id → slack_user_id
|
||||
- gmail_token.slack_id → slack_user_id
|
||||
- 서버 작업 필요
|
||||
|
||||
---
|
||||
|
||||
@ -67,7 +67,7 @@ workspace (로빙 1개)
|
||||
|
||||
### Phase 3: 사용자 격리 ✅ 완료 (2025-08-28 18:15)
|
||||
- [x] ChromaDB 사용자별 컬렉션 (rb8001_{user_uuid})
|
||||
- [x] conversation_logs UUID 저장 구현
|
||||
- [x] conversation_log UUID 저장 구현
|
||||
- [x] 완전한 사용자 대화 격리
|
||||
|
||||
---
|
||||
@ -108,7 +108,7 @@ async def get_uuid(slack_id: str):
|
||||
- rb8001: JWT 검증 구현 ✅
|
||||
- rb8001: Slack ID → UUID 자동 변환 ✅
|
||||
- ChromaDB: 사용자별 컬렉션 격리 ✅
|
||||
- conversation_logs: UUID 저장 ✅
|
||||
- conversation_log: UUID 저장 ✅
|
||||
|
||||
---
|
||||
|
||||
@ -117,7 +117,7 @@ async def get_uuid(slack_id: str):
|
||||
### ✅ 검증 완료
|
||||
1. **JWT 인증**: UUID 추출 성공 (1e16e9d5-59f3-54da-a661-8abeabff4230)
|
||||
2. **ChromaDB 격리**: rb8001_{user_uuid} 컬렉션 생성 확인
|
||||
3. **PostgreSQL**: conversation_logs에 UUID 저장 확인
|
||||
3. **PostgreSQL**: conversation_log에 UUID 저장 확인
|
||||
4. **Slack 변환**: Slack ID → UUID 자동 변환 작동
|
||||
5. **metadata None 처리**: Frontend 접속 시 slack_user_id=None 필터링 구현 ([250828_ChromaDB_metadata_None_error.md](250828_ChromaDB_metadata_None_error.md))
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# conversation_logs 채널 구분 개선
|
||||
# conversation_log 채널 구분 개선
|
||||
|
||||
**날짜**: 2025-08-28
|
||||
**테이블**: conversation_logs
|
||||
**테이블**: conversation_log
|
||||
**상태**: ✅ 해결 완료 (2025-08-28)
|
||||
|
||||
## 현재 상황 (DB 확인)
|
||||
@ -39,7 +39,7 @@ Slack DM은 여전히 "D..."로 정상 저장됩니다.
|
||||
|
||||
### Phase 2: DB 스키마 개선 (선택)
|
||||
```sql
|
||||
ALTER TABLE conversation_logs
|
||||
ALTER TABLE conversation_log
|
||||
ADD COLUMN thread_ts VARCHAR(20), -- 쓰레드 구분
|
||||
ADD COLUMN channel_type VARCHAR(20); -- public_channel/private_channel/im/mpim
|
||||
```
|
||||
|
||||
@ -70,7 +70,7 @@ async def get_user_mapping(identifier: str, db: Session = Depends(get_db)):
|
||||
query = text("""
|
||||
SELECT u.id as user_id, u.username, u.email, wm.robeing_id
|
||||
FROM users u
|
||||
LEFT JOIN workspace_members wm ON u.id = wm.user_id
|
||||
LEFT JOIN workspace_member wm ON u.id = wm.user_id
|
||||
WHERE u.id = :user_id
|
||||
""")
|
||||
result = db.execute(query, {"user_id": identifier}).first()
|
||||
@ -144,7 +144,7 @@ async def route_message(self, message: str, user_id: str, ...):
|
||||
### 2.7 Gateway 기본값 변경
|
||||
**파일**: `robeing-gateway/app/database.py`
|
||||
```python
|
||||
# spaceboum 등 workspace_members 없는 사용자를 위해
|
||||
# spaceboum 등 workspace_member 없는 사용자를 위해
|
||||
DEFAULT_ROBEING_PORT = int(os.getenv('DEFAULT_ROBEING_PORT', '8001')) # 10508 → 8001
|
||||
DEFAULT_ROBEING_ID = os.getenv('DEFAULT_ROBEING_ID', 'rb8001') # rb10508_test → rb8001
|
||||
```
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
## 1. 문제 상황
|
||||
|
||||
- **현상**: rb8001이 ChromaDB 벡터 검색만 참조하여 엉뚱한 답변
|
||||
- **원인**: PostgreSQL conversation_logs의 최근 대화 미참조
|
||||
- **원인**: PostgreSQL conversation_log의 최근 대화 미참조
|
||||
- **영향**: 직전 대화 컨텍스트 손실, 일관성 없는 응답
|
||||
- **테스트**: "내 이름은 김종태" → "내 이름은?" → "모릅니다" 응답
|
||||
|
||||
|
||||
@ -12,8 +12,8 @@
|
||||
Slack OAuth로 로그인한 사용자가 Robeing 워크스페이스에 자동 할당되지 않음
|
||||
|
||||
### 테스트 케이스
|
||||
- spaceboum (Google 로그인): workspace_members 없음 → 기본값 rb8001
|
||||
- 홍태주 (Slack 로그인): workspace_members 없음 → 기본값 rb8001
|
||||
- spaceboum (Google 로그인): workspace_member 없음 → 기본값 rb8001
|
||||
- 홍태주 (Slack 로그인): workspace_member 없음 → 기본값 rb8001
|
||||
|
||||
---
|
||||
|
||||
@ -34,7 +34,7 @@ Slack OAuth로 로그인한 사용자가 Robeing 워크스페이스에 자동
|
||||
- 매핑 있으면: 기존 User 사용
|
||||
- 매핑 없으면: 새 User 생성
|
||||
|
||||
4. **workspace_members 추가**: ❌ **없음**
|
||||
4. **workspace_member 추가**: ❌ **없음**
|
||||
- Robeing 워크스페이스 할당 로직 부재
|
||||
- SlackWorkspace ≠ Robeing Workspace (별개 개념)
|
||||
|
||||
@ -45,7 +45,7 @@ Slack OAuth로 로그인한 사용자가 Robeing 워크스페이스에 자동
|
||||
### 핵심 개념: team_id = workspace_id
|
||||
|
||||
- **Slack team_id**: Slack 워크스페이스의 고유 ID (T로 시작)
|
||||
- **workspace_members.workspace_id**: team_id를 저장하는 필드
|
||||
- **workspace_member.workspace_id**: team_id를 저장하는 필드
|
||||
- **즉, team_id가 그대로 workspace_id로 사용됨**
|
||||
|
||||
#### slack_workspaces 테이블
|
||||
@ -53,7 +53,7 @@ Slack OAuth로 로그인한 사용자가 Robeing 워크스페이스에 자동
|
||||
- **주요 컬럼**: team_id (Slack ID), team_name, bot_token
|
||||
- **현재 데이터**: GoodGang Labs (T035VFRKCN6), test (T097FCTDVEX)
|
||||
|
||||
#### workspace_members 테이블
|
||||
#### workspace_member 테이블
|
||||
- **용도**: 사용자와 Slack 워크스페이스 연결
|
||||
- **주요 컬럼**: user_id, workspace_id (=team_id), robeing_id
|
||||
- **문제**: Slack 로그인 시 자동 추가 안 됨
|
||||
@ -64,13 +64,13 @@ Slack OAuth로 로그인한 사용자가 Robeing 워크스페이스에 자동
|
||||
| users | 사용자 정보 | ✅ 생성됨 |
|
||||
| slack_user_mapping | Slack ID ↔ UUID | ✅ 생성됨 |
|
||||
| slack_workspaces | Slack 팀 정보 | ✅ 조회됨 |
|
||||
| workspace_members | **사용자-워크스페이스 멤버십** | ❌ 추가 안 됨 |
|
||||
| workspace_member | **사용자-워크스페이스 멤버십** | ❌ 추가 안 됨 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 영향
|
||||
|
||||
- 모든 Slack 로그인 사용자가 workspace_members 없음
|
||||
- 모든 Slack 로그인 사용자가 workspace_member 없음
|
||||
- Gateway가 기본값(rb8001 또는 rb10508) 사용
|
||||
- 사용자별 Robeing 할당 불가능
|
||||
|
||||
@ -82,10 +82,10 @@ Slack OAuth로 로그인한 사용자가 Robeing 워크스페이스에 자동
|
||||
|
||||
304번 줄 이후 추가:
|
||||
```python
|
||||
# workspace_members 추가 (team_id = workspace_id)
|
||||
# workspace_member 추가 (team_id = workspace_id)
|
||||
if team_id and user:
|
||||
db.execute(text("""
|
||||
INSERT INTO workspace_members (user_id, workspace_id, robeing_id)
|
||||
INSERT INTO workspace_member (user_id, workspace_id, robeing_id)
|
||||
VALUES (:user_id, :workspace_id, :robeing_id)
|
||||
ON CONFLICT (user_id, workspace_id) DO UPDATE
|
||||
SET robeing_id = :robeing_id
|
||||
@ -98,8 +98,8 @@ if team_id and user:
|
||||
|
||||
### 수동 해결 SQL (참고용)
|
||||
```sql
|
||||
-- happybell80 사용자 workspace_members 추가
|
||||
INSERT INTO workspace_members (user_id, workspace_id, robeing_id)
|
||||
-- happybell80 사용자 workspace_member 추가
|
||||
INSERT INTO workspace_member (user_id, workspace_id, robeing_id)
|
||||
VALUES (
|
||||
'1e16e9d5-59f3-54da-a661-8abeabff4230', -- happybell80 user_id
|
||||
'T035VFRKCN6', -- GoodGang Labs team_id
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
### 1. DB 스키마 불일치 ⚠️
|
||||
**문제점**:
|
||||
- `companies` 테이블과 `workspaces` 테이블이 공존
|
||||
- `company` 테이블과 `workspaces` 테이블이 공존
|
||||
- `SlackWorkspace` 모델이 `company_id`를 참조하는데 모델은 `workspace_id` 기대
|
||||
- Relationship 주석 처리로 임시 해결
|
||||
|
||||
@ -31,13 +31,13 @@
|
||||
```python
|
||||
# app/models/workspace.py
|
||||
class SlackWorkspace(Base):
|
||||
company_id = Column(UUID, ForeignKey("companies.id")) # 실제 DB
|
||||
# workspace_id로 되어야 하는데 companies 테이블 참조 중
|
||||
company_id = Column(UUID, ForeignKey("company.id")) # 실제 DB
|
||||
# workspace_id로 되어야 하는데 company 테이블 참조 중
|
||||
# relationship 주석 처리됨
|
||||
```
|
||||
|
||||
**해결 방안**:
|
||||
1. `companies` 테이블 데이터를 `workspaces`로 마이그레이션
|
||||
1. `company` 테이블 데이터를 `workspaces`로 마이그레이션
|
||||
2. FK 관계 정리
|
||||
3. 모델 통일
|
||||
|
||||
@ -101,7 +101,7 @@ login_callback_url = "https://auth.ro-being.com/auth/slack/login/callback" #
|
||||
## 향후 작업
|
||||
|
||||
### 긴급도 높음 🔴
|
||||
1. DB 스키마 통일 (companies → workspaces)
|
||||
1. DB 스키마 통일 (company → workspaces)
|
||||
2. Frontend 인증 방식 통일
|
||||
|
||||
### 중간 우선순위 🟡
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
```sql
|
||||
-- 확인 결과: 모두 0 rows
|
||||
SELECT * FROM slack_user_mapping WHERE user_id = '237494f7-061c-484c-a4f7-f500611e32f1'; -- ❌
|
||||
SELECT * FROM workspace_members WHERE user_id = '237494f7-061c-484c-a4f7-f500611e32f1'; -- ❌
|
||||
SELECT * FROM workspace_member WHERE user_id = '237494f7-061c-484c-a4f7-f500611e32f1'; -- ❌
|
||||
SELECT * FROM user_preferences WHERE user_id = '237494f7-061c-484c-a4f7-f500611e32f1'; -- ❌
|
||||
```
|
||||
|
||||
@ -25,11 +25,11 @@ SELECT * FROM user_preferences WHERE user_id = '237494f7-061c-484c-a4f7-f500611e
|
||||
auth-server의 Slack OAuth 콜백(`/auth/slack/login/callback`)에서:
|
||||
1. ✅ users 테이블 생성/업데이트
|
||||
2. ❌ slack_user_mapping 생성 안 함
|
||||
3. ❌ workspace_members 추가 안 함
|
||||
3. ❌ workspace_member 추가 안 함
|
||||
4. ❌ user_preferences 초기화 안 함
|
||||
|
||||
## 4. 영향
|
||||
- workspace_members 자동 추가 구현됨(9/11), 기본 robeing 할당 정상
|
||||
- workspace_member 자동 추가 구현됨(9/11), 기본 robeing 할당 정상
|
||||
- slack_user_mapping 의존 제거(9/11) → 이메일/기타 식별 병행
|
||||
- 상세: [/DOCS/troubleshooting/250831_slack_login_workspace_assignment_issue.md](./250831_slack_login_workspace_assignment_issue.md)
|
||||
|
||||
@ -38,8 +38,8 @@ auth-server의 Slack OAuth 콜백(`/auth/slack/login/callback`)에서:
|
||||
-- 1. username 설정
|
||||
UPDATE users SET username = 'hongtj' WHERE id = '237494f7-061c-484c-a4f7-f500611e32f1';
|
||||
|
||||
-- 2. workspace_members 추가 (team_id 확인 필요)
|
||||
INSERT INTO workspace_members (user_id, workspace_id, robeing_id)
|
||||
-- 2. workspace_member 추가 (team_id 확인 필요)
|
||||
INSERT INTO workspace_member (user_id, workspace_id, robeing_id)
|
||||
VALUES ('237494f7-061c-484c-a4f7-f500611e32f1', 'T035VFRKCN6', 'rb8001');
|
||||
```
|
||||
|
||||
|
||||
@ -127,7 +127,7 @@ state={RANDOM_STATE}
|
||||
|
||||
**관련 테이블:**
|
||||
- workspaces: robeing_port, subdomain 컬럼 보유
|
||||
- workspace_members: workspace_id, user_id, robeing_id 매핑
|
||||
- workspace_member: workspace_id, user_id, robeing_id 매핑
|
||||
- slack_user_mapping: 사용자 매핑
|
||||
|
||||
### 5.2 Slack 설정 정보
|
||||
@ -144,7 +144,7 @@ im:read, im:history, users:read, team:read, files:read, app_mentions:read
|
||||
**workspace_id 하드코딩 문제 ✅ 해결:**
|
||||
- ~~TODO 주석만 있고 구현 안 됨~~
|
||||
- ~~모든 사용자가 동일 workspace_id 사용 (550e8400-e29b-41d4-a716-446655440000)~~
|
||||
- ~~workspace_members 조회 코드 주석 처리됨~~
|
||||
- ~~workspace_member 조회 코드 주석 처리됨~~
|
||||
|
||||
**해결 내용:**
|
||||
1. ~~WorkspaceMember 조회 로직 활성화 (Line 411-419)~~ → sqlalchemy text() 직접 쿼리로 변경
|
||||
@ -161,9 +161,9 @@ im:read, im:history, users:read, team:read, files:read, app_mentions:read
|
||||
|
||||
**WorkspaceMember 모델 이슈:**
|
||||
- app/models/workspace.py에 WorkspaceMember 클래스 정의 없음
|
||||
- workspace_members 테이블 직접 쿼리로 해결
|
||||
- ~~`SELECT workspace_id FROM workspace_members WHERE user_id = :user_id::uuid AND is_active = true`~~
|
||||
- `SELECT workspace_id FROM workspace_members WHERE user_id = (:user_id)::uuid AND is_active = true` (괄호 필수)
|
||||
- workspace_member 테이블 직접 쿼리로 해결
|
||||
- ~~`SELECT workspace_id FROM workspace_member WHERE user_id = :user_id::uuid AND is_active = true`~~
|
||||
- `SELECT workspace_id FROM workspace_member WHERE user_id = (:user_id)::uuid AND is_active = true` (괄호 필수)
|
||||
|
||||
### 5.4 추가 이슈 해결 (2025-09-02 저녁)
|
||||
|
||||
@ -172,10 +172,10 @@ im:read, im:history, users:read, team:read, files:read, app_mentions:read
|
||||
- Slack App 설정: 3개 URL 모두 등록 (callback, login/callback, passport/callback)
|
||||
|
||||
**SlackWorkspace 모델 불일치:**
|
||||
- 모델 정의: `company_id` (Line 44, ForeignKey는 companies.id)
|
||||
- 모델 정의: `company_id` (Line 44, ForeignKey는 company.id)
|
||||
- 코드 사용: `workspace_id` 시도 → `company_id`로 수정 필요
|
||||
- Line 542, 557, 631, 674, 713: workspace_id → company_id
|
||||
- DB 현실: companies 테이블 없음, workspaces 테이블 사용 중
|
||||
- DB 현실: company 테이블 없음, workspaces 테이블 사용 중
|
||||
|
||||
**Company-X 설정 상태:**
|
||||
- workspace_id: 99d22d6b-d327-4fa4-bd2f-d228c11056e2
|
||||
@ -186,15 +186,15 @@ im:read, im:history, users:read, team:read, files:read, app_mentions:read
|
||||
### 5.5 최종 이슈 (✅ 해결 완료)
|
||||
|
||||
**Foreign Key 문제 해결:**
|
||||
- 모델: `ForeignKey("companies.id")` 참조
|
||||
- ~~실제 DB: companies 테이블 없음~~ → **companies 테이블 존재 확인됨**
|
||||
- 모델: `ForeignKey("company.id")` 참조
|
||||
- ~~실제 DB: company 테이블 없음~~ → **company 테이블 존재 확인됨**
|
||||
- 해결 내용:
|
||||
1. companies 테이블에 Company-X 레코드 추가 (ID: 99d22d6b-d327-4fa4-bd2f-d228c11056e2)
|
||||
1. company 테이블에 Company-X 레코드 추가 (ID: 99d22d6b-d327-4fa4-bd2f-d228c11056e2)
|
||||
2. 기존 slack_workspaces 레코드의 company_id 업데이트 완료
|
||||
3. Foreign Key 제약 조건 정상 작동
|
||||
|
||||
**최종 DB 상태 (2025-09-02 20:40):**
|
||||
- companies 테이블: Company-X (8001 포트, active 상태)
|
||||
- company 테이블: Company-X (8001 포트, active 상태)
|
||||
- workspaces 테이블: Company-X (8명 멤버)
|
||||
- slack_workspaces: T097FCTDVEX → Company-X 연결 완료
|
||||
- 봇 설치 준비 완료
|
||||
|
||||
@ -68,6 +68,6 @@ response.messages // reverse() 없이 그대로 사용
|
||||
- **결과**: 과거→최신 시간순 + 사용자→로빙 대화쌍 순서 모두 정상
|
||||
|
||||
## 7. 추가 확인 사항
|
||||
- **DB 저장 문제**: conversation_logs 테이블에 Slack 대화 저장 안 됨 (별개 이슈)
|
||||
- **DB 저장 문제**: conversation_log 테이블에 Slack 대화 저장 안 됨 (별개 이슈)
|
||||
- **API 엔드포인트**: /api/conversations/recent 404 에러 (51124 서버)
|
||||
- **테이블 컬럼**: message, response, timestamp 사용 (user_message 컬럼 없음)
|
||||
@ -20,7 +20,7 @@
|
||||
|
||||
## 3. 확인된 사실 (문서 기반)
|
||||
- 2025-08-25 DB 기반 토큰 저장으로 전환 완료 (마이그레이션 문서)
|
||||
- auth-server는 gmail_tokens 테이블에만 토큰 저장 (시퀀스 다이어그램)
|
||||
- auth-server는 gmail_token 테이블에만 토큰 저장 (시퀀스 다이어그램)
|
||||
- skill-email은 DB에서 토큰 조회하도록 설계됨 (서비스 간 직접 전달 없음)
|
||||
- Docker 컨테이너 /code 디렉토리 쓰기 권한 없음 (에러 메시지)
|
||||
- access_token, refresh_token은 TEXT 타입으로 암호화 저장 (테이블 스키마)
|
||||
@ -67,5 +67,5 @@
|
||||
1. ✅ 프론트엔드 Gmail OAuth 성공
|
||||
2. ✅ Permission denied 오류 없음
|
||||
3. ✅ unknown_gmail.json 생성 시도 없음
|
||||
4. ✅ gmail_tokens 테이블 정상 저장
|
||||
4. ✅ gmail_token 테이블 정상 저장
|
||||
5. ✅ 파일 시스템 의존성 완전 제거
|
||||
@ -4,7 +4,7 @@
|
||||
프론트엔드 대화창에서 슬랙/웹 대화 구분 불가
|
||||
|
||||
## 해결 방법
|
||||
conversation_logs 테이블의 slack_user_id 필드(VARCHAR(100))를 활용하여 슬랙 대화 시각적 표시
|
||||
conversation_log 테이블의 slack_user_id 필드(VARCHAR(100))를 활용하여 슬랙 대화 시각적 표시
|
||||
|
||||
## 수정된 파일 및 코드
|
||||
|
||||
@ -15,7 +15,7 @@ conversation_logs 테이블의 slack_user_id 필드(VARCHAR(100))를 활용하
|
||||
# get_recent_conversations() 함수
|
||||
query = text("""
|
||||
SELECT message, response, timestamp, slack_user_id # slack_user_id 추가
|
||||
FROM conversation_logs
|
||||
FROM conversation_log
|
||||
WHERE user_id = :user_id
|
||||
ORDER BY timestamp DESC
|
||||
LIMIT :limit
|
||||
|
||||
@ -40,7 +40,7 @@ HanYong: token_data 비어있음 (8/30 이후)
|
||||
-- 166번: token_data = jsonb_set(...) 사용
|
||||
|
||||
-- 개별 컬럼 삭제 (코드 수정 후)
|
||||
ALTER TABLE gmail_tokens
|
||||
ALTER TABLE gmail_token
|
||||
DROP COLUMN access_token,
|
||||
DROP COLUMN refresh_token,
|
||||
DROP COLUMN token_type,
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
| auth-server/app/models/user.py | 21-35 | 테이블 모델 정의 (picture 컬럼) |
|
||||
| auth-server/app/providers/gmail_passport.py | 178 | SELECT id FROM users WHERE username = $1 |
|
||||
| auth-server/app/providers/gmail_passport.py | 187 | SELECT username FROM users WHERE id = $1 |
|
||||
| robeing-gateway/app/database.py | 98-112 | JOIN 쿼리 (workspace_members, workspaces와 함께) |
|
||||
| robeing-gateway/app/database.py | 98-112 | JOIN 쿼리 (workspace_member, workspaces와 함께) |
|
||||
| robeing-gateway/app/database.py | 182-191 | SELECT * FROM users WHERE username = $1 |
|
||||
| robeing-gateway/app/database.py | 321-328 | SELECT * FROM users (전체 조회) |
|
||||
| robeing-gateway/app/models.py | 11-24 | 테이블 모델 정의 (avatar_url 컬럼) |
|
||||
@ -48,14 +48,14 @@
|
||||
|-----------|-----------|-----------|
|
||||
| auth-server/app/models/workspace.py | 15-31 | 테이블 모델 정의 |
|
||||
| auth-server/scripts/run_migration.py | 54 | SELECT id, name, subdomain, robeing_id FROM workspaces |
|
||||
| auth-server/migrations/add_user_workspace_tables.sql | 25-28 | ALTER TABLE companies RENAME TO workspaces |
|
||||
| auth-server/migrations/add_user_workspace_tables.sql | 25-28 | ALTER TABLE company RENAME TO workspaces |
|
||||
| robeing-gateway/app/database.py | 98-112 | JOIN 쿼리 |
|
||||
| robeing-gateway/app/database.py | 216-230 | JOIN 쿼리 (workspace_members와 함께) |
|
||||
| robeing-gateway/app/database.py | 216-230 | JOIN 쿼리 (workspace_member와 함께) |
|
||||
| robeing-gateway/app/models.py | 26-44 | 테이블 모델 정의 |
|
||||
|
||||
### 2.3 workspace_member 테이블 (실제 DB: workspace_member, 레코드 0건)
|
||||
**실제 DB 컬럼**: user_id(FK), role(user_role enum), created_at, updated_at
|
||||
**코드 모델**: workspace_members 테이블 참조 (복수형 차이)
|
||||
**코드 모델**: workspace_member 테이블 참조 (복수형 차이)
|
||||
|
||||
| 파일 경로 | 라인 번호 | 작업 내용 |
|
||||
|-----------|-----------|-----------|
|
||||
@ -90,13 +90,13 @@
|
||||
|
||||
### 2.6 gmail_token 테이블 (실제 DB: gmail_token, 3건)
|
||||
**실제 DB 컬럼**: user_id(FK), token_data(jsonb), oauth_config(jsonb), created_at, updated_at
|
||||
**코드 혼용**: auth-server는 gmail_tokens(복수)와 gmail_token(단수) 혼용
|
||||
**코드 혼용**: auth-server는 gmail_token(복수)와 gmail_token(단수) 혼용
|
||||
|
||||
| 파일 경로 | 라인 번호 | 작업 내용 |
|
||||
|-----------|-----------|-----------|
|
||||
| auth-server/app/providers/gmail_passport.py | 193 | INSERT INTO gmail_token (단수) |
|
||||
| auth-server/app/providers/gmail_passport.py | 264, 313, 354, 370 | gmail_token (단수) 사용 |
|
||||
| auth-server/app/api/gmail_refresh.py | 36, 43, 115, 124, 173, 179 | gmail_tokens (복수) 사용 |
|
||||
| auth-server/app/api/gmail_refresh.py | 36, 43, 115, 124, 173, 179 | gmail_token (복수) 사용 |
|
||||
| skill-email/services/db_credentials_provider.py | 60-70 | SELECT 쿼리 (is_equipped 필터) |
|
||||
| skill-email/services/db_credentials_provider.py | 163-177 | UPDATE 쿼리 |
|
||||
| skill-email/services/db_credentials_provider.py | 231-235 | COUNT 쿼리 |
|
||||
@ -214,7 +214,7 @@
|
||||
## 4. 위험 요소 - 치명적 불일치
|
||||
|
||||
1. **테이블명 전체 불일치**:
|
||||
- 코드: users, workspaces, workspace_members (복수형)
|
||||
- 코드: users, workspaces, workspace_member (복수형)
|
||||
- DB: user, company/team, workspace_member (단수형)
|
||||
|
||||
2. **존재하지 않는 테이블 참조**:
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
```python
|
||||
# 현재 코드 (잘못됨)
|
||||
cur.execute("""
|
||||
SELECT ... FROM gmail_tokens
|
||||
SELECT ... FROM gmail_token
|
||||
WHERE slack_user_id = %s # 존재하지 않는 컬럼
|
||||
""", (user_id,))
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
### 발견된 위반 사항
|
||||
|
||||
#### 1. rb8001/app/skills/email_integration.py
|
||||
- **잘못된 테이블명**: `gmail_tokens` → 실제는 `gmail_token`
|
||||
- **잘못된 테이블명**: `gmail_token` → 실제는 `gmail_token`
|
||||
- **Slack ID 사용**: skill-email 호출 시 Slack ID 전달
|
||||
- **미정의 변수**: `user_uuid` 변수 정의 없이 사용 (136줄)
|
||||
|
||||
@ -44,7 +44,7 @@ else:
|
||||
```
|
||||
|
||||
### 테이블명 수정 (완료)
|
||||
- `gmail_tokens` → `gmail_token`
|
||||
- `gmail_token` → `gmail_token`
|
||||
- `SELECT COUNT(*) FROM gmail_token WHERE user_id = %s`
|
||||
|
||||
## 남은 작업
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user