- users → user in SQL contexts (94 occurrences) - robeings → robeing in SQL contexts - user_preferences → user_preference (14 files) - slack_workspaces → slack_workspace in SQL contexts (17 files) All table names now correctly match PostgreSQL schema
5.2 KiB
5.2 KiB
테이블 관계도 (ERD)
작성일: 2025-08-20
관계 다이어그램
erDiagram
users ||--o{ workspace_member : "has many"
users ||--o{ slack_user_mapping : "has many"
users ||--o{ gmail_token : "has"
users ||--o{ robeing_stats : "has"
users ||--o{ conversation_log : "has many"
workspaces ||--o{ workspace_member : "has many"
workspaces }o--|| company : "belongs to"
slack_workspaces ||--o{ slack_user_mapping : "has many"
workspace_member ||--o{ slack_user_mapping : "references"
gmail_token }o--|| users : "belongs to"
robeing_stats }o--|| users : "belongs to"
conversation_log }o--|| users : "belongs to"
핵심 관계 설명
1. User 중심 관계
users (1) ─────┬──── (*) workspace_member
├──── (*) slack_user_mapping
├──── (0..1) gmail_token
├──── (0..1) robeing_stats
└──── (*) conversation_log
- 한 사용자는 여러 워크스페이스의 멤버가 될 수 있음
- 한 사용자는 여러 Slack 워크스페이스와 매핑될 수 있음
- 한 사용자는 하나의 Gmail 토큰만 가질 수 있음 (현재 구조)
- 한 사용자는 하나의 로빙 통계를 가짐
- 한 사용자는 여러 대화 로그를 가짐
2. Workspace 관계
company (1) ──── (*) workspaces
workspaces (1) ──── (*) workspace_member
- 한 회사는 여러 워크스페이스를 가질 수 있음
- 한 워크스페이스는 여러 멤버를 가질 수 있음
3. Slack 매핑 관계
slack_workspaces (1) ──── (*) slack_user_mapping
slack_user_mapping (*) ──── (1) users
slack_user_mapping (*) ──── (0..1) workspace_member
- Slack 사용자 ID를 시스템 UUID로 변환하는 브릿지 역할
- workspace_member와 선택적 연결
JOIN 예시
1. 사용자 전체 정보 조회
SELECT
u.id,
u.username,
u.name,
u.email,
wm.robeing_id,
sum.slack_user_id,
gt.is_equipped as gmail_equipped
FROM user u
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_token gt ON u.id = gt.user_id
WHERE u.username = 'happybell80';
2. Slack ID로 사용자 찾기
SELECT
sum.slack_user_id,
u.id as user_uuid,
u.username,
u.name,
u.email
FROM slack_user_mapping sum
JOIN user u ON sum.user_id = u.id
WHERE sum.slack_user_id = 'U0925SXQFDK';
3. Gmail 아이템 장착 상태 확인
SELECT
u.name,
u.email,
gt.is_equipped,
gt.equipped_to,
rs.level,
gt.scopes
FROM user u
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;
4. 워크스페이스 멤버 목록
SELECT
w.name as workspace_name,
u.name as user_name,
u.email,
wm.role,
wm.robeing_id
FROM workspaces w
JOIN workspace_member wm ON w.id = wm.workspace_id
JOIN user u ON wm.user_id = u.id
WHERE w.name = 'Ivada Robeing';
데이터 흐름
1. Slack 메시지 처리 흐름
Slack Message
↓
slack_user_id (U0925SXQFDK)
↓
slack_user_mapping 테이블 조회
↓
user_id (UUID) 획득
↓
모든 서비스에서 UUID 사용
2. Gmail 아이템 사용 흐름
User 요청
↓
user_id (UUID)로 gmail_token 조회
↓
is_equipped 확인
↓
robeing_stats에서 레벨 확인
↓
token_data에서 access_token 추출
↓
Gmail API 호출
3. 프론트엔드 인증 흐름
Google OAuth 로그인
↓
users 테이블에 사용자 생성/업데이트
↓
JWT 토큰 발급 (user_id 포함)
↓
모든 API 요청에 JWT 사용
↓
user_id로 권한 확인
데이터 정합성 규칙
1. UUID 일관성
- 모든
user_id컬럼은users.id를 참조 - 외래키 제약으로 정합성 보장
- CASCADE 옵션 미사용 (명시적 삭제 필요)
2. 유니크 제약
users.email- 중복 이메일 방지users.username- 중복 사용자명 방지slack_workspaces.team_id- 중복 Slack 팀 방지robeing_settings.robeing_id- 중복 설정 방지
3. NULL 허용 정책
- 필수 관계: NOT NULL (user_id, workspace_id 등)
- 선택적 관계: NULL 허용 (robeing_id, equipped_to 등)
트랜잭션 고려사항
1. Gmail 아이템 장착
BEGIN;
-- 1. 레벨 확인
SELECT level FROM robeing_stats WHERE user_id = ?;
-- 2. 소유권 확인
SELECT id FROM gmail_token WHERE user_id = ?;
-- 3. 장착 처리
UPDATE gmail_token
SET is_equipped = true, equipped_to = ?
WHERE user_id = ?;
-- 4. 감사 로그
INSERT INTO gmail_audit_logs (user_id, action, success)
VALUES (?, 'equip', true);
COMMIT;
2. 사용자 생성
BEGIN;
-- 1. users 테이블
INSERT INTO user (id, email, name, username)
VALUES (?, ?, ?, ?);
-- 2. workspace_member 추가
INSERT INTO workspace_member (user_id, workspace_id, role)
VALUES (?, ?, 'member');
-- 3. robeing_stats 초기화
INSERT INTO robeing_stats (user_id, robeing_id, level)
VALUES (?, ?, 1);
COMMIT;
문서 끝