merge: origin/main, research README 충돌 해결
Made-with: Cursor
This commit is contained in:
commit
417645d8fe
@ -10,6 +10,8 @@
|
||||
- workspace-team-project 계층 재정의 문제
|
||||
- ssot: `../book/300_architecture/390_workspace_team_project_도메인_모델.md`
|
||||
- ideas: `ideas/260316_workspace_team_project_계층_재정의_아이디어.md`
|
||||
- research: `research/260316_workspace_team_project_계층_재정의_영향범위_리서치.md`
|
||||
- plans: `plans/260316_workspace_team_project_계층_재정의_전환계획.md`
|
||||
|
||||
### 닫힌 문제
|
||||
|
||||
@ -63,6 +65,7 @@
|
||||
- OpenClaw 기반 로빙 개선 아이디어 – `ideas/260309_openclaw_기반_로빙_개선_아이디어.md`
|
||||
- 로빙 에이전트 루프와 스킬 훅 구조 아이디어 – `ideas/260312_로빙_에이전트루프와_스킬훅_구조_아이디어.md`
|
||||
- workspace-team-project 계층 재정의 아이디어 – `ideas/260316_workspace_team_project_계층_재정의_아이디어.md`
|
||||
- workspace-team-project 계층 재정의 전환계획 – `plans/260316_workspace_team_project_계층_재정의_전환계획.md`
|
||||
|
||||
### Intent 리뷰 / 의도 학습
|
||||
|
||||
|
||||
@ -40,6 +40,8 @@ tags: [workspace, team, project, database, slack, ideas]
|
||||
|
||||
## 관련 문서
|
||||
- [Workspace-Team-Project 도메인 모델](../../book/300_architecture/390_workspace_team_project_%EB%8F%84%EB%A9%94%EC%9D%B8_%EB%AA%A8%EB%8D%B8.md)
|
||||
- [workspace-team-project 계층 재정의 영향범위 리서치](../research/260316_workspace_team_project_%EA%B3%84%EC%B8%B5_%EC%9E%AC%EC%A0%95%EC%9D%98_%EC%98%81%ED%96%A5%EB%B2%94%EC%9C%84_%EB%A6%AC%EC%84%9C%EC%B9%98.md)
|
||||
- [workspace-team-project 계층 재정의 전환계획](../plans/260316_workspace_team_project_%EA%B3%84%EC%B8%B5_%EC%9E%AC%EC%A0%95%EC%9D%98_%EC%A0%84%ED%99%98%EA%B3%84%ED%9A%8D.md)
|
||||
- [database/tables.md](../../book/300_architecture/database/tables.md)
|
||||
- [380_authentication_system.md](../../book/300_architecture/380_authentication_system.md)
|
||||
- [journey/README.md](../README.md)
|
||||
|
||||
256
journey/plans/260316_workspace_team_project_계층_재정의_전환계획.md
Normal file
256
journey/plans/260316_workspace_team_project_계층_재정의_전환계획.md
Normal file
@ -0,0 +1,256 @@
|
||||
tags: [workspace, team, project, database, slack, auth, gateway, rag, migration, plans]
|
||||
|
||||
# workspace-team-project 계층 재정의 전환계획
|
||||
|
||||
상위 원칙:
|
||||
- [0_VALUE Writing Principles](../../../../0_VALUE/02_Governance/writing-principles.md)
|
||||
- [Workspace-Team-Project 도메인 모델](../../book/300_architecture/390_workspace_team_project_%EB%8F%84%EB%A9%94%EC%9D%B8_%EB%AA%A8%EB%8D%B8.md)
|
||||
- [database/tables.md](../../book/300_architecture/database/tables.md)
|
||||
|
||||
관련 문서:
|
||||
- [workspace-team-project 계층 재정의 아이디어](../ideas/260316_workspace_team_project_%EA%B3%84%EC%B8%B5_%EC%9E%AC%EC%A0%95%EC%9D%98_%EC%95%84%EC%9D%B4%EB%94%94%EC%96%B4.md)
|
||||
- [workspace-team-project 계층 재정의 영향범위 리서치](../research/260316_workspace_team_project_%EA%B3%84%EC%B8%B5_%EC%9E%AC%EC%A0%95%EC%9D%98_%EC%98%81%ED%96%A5%EB%B2%94%EC%9C%84_%EB%A6%AC%EC%84%9C%EC%B9%98.md)
|
||||
- [통합 인증 시스템 아키텍처](../../book/300_architecture/380_authentication_system.md)
|
||||
- [테이블 관계도](../../book/300_architecture/database/relationships.md)
|
||||
|
||||
## 목적
|
||||
- `team`이 상위 조직과 실행 조직 의미를 동시에 갖는 현재 구조를 종료합니다.
|
||||
- 운영 중인 `auth-server`, `robeing-gateway`, `rb8001`, `skill-rag-file`, `skill-slack`, `admin-dashboard`를 한 번에 깨지 않도록 병행 지원 순서로 전환합니다.
|
||||
- 최종적으로 `workspace > team`, `team owns project`를 운영 DB와 코드 SSOT에 맞춰 고정합니다.
|
||||
|
||||
## 범위
|
||||
- 포함:
|
||||
- 새 조직 모델 정의와 목표 ERD 고정
|
||||
- 운영 DB의 병행 지원용 컬럼/테이블 추가
|
||||
- Slack/Auth/RAG 경로의 단계별 전환
|
||||
- Company-X와 Robeing의 초기 매핑 규칙 확정
|
||||
- 검증 체크리스트와 롤백 기준 고정
|
||||
- 제외:
|
||||
- 모든 고객사의 조직 구조 일괄 정리
|
||||
- 실제 개별 프로젝트 팀 구조의 최종 업무 운영 정책 확정
|
||||
- 오래된 문서 전체 아카이브 정리
|
||||
|
||||
## 목표 모델
|
||||
|
||||
### 1. 도메인 해석
|
||||
- `workspace`: Company-X, Goosefarm 같은 상위 조직 단위
|
||||
- `team`: workspace 소속 실행 조직
|
||||
- `project`: team이 담당하는 대상/업무 단위
|
||||
|
||||
### 2. 목표 관계
|
||||
- `workspace has many teams`
|
||||
- `team belongs to one workspace`
|
||||
- `team owns many projects`
|
||||
- `slack_workspace belongs to one workspace`
|
||||
- `slack_channel`은 `workspace` 소속을 기본으로 하고, 필요 시 `project`를 선택적으로 참조
|
||||
|
||||
### 3. 초기 운영 매핑
|
||||
- `Company-X`는 `workspace`로 승격
|
||||
- 현재 `Company-X Team`은 임시로 `Company-X 실행팀` 성격의 `team`으로 재정의
|
||||
- `xvaluelab`은 `project`로 등록
|
||||
- `Robeing`도 같은 기준으로 `workspace`와 하위 `team`을 분리할 수 있게 설계
|
||||
|
||||
## 목표 ERD 초안
|
||||
|
||||
### 1. 신규/재정의 엔터티
|
||||
- `workspace`
|
||||
- `id`
|
||||
- `name`
|
||||
- `slug`
|
||||
- `is_active`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
- `team`
|
||||
- `id`
|
||||
- `workspace_id`
|
||||
- `name`
|
||||
- `slug`
|
||||
- `role_type`
|
||||
- `is_active`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
- `project`
|
||||
- `id`
|
||||
- `team_id`
|
||||
- `name`
|
||||
- `slug`
|
||||
- `status`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
|
||||
### 2. 기존 테이블의 목표 참조
|
||||
- `user.team_id`는 유지하되 전환 완료 전까지 `team`만 참조
|
||||
- `workspace_member`는 `workspace_id`를 추가해 이름과 구조를 일치시킴
|
||||
- `slack_workspace.team_id`는 최종적으로 `workspace_id`로 전환
|
||||
- `slack_channel`은 `workspace_id`와 `project_id`를 병행 지원
|
||||
- `slack_canvas`는 기존 `slack_channel_id`를 유지
|
||||
- `team_document`, `startup_valuation`은 우선 기존 `team_id` 유지 후 필요 시 후속 분리
|
||||
- `coldmail_list_config`는 `slack_workspace_id` 유지
|
||||
|
||||
## 전환 원칙
|
||||
|
||||
### 1. 레거시 `team_id` 경로를 바로 제거하지 않습니다.
|
||||
- 새 축을 먼저 추가합니다.
|
||||
- 읽기는 `신규 필드 우선 + 레거시 fallback`으로 갑니다.
|
||||
- 쓰기는 이행 기간 동안 dual-write를 허용합니다.
|
||||
|
||||
### 2. Slack/Auth 경로를 최우선 보호합니다.
|
||||
- Slack OIDC 로그인
|
||||
- Slack passport install/callback/status/token
|
||||
- gateway Slack token lookup / user uuid mapping
|
||||
- rb8001 Slack event/file/message 처리
|
||||
- skill-slack Lists API
|
||||
|
||||
### 3. Company-X RAG 경로를 두 번째 보호 축으로 둡니다.
|
||||
- `team_document`
|
||||
- `skill-rag-file` 업로드/검색
|
||||
- `companyx_grounding_service`
|
||||
- IR 채널/Canvas 처리
|
||||
|
||||
### 4. 문서 SSOT를 코드 전환과 같은 묶음으로 처리합니다.
|
||||
- 구조를 바꾸고 문서를 나중에 맞추는 방식은 금지합니다.
|
||||
- 최소 `tables.md`, `relationships.md`, `380_authentication_system.md`는 같은 단계에서 갱신합니다.
|
||||
|
||||
## 작업 단계
|
||||
|
||||
### Phase 0. 사전 고정
|
||||
- `workspace`, `team`, `project` 정의를 본 문서 기준으로 동결
|
||||
- Company-X, Robeing 초기 매핑을 표로 확정
|
||||
- `workspace_member`를 계속 쓸지 대체할지 결정하지 말고, 우선 `workspace_id` 추가를 기준안으로 둠
|
||||
|
||||
### Phase 1. DB 병행 지원 준비
|
||||
- `workspace` 테이블 신설
|
||||
- `project` 테이블 신설
|
||||
- `team.workspace_id` 추가
|
||||
- `workspace_member.workspace_id` 추가
|
||||
- `slack_workspace.workspace_id` 추가
|
||||
- `slack_channel.workspace_id`, `slack_channel.project_id` 추가
|
||||
- 필요 시 `project_name`은 유지하되 FK 전환 완료 후 보조 메타 필드로만 사용
|
||||
|
||||
### Phase 2. 기초 데이터 이관
|
||||
- 기존 `company` 레코드를 기준으로 `workspace` 생성
|
||||
- `team.company_id`를 해석해 각 `team.workspace_id` 채움
|
||||
- Company-X용 `project(xvaluelab)` 생성
|
||||
- `slack_workspace.workspace_id`를 채우고 기존 `team_id`는 유지
|
||||
- `slack_channel.workspace_id`를 채우고, `xvaluelab` 채널에 `project_id` 연결
|
||||
- `workspace_member.workspace_id`를 사용자 소속 기준으로 채움
|
||||
|
||||
### Phase 3. 읽기 경로 병행 지원
|
||||
- `auth-server`
|
||||
- `Workspace = Team` alias 제거 준비
|
||||
- Slack OAuth/passport 경로를 `workspace_id` 중심으로 병행 조회
|
||||
- `workspace_member` 조회를 실제 `workspace_id` 구조로 정합화
|
||||
- `robeing-gateway`
|
||||
- `get_user_workspace`, `assign_user_to_workspace`, `slack_user_to_uuid` 병행 지원
|
||||
- Slack `team_id(T...) -> slack_workspace -> workspace/team` 매핑 명확화
|
||||
- `rb8001`
|
||||
- Slack repository에서 `slack_team_id -> workspace/team` 해석 병행 지원
|
||||
- Company-X 전용 상수는 `workspace`/`project` 기반 식별자로 치환 준비
|
||||
- `skill-slack`
|
||||
- `X-Team-Id` 계약을 유지하되 내부에서 workspace-aware lookup 지원
|
||||
- `admin-dashboard`
|
||||
- `workspace + team` 통계 병행 노출 준비
|
||||
|
||||
### Phase 4. 쓰기 경로 dual-write
|
||||
- 새 사용자/조직 연결 시 `team_id`와 `workspace_id`를 함께 기록
|
||||
- Slack 설치/재설치 시 `slack_workspace.workspace_id`와 레거시 `team_id`를 함께 채움
|
||||
- 새 채널/Canvas/프로젝트 연결 시 `project_id` 우선 기록
|
||||
- 운영 로그에 `workspace_id`, `team_id`, `project_id`를 함께 남겨 비교 가능하게 함
|
||||
|
||||
### Phase 5. 서비스별 전환
|
||||
- `auth-server`에서 `workspace`를 실제 `workspace` 엔터티로 전환
|
||||
- `robeing-gateway`에서 사용자 컨텍스트 기본 축을 `workspace + team`으로 변경
|
||||
- `rb8001`에서 Company-X 전용 로직을 `workspace/project` 기반으로 재작성
|
||||
- `skill-rag-file`는 현 단계에서는 `team_document.team_id`를 유지하되, API 계약과 내부 검색 필터에서 `workspace/project` 메타를 병행 지원
|
||||
- `admin-dashboard`는 기존 팀 통계와 새 워크스페이스 통계를 함께 검증
|
||||
|
||||
### Phase 6. 정리 단계
|
||||
- 더 이상 사용하지 않는 `Workspace = Team` alias 제거
|
||||
- `workspace_member` 레거시 해석 제거
|
||||
- `slack_workspace.team_id` 사용처 제거 또는 보조 참조로 축소
|
||||
- `project_name` 문자열 의존 경로 제거
|
||||
- 필요 시 `company`의 역할을 archive/legacy 참조로 축소
|
||||
|
||||
## 데이터 이관 규칙
|
||||
|
||||
### 1. Company-X
|
||||
- `company.name='Company-X'` 기준 `workspace` 1건 생성
|
||||
- 현재 `team.id=79441171-3951-4870-beb8-916d07fe8be5`는 같은 workspace 하위 team으로 유지
|
||||
- `project.name='xvaluelab'` 생성
|
||||
- `slack_workspace.slack_team_id='T09C98KB933'`는 새 Company-X workspace에 연결
|
||||
- `slack_channel.channel_id='C0ALCV5S0FL'`는 Company-X workspace + `xvaluelab` project에 연결
|
||||
|
||||
### 2. Robeing
|
||||
- `company.name='Robeing'` 기준 `workspace` 1건 생성
|
||||
- 기존 `Robeing` team은 해당 workspace 하위 team으로 유지
|
||||
- 하위 project는 후속 운영 구조 확정 후 추가
|
||||
|
||||
### 3. 레거시 보존
|
||||
- 이행 기간 동안 기존 UUID는 가능한 한 재사용합니다.
|
||||
- 신규 엔터티 추가 때문에 기존 `team.id`를 바꾸지 않습니다.
|
||||
- old/new 매핑 테이블 또는 migration note를 남겨 추적성을 확보합니다.
|
||||
|
||||
## 서비스별 검증 체크리스트
|
||||
|
||||
### 1. auth-server
|
||||
- Slack OIDC 로그인 성공
|
||||
- Slack passport install/callback/status/token 성공
|
||||
- Slack uninstall 경로에서 잘못된 `workspace_id` 참조 제거 확인
|
||||
- `workspace_member` 조회가 실제 `workspace_id`를 사용해도 정상 동작
|
||||
|
||||
### 2. robeing-gateway
|
||||
- Slack event 요청에서 bot token 조회 성공
|
||||
- Slack user -> internal UUID 변환 성공
|
||||
- 사용자 소속 조회에서 `workspace`, `team`이 모두 기대값으로 반환
|
||||
|
||||
### 3. rb8001
|
||||
- Slack message/file/event 처리 성공
|
||||
- Company-X grounding 성공
|
||||
- IR 채널 `C0ALCV5S0FL` 읽기/전송 성공
|
||||
- Canvas 조회 성공
|
||||
|
||||
### 4. skill-rag-file
|
||||
- 업로드 API 성공
|
||||
- 기존 Company-X 문서 검색 성공
|
||||
- 재인덱싱 없이도 기존 컬렉션 fallback이 동작
|
||||
|
||||
### 5. skill-slack
|
||||
- Lists 조회/동기화 성공
|
||||
- 내부 팀 식별자와 workspace 매핑이 모두 로그에 남음
|
||||
|
||||
### 6. admin-dashboard
|
||||
- `total_workspaces`, `total_teams` 통계 비교
|
||||
- 사용자 상세 응답에 `workspace_id`, `team_id` 병행 노출 확인
|
||||
|
||||
## 롤백 기준
|
||||
- Slack 로그인 또는 Slack 이벤트 처리 실패가 1건이라도 재현되면 즉시 롤백
|
||||
- Company-X RAG 검색 0건 회귀가 발생하면 즉시 롤백
|
||||
- Company-X IR 채널 읽기/전송 또는 Canvas 조회 실패 시 즉시 롤백
|
||||
- dual-write 비교에서 `workspace_id`와 `team_id` 해석이 어긋나는 데이터가 발견되면 해당 단계는 닫지 않음
|
||||
|
||||
## 예상 리스크와 대응
|
||||
|
||||
### 1. `workspace_member` 정합화 실패
|
||||
- 대응: Phase 1에서 실제 컬럼 추가 후 읽기 경로를 명시적으로 분리
|
||||
|
||||
### 2. Slack payload의 `team_id(T...)`와 내부 UUID 혼선 재발
|
||||
- 대응: Slack 외부 식별자와 내부 식별자를 함수/컬럼명 단계에서 분리
|
||||
|
||||
### 3. Company-X 전용 상수로 인한 부분 회귀
|
||||
- 대응: 상수 제거 전까지는 `workspace_id`, `team_id`, `project_id`를 모두 로그로 남김
|
||||
|
||||
### 4. 기존 RAG 컬렉션명과 새 메타 모델 충돌
|
||||
- 대응: `team_document`와 컬렉션명은 후속 단계까지 유지하고, 이번 계획에서는 metadata bridge만 추가
|
||||
|
||||
## 완료 판정
|
||||
- 계획 문서 단계의 완료는 구현 완료가 아닙니다.
|
||||
- 아래 조건이 채워지면 이 계획 문서는 닫을 수 있습니다.
|
||||
- 목표 ERD 확정
|
||||
- 단계별 DB 변경 순서 확정
|
||||
- 서비스별 병행 지원 범위 확정
|
||||
- 검증 체크리스트와 롤백 기준 확정
|
||||
|
||||
## 다음 단계
|
||||
- 이 문서를 기준으로 DB 마이그레이션 초안 문서를 별도로 작성
|
||||
- `auth-server`, `robeing-gateway`, `rb8001`, `skill-rag-file`, `skill-slack`, `admin-dashboard`별 세부 구현 작업을 worklog로 분리
|
||||
- 전환 시작 전 `tables.md`, `relationships.md`, `380_authentication_system.md` 갱신 순서를 먼저 잡음
|
||||
@ -45,6 +45,11 @@
|
||||
**목표**: StarsAndI 카탈로그 재임베딩, TheGooseCouncil API 전환. 열어둠.
|
||||
**참고**: `plans/260316_임베딩_2차_StarsAndI_GooseCouncil_전환_계획.md`
|
||||
|
||||
### 6. workspace-team-project 계층 재정의 전환 (260316)
|
||||
**상태**: planned
|
||||
**목표**: `team`에 겹쳐 있는 상위 조직/실행 조직 의미를 분리해 `workspace > team`, `team owns project` 구조로 병행 전환
|
||||
**참고**: `plans/260316_workspace_team_project_계층_재정의_전환계획.md`
|
||||
|
||||
## ✅ 완료된 항목 (archive 이동 완료)
|
||||
|
||||
1. **admin_dashboard_business_integration (251204)** - 완료 → archive 이동
|
||||
|
||||
@ -0,0 +1,223 @@
|
||||
tags: [workspace, team, project, database, slack, auth, gateway, rag, research]
|
||||
|
||||
# workspace-team-project 계층 재정의 영향범위 리서치
|
||||
|
||||
상위 원칙:
|
||||
- [0_VALUE Writing Principles](../../../../0_VALUE/02_Governance/writing-principles.md)
|
||||
- [Workspace-Team-Project 도메인 모델](../../book/300_architecture/390_workspace_team_project_%EB%8F%84%EB%A9%94%EC%9D%B8_%EB%AA%A8%EB%8D%B8.md)
|
||||
- [database/tables.md](../../book/300_architecture/database/tables.md)
|
||||
|
||||
관련 문서:
|
||||
- [workspace-team-project 계층 재정의 아이디어](../ideas/260316_workspace_team_project_%EA%B3%84%EC%B8%B5_%EC%9E%AC%EC%A0%95%EC%9D%98_%EC%95%84%EC%9D%B4%EB%94%94%EC%96%B4.md)
|
||||
- [workspace-team-project 계층 재정의 전환계획](../plans/260316_workspace_team_project_%EA%B3%84%EC%B8%B5_%EC%9E%AC%EC%A0%95%EC%9D%98_%EC%A0%84%ED%99%98%EA%B3%84%ED%9A%8D.md)
|
||||
- [통합 인증 시스템 아키텍처](../../book/300_architecture/380_authentication_system.md)
|
||||
- [테이블 관계도](../../book/300_architecture/database/relationships.md)
|
||||
- [Slack install workspace_id error](../troubleshooting/251015_slack_install_workspace_id_error.md)
|
||||
- [PostgreSQL 테이블명 단수형 통일](../troubleshooting/250911_happybell80_PostgreSQL_%ED%85%8C%EC%9D%B4%EB%B8%94%EB%AA%85_%EB%8B%A8%EC%88%98%ED%98%95_%ED%86%B5%EC%9D%BC.md)
|
||||
- [rb8001 skill-rag-file 연동 구조](../troubleshooting/250916_rb8001_skill-rag-file_%EC%97%B0%EB%8F%99_%EA%B5%AC%EC%A1%B0.md)
|
||||
|
||||
## 목적
|
||||
- `workspace > team`, `team owns project` 목표 모델을 현재 운영 구조에 적용하려 할 때 어디에 영향이 가는지 좁힙니다.
|
||||
- 계획 문서를 쓰기 전에 반드시 확인해야 할 코드/DB/문서 충돌 지점을 한 곳에 모읍니다.
|
||||
- 변경 도중과 변경 직후에 발생할 회귀 가능성을 미리 드러냅니다.
|
||||
|
||||
## Facts
|
||||
|
||||
### 1. 현재 운영 DB는 `company + team` 구조이며 `workspace` 테이블은 없습니다.
|
||||
- 2026-03-16 현재 `main_db` 실테이블 확인 결과 존재하는 조직 테이블은 `company`, `team`, `workspace_member`, `slack_workspace`입니다.
|
||||
- 같은 시각 데이터 건수는 다음과 같습니다.
|
||||
|
||||
| 테이블 | 건수 |
|
||||
|---|---:|
|
||||
| `company` | 2 |
|
||||
| `team` | 2 |
|
||||
| `user` | 11 |
|
||||
| `robeing` | 1 |
|
||||
| `slack_workspace` | 2 |
|
||||
| `workspace_member` | 9 |
|
||||
| `team_document` | 145 |
|
||||
| `startup_valuation` | 13 |
|
||||
| `slack_channel` | 6 |
|
||||
| `slack_canvas` | 2 |
|
||||
| `coldmail_list_config` | 2 |
|
||||
|
||||
### 2. `Company-X`는 현재 `company`이면서 동시에 단일 `team`에 거의 모든 실무 데이터가 묶여 있습니다.
|
||||
- `company.name='Company-X'` 아래에 `team.name='Company-X Team'` 한 건이 존재합니다.
|
||||
- 그 `team.id`는 `79441171-3951-4870-beb8-916d07fe8be5`입니다.
|
||||
- 같은 `team_id`에 현재 아래 데이터가 직접 연결돼 있습니다.
|
||||
- `user`: 8명
|
||||
- `slack_workspace`: 1건 (`slack_team_id=T09C98KB933`)
|
||||
- `team_document`: 129건
|
||||
- `startup_valuation`: 13건
|
||||
- `slack_channel`: 4건
|
||||
- 같은 `slack_workspace.id=59f4aeda-8ad0-4ab7-a818-5ee8dd14f5d1` 아래에는 `coldmail_list_config` 1건도 연결돼 있습니다.
|
||||
- 즉 현재 운영 현실에서 `Company-X Team`은 단순 팀이 아니라, 사실상 Company-X 전체 실행 컨텍스트처럼 쓰이고 있습니다.
|
||||
|
||||
### 3. `workspace_member`는 이름과 달리 현재 `workspace_id` FK가 없습니다.
|
||||
- 2026-03-16 현재 `workspace_member` 컬럼은 `id`, `user_id`, `role`, `is_active`, `joined_at`, `updated_at`, `slack_user_id`만 있습니다.
|
||||
- `workspace_id` 컬럼이 실제 DB에 없습니다.
|
||||
- 그런데 여러 코드/문서가 `workspace_member.workspace_id` 존재를 전제로 작성돼 있거나, 반대로 `user.team_id`를 사실상 `workspace_id`처럼 대신 쓰고 있습니다.
|
||||
|
||||
### 4. 인증 계층은 `Workspace`라는 이름을 쓰지만 실제 구현은 `Team` alias입니다.
|
||||
- `auth-server/app/models/workspace.py`는 `Company`, `Team`, `SlackWorkspace` 모델을 정의하고 마지막에 `Workspace = Team` alias를 둡니다.
|
||||
- 같은 파일에서 `SlackWorkspace.team_id -> team.id` FK를 유지합니다.
|
||||
- `auth-server/app/models/user.py`의 `User.team_id`도 여전히 `team.id` FK입니다.
|
||||
- 즉 API/함수 이름은 workspace지만 실제 PK/FK는 team을 가리키는 구간이 많습니다.
|
||||
|
||||
### 5. Slack OAuth와 Slack passport 경로는 `workspace`라는 이름으로 `user.team_id`를 사용합니다.
|
||||
- `auth-server/app/providers/slack.py`에서 Slack OIDC 로그인 시 Slack `team_id(T...)`를 `slack_workspace.slack_team_id`로 찾고, 그 결과 `slack_workspace.team_id`를 내부 사용자의 `team_id`에 넣습니다.
|
||||
- 같은 파일의 `/passport/install` 경로는 주석상 `workspace_id 조회`라고 적지만 실제 구현은 `workspace_id = user.team_id`입니다.
|
||||
- `/passport/callback`, `/passport/status/{workspace_id}`, `/passport/token/{workspace_id}`도 실제로는 `SlackWorkspace.team_id == workspace_id`를 사용합니다.
|
||||
|
||||
### 6. `auth-server`에는 실제 운영 DB와 다른 방향의 미완료 마이그레이션 흔적이 남아 있습니다.
|
||||
- `auth-server/migrations/add_user_workspace_tables.sql`은 `companies -> workspaces`, `workspace_members`(복수형), `slack_workspaces.workspace_id` 같은 구조를 전제합니다.
|
||||
- 하지만 현재 `main_db`에는 `company`, `team`, `workspace_member`, `slack_workspace`가 존재하고 `workspaces`, `workspace_members`, `slack_workspaces`는 없습니다.
|
||||
- 즉 auth 문서/마이그레이션 설계와 실제 운영 DB가 이미 어긋나 있습니다.
|
||||
|
||||
### 7. `auth-server` Slack 라우터도 `team`과 `workspace`를 혼용한 상태입니다.
|
||||
- `auth-server/app/api/slack_router.py`는 Slack 이벤트 payload의 `team_id(T...)`를 읽고도 `SlackWorkspace.team_id == team_id`로 조회하는 경로를 포함합니다.
|
||||
- `auth-server/app/providers/slack.py`에는 `SlackWorkspace.workspace_id`를 참조하는 제거 경로가 남아 있지만 실제 모델 컬럼은 `team_id`입니다.
|
||||
- `auth-server/app/models/user.py`의 `WorkspaceMember.__repr__`도 실제로 존재하지 않는 `workspace_id`를 문자열에 포함합니다.
|
||||
- 즉 인증 서버 안에서도 `workspace`라는 이름과 실제 컬럼 구조가 서로 맞지 않는 코드가 이미 공존합니다.
|
||||
|
||||
### 8. `robeing-gateway`는 사용자 라우팅, Slack 토큰 조회, Slack UUID 변환을 모두 `team` 전제로 수행합니다.
|
||||
- `robeing-gateway/app/database.py`의 `get_user_workspace()`는 `user -> team -> company` 조인으로 사용자 소속을 조회합니다.
|
||||
- 같은 파일의 `slack_user_to_uuid()`는 `user.team_id -> team.id -> slack_workspace.team_id` 조인으로 Slack 사용자 UUID를 변환합니다.
|
||||
- `get_slack_bot_token()`은 Slack `team_id(T...)`를 받아 `slack_workspace.slack_team_id`로 토큰을 찾습니다.
|
||||
- `assign_user_to_workspace()`는 함수 이름과 달리 현재 `workspace_member`에 `user_id`만 기록하며 `workspace_id`를 저장하지 않습니다.
|
||||
|
||||
### 9. `rb8001`은 Slack 팀을 내부 `team_id`로 바꾸는 경로와 Company-X 전용 로직 모두를 `team` 중심으로 가정합니다.
|
||||
- `rb8001/app/state/slack_repository.py`는 `slack_workspace.slack_team_id -> slack_workspace.team_id` 조회로 `team UUID`를 반환합니다.
|
||||
- `rb8001/app/router/slack_handler.py`, `app/services/slack/message_service.py`, `app/services/slack/file_service.py`는 Slack 요청 처리에서 이 변환을 그대로 사용합니다.
|
||||
- `rb8001/app/services/companyx_grounding_service.py`는 `COMPANYX_TEAM_ID = 79441171-...` 상수를 기준으로 Company-X 사용자 여부를 판정합니다.
|
||||
- `app/services/naverworks_file_processor.py`, `app/services/ir_deck_analyzer.py`, `app/services/startup_valuation.py`도 문서/분석/RAG 흐름에서 `team_id`를 핵심 인자로 사용합니다.
|
||||
|
||||
### 10. RAG/문서 계층은 `team_document`와 컬렉션명 모두 `team_id`에 고정돼 있습니다.
|
||||
- `skill-rag-file/app/api/upload.py`는 업로드 시 `X-Team-Id` 헤더를 필수로 받으며, 먼저 `SELECT 1 FROM team WHERE id = :team_id`로 팀 존재를 검증합니다.
|
||||
- 같은 서비스는 DB 레코드를 `team_document.team_id`로 저장하고, Chroma 컬렉션 이름도 `skill_rag_file_{team_id}_documents`를 사용합니다.
|
||||
- `team_document` 145건 중 `Company-X Team` 소속이 129건으로 가장 큽니다.
|
||||
- 따라서 `Company-X Team`의 의미를 바꾸면 저장 경로, 컬렉션명, 업로드 검증, 재인덱싱 스크립트가 모두 영향권입니다.
|
||||
|
||||
### 11. `skill-slack`도 내부 식별자를 `team_id`로 받아 Slack workspace로 역변환합니다.
|
||||
- `skill-slack/app/state/slack_workspace_repository.py`는 `get_slack_team_id_by_team_id(team_id)`로 내부 팀 UUID를 Slack `slack_team_id`로 바꿉니다.
|
||||
- `skill-slack/app/api/endpoints/lists.py`를 포함한 Slack Lists 경로는 `X-Team-Id`를 받아 이 변환 결과로 Slack API를 호출합니다.
|
||||
- 따라서 조직 축을 재정의할 때 `rb8001`뿐 아니라 `skill-slack`도 함께 병행 지원 대상에 넣어야 합니다.
|
||||
|
||||
### 12. 운영 DB의 FK는 이미 `company -> team -> slack_workspace -> channel/canvas`와 `team -> document/valuation` 축으로 닫혀 있습니다.
|
||||
- `team.company_id -> company.id`
|
||||
- `user.team_id`, `robeing.team_id`, `slack_workspace.team_id`, `team_document.team_id`, `startup_valuation.team_id`가 모두 `team.id`를 참조합니다.
|
||||
- `slack_channel.slack_workspace_id -> slack_workspace.id`, `slack_canvas.slack_channel_id -> slack_channel.id`, `coldmail_list_config.slack_workspace_id -> slack_workspace.id`도 운영 중입니다.
|
||||
- 즉 이번 문제는 일부 화면만 바꾸는 수준이 아니라 실제 FK 그래프 자체를 재배치하는 작업입니다.
|
||||
|
||||
### 13. 관리자 대시보드도 사용자/로빙 통계를 `team_id` 기준으로 집계합니다.
|
||||
- `admin-dashboard/backend/state/user_repository.py`는 사용자 응답 모델에 `team_id`를 노출하고 `COUNT(DISTINCT team_id)`를 통계로 사용합니다.
|
||||
- `admin-dashboard/backend/state/robeing_repository.py`도 `team_id`를 그대로 응답하고 `teams_with_robeings`를 집계합니다.
|
||||
- 대응 Pydantic 스키마 역시 `team_id: UUID`를 필수 필드로 고정합니다.
|
||||
|
||||
### 14. Slack 채널/Canvas 계층은 이미 `project_name`을 임시 보강했지만 FK는 여전히 `team` 계층 위에 걸려 있습니다.
|
||||
- `slack_channel`은 `slack_workspace_id -> slack_workspace.id` FK를 가집니다.
|
||||
- `slack_canvas`는 `slack_channel_id -> slack_channel.id` FK를 가집니다.
|
||||
- 현재 `C0ALCV5S0FL` 채널에는 `project_name='xvaluelab'`이 들어가 있고, Canvas 2건도 같은 채널에 연결돼 있습니다.
|
||||
- 하지만 이 `project_name`은 FK가 아니라 보강 필드라서 현재 조직 구조를 교정하지는 못합니다.
|
||||
|
||||
### 15. 관련 문서 계층도 이미 `workspace`와 `team`을 혼용하고 있습니다.
|
||||
- [380_authentication_system.md](../../book/300_architecture/380_authentication_system.md)는 `company vs workspaces 테이블 공존`을 미해결로 적고 있습니다.
|
||||
- [database/relationships.md](../../book/300_architecture/database/relationships.md)는 `workspaces`, `workspace_member.workspace_id` 같은 구조를 설명하지만, 현재 실DB와 다릅니다.
|
||||
- [251015_slack_install_workspace_id_error.md](../troubleshooting/251015_slack_install_workspace_id_error.md)와 [251016_troubleshooting_summary.md](../troubleshooting/251016_troubleshooting_summary.md)는 실제 `workspace_member.workspace_id`가 없어서 `user.team_id`를 대신 사용했다고 기록합니다.
|
||||
- 즉 이번 문제는 새로 생긴 문제가 아니라, 문서와 구현이 서로 다른 방향으로 누적된 상태입니다.
|
||||
|
||||
## Interpretation
|
||||
|
||||
### 1. 이번 문제는 단순 테이블 추가가 아니라 도메인 기준 복구 문제입니다.
|
||||
- 현재 구조는 `company`, `team`, `workspace`, `slack_workspace`가 역할별로 분리된 것이 아니라, 이름과 실제 의미가 서로 다른 채 중첩돼 있습니다.
|
||||
- 그래서 `workspace`를 새로 만든다고 끝나지 않고, 현재 `team`이 맡고 있는 상위 조직 의미를 어디까지 분리할지부터 고정해야 합니다.
|
||||
|
||||
### 2. 가장 먼저 깨질 축은 Slack 인증/Slack 라우팅입니다.
|
||||
- Slack OIDC, Slack passport, gateway Slack proxy, rb8001 Slack event/file/message 처리 모두 `Slack team ID -> internal team UUID` 변환에 기대고 있습니다.
|
||||
- 이 경로를 먼저 병행 지원 없이 바꾸면 로그인, 이벤트 수신, 사용자 UUID 변환, 봇 토큰 조회가 함께 깨질 가능성이 큽니다.
|
||||
|
||||
### 3. 두 번째로 큰 영향은 Company-X RAG와 문서 저장 축입니다.
|
||||
- 현재 Company-X 내부문서, 채널, Canvas, grounding 로직이 모두 `Company-X Team UUID`를 사실상 고객/워크스페이스 식별자처럼 사용하고 있습니다.
|
||||
- 따라서 `team_document`, Chroma 컬렉션명, `COMPANYX_TEAM_ID` 상수, `X-Team-Id` 헤더 규약을 병행 지원 없이 바꾸면 Company-X 질문 응답과 업로드 파이프가 곧바로 회귀할 가능성이 큽니다.
|
||||
|
||||
### 4. 부수 업무 테이블도 이미 `team` 또는 `slack_workspace`에 붙어 있어서 영향 범위가 예상보다 넓습니다.
|
||||
- `startup_valuation`은 현재 전량이 `Company-X Team`에 연결돼 있습니다.
|
||||
- `coldmail_list_config`는 `slack_workspace_id`에 묶여 있어 Slack workspace 재배치와 함께 검토해야 합니다.
|
||||
- 따라서 이번 변경은 Slack 채널만이 아니라 valuation, 콜드메일 운영 설정, 대시보드 집계까지 함께 영향권입니다.
|
||||
|
||||
### 5. `workspace_member`는 구조상 가장 위험한 부채 지점입니다.
|
||||
- 이름은 workspace membership이지만 실제 DB에는 `workspace_id`가 없습니다.
|
||||
- 코드도 이를 일관되게 다루지 못하고 `workspace_member`를 사용자-로빙 매핑처럼 쓰는 구간과, `user.team_id`를 workspace처럼 대체하는 구간으로 나뉘어 있습니다.
|
||||
- 따라서 계획 문서에서는 `workspace_member`를 유지/교체/재정의 중 무엇으로 갈지 먼저 고정해야 합니다.
|
||||
|
||||
### 6. 문서 SSOT도 함께 교정하지 않으면 재발 가능성이 큽니다.
|
||||
- 현재 DOCS 안에서도 `company -> workspaces 통합 완료`처럼 남아 있는 문서와, 실제 DB 현실이 다릅니다.
|
||||
- 이번 문제를 푸는 동안 코드를 고쳐도 상위 해석 문서와 하위 구조 문서가 계속 엇갈리면 같은 혼선이 다시 발생할 가능성이 높습니다.
|
||||
|
||||
## Unresolved
|
||||
|
||||
### 1. 새 `workspace` 테이블을 `company`의 이름 변경으로 갈지, 별도 신설로 갈지는 아직 미확정입니다.
|
||||
|
||||
### 2. 현재 `Company-X Team`을 분해할 실제 실행 팀 수와, `xvaluelab` 외 프로젝트 목록은 아직 미확정입니다.
|
||||
|
||||
### 3. `workspace_member`를 `workspace_id` 포함 구조로 정상화할지, 별도 membership 테이블로 대체할지는 아직 미확정입니다.
|
||||
|
||||
### 4. `slack_workspace.team_id`를 `workspace_id`로 바꿀지, `workspace_id + owner_team_id` 이중 참조로 갈지는 아직 미확정입니다.
|
||||
|
||||
### 5. `team_document.team_id`를 `project_id` 또는 `workspace_id`로 옮길 때 컬렉션명과 저장 경로를 어떻게 병행 운영할지는 아직 미확정입니다.
|
||||
|
||||
### 6. 관리자 화면에서 보여줄 기본 조직 축을 `team` 중심으로 둘지 `workspace + team` 2계층으로 바꿀지는 아직 미확정입니다.
|
||||
|
||||
## 계획 수립 시 반드시 참고할 내용
|
||||
|
||||
### 1. 병행 지원 순서가 필요합니다.
|
||||
- 우선 `workspace`, `team`, `project` 새 해석을 추가합니다.
|
||||
- 그 다음 기존 `team_id` 경로를 유지한 채 새 FK/새 조회를 병행 지원해야 합니다.
|
||||
- 마지막에 데이터 이관과 레거시 제거를 진행해야 합니다.
|
||||
|
||||
### 2. Slack 경로를 1순위 검증 대상으로 잡아야 합니다.
|
||||
- 검증 대상:
|
||||
- Slack OIDC 로그인
|
||||
- Slack passport install/callback/status/token
|
||||
- gateway Slack event/interative proxy
|
||||
- rb8001 Slack event/file/message 처리
|
||||
|
||||
### 3. Company-X RAG 경로를 2순위 검증 대상으로 잡아야 합니다.
|
||||
- 검증 대상:
|
||||
- `team_document` 업로드
|
||||
- `skill-rag-file` 검색
|
||||
- Company-X grounding
|
||||
- IR 채널/Canvas 조회와 전송
|
||||
|
||||
### 4. 문서 SSOT 갱신을 계획에 포함해야 합니다.
|
||||
- 갱신 대상:
|
||||
- `database/tables.md`
|
||||
- `database/relationships.md`
|
||||
- `380_authentication_system.md`
|
||||
- 관련 troubleshooting 중 현실과 충돌하는 문서
|
||||
|
||||
## 예상 회귀 지점
|
||||
|
||||
### 변경 도중 발생 가능
|
||||
- Slack 로그인은 되지만 사용자 `team_id`/`workspace_id` 매핑이 어긋나 `team_not_found` 또는 403이 발생할 수 있습니다.
|
||||
- gateway가 Slack `team_id(T...)`는 받지만 내부 UUID 변환을 못 해서 사용자 미등록 오류가 날 수 있습니다.
|
||||
- `auth-server`의 Slack 이벤트/설치 해제 경로처럼 이미 혼용된 코드가 먼저 터져 특정 API만 500이 날 수 있습니다.
|
||||
- `skill-rag-file`가 새 조직 ID를 인식하지 못해 업로드 404 또는 검색 0건이 될 수 있습니다.
|
||||
- `skill-slack` Lists 경로가 새 식별자를 Slack `slack_team_id`로 바꾸지 못해 리스트 조회/동기화가 실패할 수 있습니다.
|
||||
- Company-X 전용 상수가 남아 있으면 일부 경로만 옛 `team_id`를 계속 사용해 이중 상태가 생길 수 있습니다.
|
||||
|
||||
### 변경 후 발생 가능
|
||||
- 관리자 대시보드의 `total_teams`, `teams_with_robeings` 같은 통계가 새 해석과 맞지 않아 숫자가 왜곡될 수 있습니다.
|
||||
- 기존 Chroma 컬렉션명과 스토리지 경로가 `team_id` 기반이라 과거 문서 검색이 누락될 수 있습니다.
|
||||
- `workspace_member` 정리가 불완전하면 사용자-로빙 배정과 권한 판정이 일부 사용자에서만 깨질 수 있습니다.
|
||||
- `startup_valuation`, `coldmail_list_config`를 이관 목록에서 빼먹으면 Company-X 운영 기능 일부만 조용히 실패하는 비대칭 회귀가 생길 수 있습니다.
|
||||
- 문서 SSOT를 함께 갱신하지 않으면 이후 운영자가 `workspace`, `team`, `project`를 다시 혼용할 수 있습니다.
|
||||
|
||||
## 이번 리서치의 닫힘 조건
|
||||
- 이 문서는 문제 해결 문서가 아닙니다.
|
||||
- 다음 단계에서 닫아야 할 것은 `plans` 문서이며, 그 계획은 최소한 아래를 포함해야 합니다.
|
||||
- 목표 ERD
|
||||
- 병행 지원 순서
|
||||
- 데이터 이관 규칙
|
||||
- 서비스별 검증 체크리스트
|
||||
- 롤백 기준
|
||||
@ -16,6 +16,7 @@
|
||||
- [Company X RAG 답변합성 시나리오·트러블 동시종결 리서치 (260315)](./260315_companyx_rag_답변합성_시나리오동시종결_리서치.md)
|
||||
- [스킬 계약 문서 기반 컨텍스트 오케스트레이션 리서치 (260314)](./260314_스킬_계약_문서_기반_컨텍스트_오케스트레이션_리서치.md)
|
||||
- [Ralph Loop 참조 및 RAG 적용 (260316)](./260316_Ralph_Loop_참조_및_RAG_적용.md)
|
||||
- [workspace-team-project 계층 재정의 영향범위 리서치 (260316)](./260316_workspace_team_project_계층_재정의_영향범위_리서치.md)
|
||||
- [임베딩 1차 로빙 현황 SSOT (260316)](./rag/260316_임베딩_1차_로빙_현황_SSOT_리서치.md)
|
||||
- [임베딩 2차 StarsAndI·GooseCouncil 현황 (260316)](./rag/260316_임베딩_2차_StarsAndI_GooseCouncil_현황_리서치.md)
|
||||
- [임베딩 전체 프로젝트 현황 및 SSOT (260316, 인덱스)](./rag/260316_임베딩_전체프로젝트_현황_및_SSOT_리서치.md)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user