docs: add workspace-team-project impact research

This commit is contained in:
happybell80 2026-03-16 13:18:03 +09:00
parent 66e3730fe1
commit 8074f9d236
4 changed files with 195 additions and 0 deletions

View File

@ -10,6 +10,7 @@
- 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`
### 닫힌 문제

View File

@ -40,6 +40,7 @@ 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)
- [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)

View File

@ -0,0 +1,192 @@
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)
- [통합 인증 시스템 아키텍처](../../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 |
| `slack_channel` | 6 |
### 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건
- `slack_channel`: 4건
- 즉 현재 운영 현실에서 `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. `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`를 저장하지 않습니다.
### 8. `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`를 핵심 인자로 사용합니다.
### 9. 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`의 의미를 바꾸면 저장 경로, 컬렉션명, 업로드 검증, 재인덱싱 스크립트가 모두 영향권입니다.
### 10. 관리자 대시보드도 사용자/로빙 통계를 `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`를 필수 필드로 고정합니다.
### 11. 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가 아니라 보강 필드라서 현재 조직 구조를 교정하지는 못합니다.
### 12. 관련 문서 계층도 이미 `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. `workspace_member`는 구조상 가장 위험한 부채 지점입니다.
- 이름은 workspace membership이지만 실제 DB에는 `workspace_id`가 없습니다.
- 코드도 이를 일관되게 다루지 못하고 `workspace_member`를 사용자-로빙 매핑처럼 쓰는 구간과, `user.team_id`를 workspace처럼 대체하는 구간으로 나뉘어 있습니다.
- 따라서 계획 문서에서는 `workspace_member`를 유지/교체/재정의 중 무엇으로 갈지 먼저 고정해야 합니다.
### 5. 문서 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 변환을 못 해서 사용자 미등록 오류가 날 수 있습니다.
- `skill-rag-file`가 새 조직 ID를 인식하지 못해 업로드 404 또는 검색 0건이 될 수 있습니다.
- Company-X 전용 상수가 남아 있으면 일부 경로만 옛 `team_id`를 계속 사용해 이중 상태가 생길 수 있습니다.
### 변경 후 발생 가능
- 관리자 대시보드의 `total_teams`, `teams_with_robeings` 같은 통계가 새 해석과 맞지 않아 숫자가 왜곡될 수 있습니다.
- 기존 Chroma 컬렉션명과 스토리지 경로가 `team_id` 기반이라 과거 문서 검색이 누락될 수 있습니다.
- `workspace_member` 정리가 불완전하면 사용자-로빙 배정과 권한 판정이 일부 사용자에서만 깨질 수 있습니다.
- 문서 SSOT를 함께 갱신하지 않으면 이후 운영자가 `workspace`, `team`, `project`를 다시 혼용할 수 있습니다.
## 이번 리서치의 닫힘 조건
- 이 문서는 문제 해결 문서가 아닙니다.
- 다음 단계에서 닫아야 할 것은 `plans` 문서이며, 그 계획은 최소한 아래를 포함해야 합니다.
- 목표 ERD
- 병행 지원 순서
- 데이터 이관 규칙
- 서비스별 검증 체크리스트
- 롤백 기준

View File

@ -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)
- [임베딩 전체 프로젝트 현황 및 SSOT 리서치 (260316)](./rag/260316_임베딩_전체프로젝트_현황_및_SSOT_리서치.md)
### [기억(Memory)](./memory/README.md)