# Auth DB 테이블 구조 단순화 방안 작성일: 2025년 8월 12일 작성자: Claude (51123 서버) 요청자: happybell80 ## 1. 현재 테이블 구조 분석 ### 1.1 현재 테이블 (5개) - **users**: 사용자 기본 정보 - **workspaces**: 워크스페이스 정보 (로빙 할당) - **workspace_members**: 사용자-워크스페이스 연결 - **companies**: 회사 정보 - **slack_workspaces**: Slack 워크스페이스 정보 ### 1.2 현재 구조의 문제점 #### 복잡도 문제 1. **과도한 관계 분리** - companies ↔ slack_workspaces ↔ workspaces 3단계 관계 - 실제로는 1개 workspace만 사용 중 2. **중복 데이터** - robeing_id가 workspaces와 workspace_members 양쪽에 존재 - robeing_url도 중복 저장 3. **불명확한 개념** - companies의 실제 필요성 불분명 - workspaces가 실제로 무엇을 나타내는지 모호 4. **누락된 기능** - Slack user_id와 시스템 user_id 매핑 테이블 없음 - 사용자가 여러 로빙을 사용할 때 관리 방법 불명확 ### 1.3 현재 데이터 현황 ``` users: 3명 (happybell80, eagle0914, hhyong91) workspaces: 1개 (ivada-robeing) workspace_members: 3개 (모두 rb10508_micro 사용) companies: 2개 (테스트 회사) slack_workspaces: 2개 (GoodGang Labs, test) ``` ## 2. 단순화 방안 ### 방안 1: 최소 구조 (3개 테이블) ```sql -- 사용자 테이블 CREATE TABLE users ( id UUID PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, username VARCHAR(50) UNIQUE, name VARCHAR(255), oauth_provider VARCHAR(50), oauth_id VARCHAR(255), created_at TIMESTAMP, updated_at TIMESTAMP ); -- 사용자별 로빙 할당 CREATE TABLE user_robeings ( id UUID PRIMARY KEY, user_id UUID REFERENCES users(id), robeing_id VARCHAR(100) NOT NULL, -- rb10508_micro, rb8001 등 robeing_port INTEGER, is_primary BOOLEAN DEFAULT false, created_at TIMESTAMP, UNIQUE(user_id, robeing_id) ); -- Slack 사용자 매핑 CREATE TABLE slack_user_mapping ( id UUID PRIMARY KEY, slack_user_id VARCHAR(100) NOT NULL, -- U04KJHGLS slack_team_id VARCHAR(100), -- T035VFRKCN6 user_id UUID REFERENCES users(id), bot_token TEXT, -- 워크스페이스별 봇 토큰 created_at TIMESTAMP, UNIQUE(slack_user_id, slack_team_id) ); ``` **장점**: 매우 단순, 최소한의 테이블 **단점**: Slack workspace 정보 관리 어려움, 확장성 제한 ### 방안 2: 중간 단계 (4개 테이블) ⭐ 권장 ```sql -- 기존 users 테이블 유지 CREATE TABLE users ( id UUID PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, username VARCHAR(50) UNIQUE, name VARCHAR(255), picture VARCHAR(500), oauth_provider VARCHAR(50), oauth_id VARCHAR(255), is_active BOOLEAN DEFAULT true, created_at TIMESTAMP, updated_at TIMESTAMP, last_login_at TIMESTAMP ); -- Slack 워크스페이스 (단순화) CREATE TABLE slack_workspaces ( id UUID PRIMARY KEY, team_id VARCHAR(100) UNIQUE NOT NULL, team_name VARCHAR(255), bot_token TEXT, bot_user_id VARCHAR(100), app_id VARCHAR(100), scopes JSON, is_active BOOLEAN DEFAULT true, installed_at TIMESTAMP, updated_at TIMESTAMP ); -- 사용자-로빙 연결 CREATE TABLE user_robeings ( id UUID PRIMARY KEY, user_id UUID REFERENCES users(id), robeing_id VARCHAR(100) NOT NULL, robeing_port INTEGER, robeing_host VARCHAR(255) DEFAULT '192.168.219.52', is_primary BOOLEAN DEFAULT false, created_at TIMESTAMP, UNIQUE(user_id, robeing_id) ); -- Slack-시스템 사용자 매핑 CREATE TABLE slack_users ( id UUID PRIMARY KEY, slack_user_id VARCHAR(100) NOT NULL, slack_team_id VARCHAR(100) REFERENCES slack_workspaces(team_id), user_id UUID REFERENCES users(id), robeing_id VARCHAR(100), -- 이 Slack 사용자가 대화할 로빙 created_at TIMESTAMP, updated_at TIMESTAMP, UNIQUE(slack_user_id, slack_team_id) ); ``` **장점**: - 명확한 관심사 분리 - 다중 로빙 지원 - 다중 Slack workspace 지원 - 기존 users 테이블 최소 변경 **단점**: - 여전히 4개 테이블 필요 ### 방안 3: 통합 단순 구조 (2개 테이블) ```sql -- 사용자 (모든 정보 통합) CREATE TABLE users ( id UUID PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, username VARCHAR(50) UNIQUE, name VARCHAR(255), robeing_id VARCHAR(100), -- 기본 로빙 robeing_port INTEGER, slack_user_id VARCHAR(100), -- Slack ID (있으면) slack_team_id VARCHAR(100), -- Slack workspace (있으면) oauth_provider VARCHAR(50), oauth_id VARCHAR(255), created_at TIMESTAMP, updated_at TIMESTAMP ); -- Slack 설정 (앱 레벨) CREATE TABLE slack_config ( team_id VARCHAR(100) PRIMARY KEY, team_name VARCHAR(255), bot_token TEXT, bot_user_id VARCHAR(100), app_id VARCHAR(100), is_active BOOLEAN DEFAULT true ); ``` **장점**: 매우 단순 **단점**: 확장성 없음, 다중 로빙/workspace 지원 불가 ## 3. 권장 방안: 방안 2 (4개 테이블) ### 3.1 선택 이유 1. **적절한 균형**: 단순함과 확장성의 균형 2. **명확한 분리**: 각 테이블의 역할이 명확 3. **유연성**: 향후 요구사항 변경에 대응 가능 4. **호환성**: 기존 시스템과의 호환성 유지 ### 3.2 마이그레이션 계획 #### Phase 1: 데이터 백업 ```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; ``` #### Phase 2: 새 테이블 생성 ```sql -- user_robeings 생성 및 데이터 이전 CREATE TABLE user_robeings AS SELECT gen_random_uuid() as id, user_id, robeing_id, CASE robeing_id WHEN 'rb10508_micro' THEN 10508 WHEN 'rb8001' THEN 8001 WHEN 'rb10408' THEN 10408 END as robeing_port, '192.168.219.52' as robeing_host, true as is_primary, joined_at as created_at FROM workspace_members; -- slack_users 테이블 생성 (빈 테이블) CREATE TABLE slack_users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), slack_user_id VARCHAR(100) NOT NULL, slack_team_id VARCHAR(100), user_id UUID REFERENCES users(id), robeing_id VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(slack_user_id, slack_team_id) ); ``` #### Phase 3: 기존 테이블 정리 ```sql -- Foreign key 제약 제거 후 테이블 삭제 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 workspaces; DROP TABLE companies; ``` ### 3.3 새로운 데이터 흐름 #### 사용자 로그인 ``` OAuth 로그인 → users 테이블 조회/생성 ↓ user_robeings에서 기본 로빙 확인 ↓ 로빙 서비스 연결 ``` #### Slack 메시지 처리 ``` Slack 이벤트 수신 (slack_user_id 포함) ↓ slack_users 테이블에서 user_id, robeing_id 조회 ↓ 해당 로빙으로 메시지 라우팅 ↓ ChromaDB에 user_id 기반 저장 ``` ## 4. 구현 우선순위 1. **즉시 필요**: slack_users 테이블 생성 - Slack 사용자 매핑 기능 구현 가능 - 기존 테이블 영향 없음 2. **단계적 마이그레이션**: user_robeings 테이블 - workspace_members 데이터 이전 - 테스트 후 기존 테이블 제거 3. **정리 작업**: 불필요한 테이블 제거 - companies, workspaces 제거 - slack_workspaces 단순화 ## 5. API 변경사항 ### 5.1 사용자-로빙 조회 ```python # 기존 SELECT * FROM workspace_members WHERE user_id = ? # 변경 SELECT * FROM user_robeings WHERE user_id = ? AND is_primary = true ``` ### 5.2 Slack 사용자 조회 ```python # 신규 SELECT u.*, sr.robeing_id FROM slack_users sr JOIN users u ON sr.user_id = u.id WHERE sr.slack_user_id = ? AND sr.slack_team_id = ? ``` ## 6. 예상 효과 ### 6.1 복잡도 감소 - 테이블 수: 5개 → 4개 - 관계 복잡도: 3단계 → 2단계 - 중복 데이터 제거 ### 6.2 기능 개선 - Slack 사용자 매핑 지원 - 다중 로빙 지원 - 명확한 데이터 모델 ### 6.3 유지보수성 - 각 테이블 역할 명확 - 확장 가능한 구조 - 마이그레이션 경로 명확 ## 7. 리스크 및 대응 ### 7.1 데이터 손실 위험 - 대응: 모든 변경 전 백업 테이블 생성 - 롤백 계획 수립 ### 7.2 서비스 중단 - 대응: 단계적 마이그레이션 - 새 테이블 먼저 생성, 테스트 후 전환 ### 7.3 애플리케이션 호환성 - 대응: API 래퍼 함수로 하위 호환성 유지 - 점진적 코드 업데이트 ## 8. 51124 서버 검토 의견 및 추가 제안 ### 8.1 동의하는 부분 1. **방안 2 (4개 테이블) 선택** - 적절한 균형점입니다 - 확장성과 단순성 모두 확보 - 명확한 관심사 분리 2. **slack_users 테이블 설계** - `robeing_id` 필드 포함이 좋습니다 - Slack 사용자별로 다른 로빙 할당 가능 - UNIQUE 제약 조건 적절 3. **단계적 마이그레이션** - 백업 우선 - 새 테이블 먼저 생성 - 안전한 접근 ### 8.2 추가 제안사항 #### user_robeings 테이블에 추가 필드 ```sql CREATE TABLE user_robeings ( id UUID PRIMARY KEY, user_id UUID REFERENCES users(id), robeing_id VARCHAR(100) NOT NULL, robeing_port INTEGER, robeing_host VARCHAR(255) DEFAULT '192.168.219.52', is_primary BOOLEAN DEFAULT false, last_used_at TIMESTAMP, -- 마지막 사용 시간 usage_count INTEGER DEFAULT 0, -- 사용 횟수 status VARCHAR(20) DEFAULT 'active', -- active/inactive/suspended settings JSON, -- 로빙별 개인 설정 created_at TIMESTAMP, UNIQUE(user_id, robeing_id) ); ``` #### slack_users 테이블 개선 ```sql CREATE TABLE slack_users ( id UUID PRIMARY KEY, slack_user_id VARCHAR(100) NOT NULL, slack_team_id VARCHAR(100), user_id UUID REFERENCES users(id), robeing_id VARCHAR(100), display_name VARCHAR(255), -- Slack 표시 이름 slack_timezone VARCHAR(50), -- 사용자 시간대 last_message_at TIMESTAMP, -- 마지막 메시지 시간 is_bot BOOLEAN DEFAULT false, -- 봇 여부 확인 created_at TIMESTAMP, updated_at TIMESTAMP, UNIQUE(slack_user_id, slack_team_id) ); ``` #### 인덱스 추가 필요 ```sql -- Slack 사용자 빠른 조회 CREATE INDEX idx_slack_users_lookup ON slack_users(slack_user_id, slack_team_id); -- 주 로빙 빠른 조회 CREATE INDEX idx_user_robeings_primary ON user_robeings(user_id, is_primary); -- 활성 상태 필터링 CREATE INDEX idx_user_robeings_status ON user_robeings(status, user_id); ``` ### 8.3 주의사항 1. **데이터 일관성** - `robeing_id`가 여러 테이블에 분산 - 중앙 관리 방법 필요 (enum 또는 별도 robeings 테이블) 2. **포트 하드코딩 문제** ```sql -- 하드코딩 대신 설정 테이블 권장 CREATE TABLE robeing_configs ( robeing_id VARCHAR(100) PRIMARY KEY, port INTEGER NOT NULL, host VARCHAR(255), is_active BOOLEAN DEFAULT true ); ``` 3. **ChromaDB 컬렉션명 규칙** - `{robeing_id}_{user_id}_episodic` 형식 통일 - slack_users의 user_id 사용 필수 ### 8.4 개선된 실행 순서 #### Phase 0: 즉시 실행 (영향 없음) 1. slack_users 테이블만 먼저 생성 2. 인덱스 생성 3. 테스트 데이터 입력 4. rb10508_micro에서 매핑 테스트 #### Phase 1: 테스트 환경 검증 1. 새 테이블 전체 생성 (테스트 DB) 2. 마이그레이션 스크립트 검증 3. API 호환성 테스트 4. 롤백 시나리오 테스트 #### Phase 2: 프로덕션 적용 1. 전체 백업 2. 새 테이블 생성 3. 데이터 마이그레이션 4. 애플리케이션 전환 5. 구 테이블 보관 (1주일) 6. 안정화 확인 후 구 테이블 삭제 ## 9. 최종 결론 현재의 복잡한 5개 테이블 구조를 4개 테이블로 단순화하여: - 데이터 모델의 명확성 향상 - Slack 통합 기능 지원 - 유지보수성 개선 방안 2 (4개 테이블)를 채택하되, 51124 서버에서 제안한 추가 필드와 인덱스를 포함하여 구현하는 것을 권장합니다. 특히 slack_users 테이블을 즉시 생성하여 Slack 사용자 매핑 기능을 우선 구현하고, 나머지 테이블은 단계적으로 마이그레이션하는 것이 안전합니다. --- *이 문서는 2025년 8월 12일 51123 서버에서 작성되고, 51124 서버에서 검토되었습니다.*