DOCS/plans/250812_auth_db_테이블_단순화_방안.md

13 KiB

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개 테이블)

-- 사용자 테이블
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개 테이블) 권장

-- 기존 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개 테이블)

-- 사용자 (모든 정보 통합)
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: 데이터 백업

-- 기존 데이터 백업
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: 새 테이블 생성

-- 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: 기존 테이블 정리

-- 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 사용자-로빙 조회

# 기존
SELECT * FROM workspace_members WHERE user_id = ?

# 변경
SELECT * FROM user_robeings WHERE user_id = ? AND is_primary = true

5.2 Slack 사용자 조회

# 신규
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 테이블에 추가 필드

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 테이블 개선

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)
);

인덱스 추가 필요

-- 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. 포트 하드코딩 문제

    -- 하드코딩 대신 설정 테이블 권장
    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 서버에서 검토되었습니다.