DOCS/300_architecture/plans/250910_happybell80_PostgreSQL_테이블_변경_계획.md
happybell80 55e2b7e103 docs: PostgreSQL 테이블 변경 계획 누락 사항 추가
- gmail_tokens: username 컬럼 및 token_data(JSON) 병행 사용 명시
- users: provider/provider_id vs oauth_provider/oauth_id 차이 명시
- workspace_members: role 타입 차이 (Enum vs String) 명시
- slack_user_mapping: 완전한 제약조건 (UNIQUE, FK) 명시
- 위험 요소에 모델 불일치 상세 내용 추가
2025-09-10 21:30:36 +09:00

13 KiB

PostgreSQL 데이터베이스 테이블 변경 계획

작성 정보

  • 작성일: 250910
  • 작성자: happybell80
  • 목적: PostgreSQL 테이블 구조 대대적 변경에 따른 영향 범위 파악 및 수정 계획

1. 데이터베이스 연결 정보

메인 데이터베이스

  • main_db: postgresql://robeings:robeings@192.168.219.45:5432/main_db
  • robeing_metrics: postgresql://postgres:@172.17.0.1:5432/robeing_metrics

사용 라이브러리

저장소 라이브러리
auth-server SQLAlchemy, asyncpg, psycopg2
rb8001 SQLAlchemy
rb10508_micro asyncpg
frontend-base asyncpg
robeing-gateway SQLAlchemy, asyncpg
robeing-monitor SQLAlchemy, asyncpg
skill-email psycopg2

2. 테이블별 사용 위치 상세

2.1 users 테이블

컬럼:

  • auth-server 모델: id(UUID), username, email, name, picture, oauth_provider, oauth_id, is_active, created_at, updated_at, last_login_at
  • robeing-gateway 모델: id(UUID), email, name, avatar_url, provider, provider_id, created_at, updated_at (username 없음)
파일 경로 라인 번호 작업 내용
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 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 컬럼)

2.2 workspaces 테이블

컬럼: id(UUID), name, subdomain, robeing_id, robeing_port, robeing_url, max_members, workspace_type, status, created_at, updated_at

파일 경로 라인 번호 작업 내용
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
robeing-gateway/app/database.py 98-112 JOIN 쿼리
robeing-gateway/app/database.py 216-230 JOIN 쿼리 (workspace_members와 함께)
robeing-gateway/app/models.py 26-44 테이블 모델 정의

2.3 workspace_members 테이블

컬럼: id(UUID), workspace_id(FK), user_id(FK), role, robeing_id, robeing_url, is_active, joined_at, updated_at 주의: role 타입이 auth-server는 Enum(UserRole), robeing-gateway는 String(50)

파일 경로 라인 번호 작업 내용
auth-server/app/models/user.py 46-60 테이블 모델 정의
auth-server/migrations/add_user_workspace_tables.sql 41-52 CREATE TABLE 정의
robeing-gateway/app/database.py 98-112 JOIN 쿼리
robeing-gateway/app/database.py 263-266 중복 체크 쿼리
robeing-gateway/app/database.py 274-282 UPDATE 쿼리
robeing-gateway/app/database.py 285-299 INSERT 쿼리 (gen_random_uuid() 사용)
robeing-gateway/app/models.py 46-60 테이블 모델 정의

2.4 slack_user_mapping 테이블

컬럼: slack_user_id, slack_workspace_id, user_id, created_at, updated_at 제약조건: UNIQUE(slack_user_id, slack_workspace_id), FK(user_id → users.id), FK(slack_workspace_id → slack_workspaces.id)

파일 경로 라인 번호 작업 내용
auth-server/app/providers/slack.py 266 SELECT user_id FROM slack_user_mapping WHERE slack_user_id = :slack_user_id AND slack_workspace_id = :slack_workspace_id
auth-server/app/providers/slack.py 308-312 INSERT INTO slack_user_mapping ... DO UPDATE SET (slack_user_id, slack_workspace_id 조합 기준)
rb8001/app/router/router.py 92 SELECT user_id FROM slack_user_mapping WHERE slack_user_id = :slack_id
robeing-gateway/app/main.py 479-486 SELECT user_id FROM slack_user_mapping WHERE slack_user_id = $1

2.5 slack_workspaces 테이블

컬럼: id(UUID), workspace_id(UUID), team_id, team_name, bot_token, bot_user_id, app_id, scopes(JSON), is_enterprise_install, is_active, installed_at, updated_at 주의: 마이그레이션에서 company_id → workspace_id로 컬럼명 변경 정의됨

파일 경로 라인 번호 작업 내용
auth-server/app/models/workspace.py 43-62 테이블 모델 정의 (현재 company_id로 정의됨)
auth-server/migrations/add_user_workspace_tables.sql 60-76 ALTER TABLE 정의 (company_id → workspace_id 변경)
robeing-gateway/app/main.py 522-525 SELECT bot_token FROM slack_workspaces WHERE team_id = $1
robeing-gateway/app/main.py 567-570 SELECT bot_token FROM slack_workspaces WHERE team_id = $1

2.6 gmail_tokens 테이블

컬럼: id, user_id, username, slack_user_id, robeing_id, token_data(JSON), access_token, refresh_token, oauth_config, scopes, expiry, is_equipped, equipped_to, created_at, updated_at 주의: token_data(JSON) 컬럼과 개별 토큰 컬럼(access_token, refresh_token)이 병행 사용 중

파일 경로 라인 번호 작업 내용
auth-server/app/providers/gmail_passport.py 193-198 INSERT INTO gmail_tokens ... DO UPDATE SET
auth-server/app/providers/gmail_passport.py 354 SELECT token_data FROM gmail_tokens WHERE user_id = $1
auth-server/app/providers/gmail_passport.py 370 DELETE FROM gmail_tokens WHERE user_id = $1
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 쿼리
robeing-monitor/app/api/items.py 97-111 SELECT 쿼리
robeing-monitor/app/api/items.py 185-190 소유권 확인 쿼리
robeing-monitor/app/api/items.py 197-211 UPDATE 쿼리 (장착/해제)
robeing-monitor/app/api/items.py 252-256 UPDATE 쿼리 (해제)
robeing-monitor/app/api/items.py 307-319 SELECT 쿼리 (장착된 토큰)
robeing-monitor/app/api/items.py 384-388 DELETE 쿼리

2.7 gmail_audit_logs 테이블

컬럼: user_id, robeing_id, action, success, details

파일 경로 라인 번호 작업 내용
robeing-monitor/app/api/items.py 214-223 INSERT 쿼리
robeing-monitor/app/api/items.py 263-270 INSERT 쿼리
robeing-monitor/app/api/items.py 395-401 INSERT 쿼리

2.8 robeing_stats 테이블

컬럼: id, robeing_id, memory, compute, react, empathy, leadership, ethics, level, experience, stat_points, created_at, updated_at

파일 경로 라인 번호 작업 내용
rb8001/app/state/database.py 24-38 테이블 모델 정의
rb10508_micro/app/api/endpoints.py 155-161 SELECT 쿼리
robeing-monitor/app/state/database.py 19-33 테이블 모델 정의
robeing-monitor/app/state/state_service.py 55 SELECT 쿼리
robeing-monitor/app/state/state_service.py 59-62 INSERT 쿼리
robeing-monitor/app/state/state_service.py 81 SELECT 쿼리
robeing-monitor/app/state/state_service.py 215 SELECT 전체 조회
robeing-monitor/app/api/items.py 169-173 SELECT level 쿼리

2.9 robeing_settings 테이블

컬럼: id, robeing_id, company_name, workspace_id, preferences(JSON), created_at, updated_at

파일 경로 라인 번호 작업 내용
rb8001/app/state/database.py 40-50 테이블 모델 정의
robeing-monitor/app/state/database.py 35-45 테이블 모델 정의
robeing-monitor/app/state/state_service.py 110 SELECT 쿼리
robeing-monitor/app/state/state_service.py 114-117 INSERT 쿼리
robeing-monitor/app/state/state_service.py 133 SELECT 쿼리

2.10 conversation_logs 테이블

컬럼:

  • rb8001 모델: id, robeing_id, user_id, slack_user_id, channel_id, message, response, intent, confidence, timestamp
  • robeing-monitor 모델: id, robeing_id, user_id, channel_id, message, response, intent, confidence, timestamp (slack_user_id 없음)
파일 경로 라인 번호 작업 내용
rb8001/app/state/database.py 52-65 테이블 모델 정의 (slack_user_id 포함)
rb8001/app/state/database.py 86-92 SELECT 쿼리 (최근 대화, slack_user_id 포함)
rb8001/app/router/router.py 464-496 INSERT 쿼리 (slack_user_id 포함)
robeing-monitor/app/state/database.py 47-59 테이블 모델 정의 (slack_user_id 없음)
robeing-monitor/app/state/state_service.py 156-159 INSERT 쿼리 (slack_user_id 없음)
robeing-monitor/app/state/state_service.py 173-177 SELECT 쿼리 (최근 로그, slack_user_id 없음)
robeing-monitor/app/state/state_service.py 194-203 SELECT 쿼리 (7일간, slack_user_id 없음)

2.11 user_preferences 테이블

컬럼: user_id, slack_user_id, news_keywords, email_filter, briefing_enabled, briefing_time

파일 경로 라인 번호 작업 내용
rb8001/app/skills/dm_skill.py 466 SELECT news_keywords WHERE user_id = :user_id
rb8001/app/skills/dm_skill.py 471 SELECT news_keywords WHERE slack_user_id = :slack_user_id
robeing-monitor/app/api/monitor.py 148-165 SELECT 쿼리
robeing-monitor/app/api/monitor.py 276-292 UPDATE 쿼리 (동적 쿼리 생성)
robeing-monitor/app/api/monitor.py 309-316 INSERT 쿼리

2.12 system_metrics 테이블

컬럼: time, metric_type, value

파일 경로 라인 번호 작업 내용
frontend-base/backend/metrics_database.py 58-60 INSERT INTO system_metrics
frontend-base/backend/metrics_database.py 93-100 SELECT (time_bucket 사용)

3. 수정 작업 체크리스트

3.1 테이블 구조 변경 시

  • SQLAlchemy 모델 클래스 수정
  • Migration 스크립트 작성
  • 기존 데이터 마이그레이션 계획

3.2 컬럼명 변경 시

  • 모든 SELECT 쿼리 수정
  • 모든 INSERT 쿼리 수정
  • 모든 UPDATE 쿼리 수정
  • 모든 DELETE 쿼리 수정
  • SQLAlchemy 모델 속성명 수정
  • API 응답 필드명 확인

3.3 저장소별 작업

  • auth-server: SQLAlchemy 모델 + asyncpg 쿼리 수정
  • rb8001: SQLAlchemy 모델 + text() 쿼리 수정
  • rb10508_micro: asyncpg 직접 쿼리 수정
  • frontend-base: asyncpg 직접 쿼리 수정
  • robeing-gateway: SQLAlchemy 모델 + asyncpg 쿼리 수정
  • robeing-monitor: SQLAlchemy 모델 + asyncpg 쿼리 수정
  • skill-email: psycopg2 쿼리 수정

3.4 테스트 계획

  • 각 저장소별 단위 테스트
  • 통합 테스트 (API 엔드포인트)
  • 데이터 마이그레이션 테스트
  • 롤백 계획 수립

4. 위험 요소

  1. 다중 라이브러리 사용: SQLAlchemy, asyncpg, psycopg2를 혼용하고 있어 일관성 있는 수정 필요
  2. UUID 처리: 일부는 문자열로, 일부는 UUID 타입으로 처리
  3. JSON 컬럼: preferences, scopes, oauth_config, token_data 등 JSON 타입 컬럼 처리 주의
  4. 외래키 관계: workspace_members의 workspace_id, user_id FK 관계 유지
  5. gen_random_uuid(): PostgreSQL 함수 사용 부분 확인 필요
  6. 모델 불일치 - 심각:
    • users: picture vs avatar_url, oauth_provider/oauth_id vs provider/provider_id
    • workspace_members: role이 Enum vs String(50)
    • conversation_logs: slack_user_id 유무
    • gmail_tokens: token_data(JSON) vs 개별 컬럼 병행
  7. 마이그레이션 충돌: slack_workspaces의 company_id → workspace_id 변경이 모델과 불일치
  8. 복합 고유키: slack_user_mapping의 (slack_user_id, slack_workspace_id) 조합 처리

5. 작업 우선순위

  1. 높음: users, workspaces, workspace_members (핵심 인증/권한)
  2. 중간: gmail_tokens, slack_user_mapping (통합 기능)
  3. 낮음: robeing_stats, conversation_logs (부가 기능)

6. 롤백 계획

  1. 변경 전 전체 데이터베이스 백업
  2. 각 테이블별 데이터 덤프
  3. 이전 버전 코드 태그 생성
  4. 단계별 배포 (테스트 환경 → 프로덕션)

주의사항:

  • 모든 변경사항은 테스트 환경(rb10508_micro)에서 먼저 검증
  • 프로덕션(rb8001) 적용은 완전한 테스트 후 진행
  • 데이터 손실 방지를 위한 백업 필수