@things-factory/integration-label-studio 9.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +85 -0
- package/EXTERNAL_DATA_SOURCING.md +484 -0
- package/IMPLEMENTATION_GUIDE.md +469 -0
- package/INTEGRATION.md +279 -0
- package/README.md +1014 -0
- package/SETUP_GUIDE.md +577 -0
- package/TEST_GUIDE.md +387 -0
- package/UI_CUSTOMIZATION.md +395 -0
- package/USER_SYNC_GUIDE.md +514 -0
- package/client/bootstrap.ts +1 -0
- package/client/index.ts +1 -0
- package/client/label-studio-label-page.ts +52 -0
- package/client/label-studio-project-create.ts +216 -0
- package/client/label-studio-project-list.ts +214 -0
- package/client/label-studio-wrapper.ts +294 -0
- package/client/route.ts +15 -0
- package/client/tsconfig.json +13 -0
- package/config/config.development.js +124 -0
- package/config/config.production.js +182 -0
- package/dist-client/bootstrap.d.ts +1 -0
- package/dist-client/bootstrap.js +2 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/index.d.ts +1 -0
- package/dist-client/index.js +2 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/label-studio-label-page.d.ts +8 -0
- package/dist-client/label-studio-label-page.js +54 -0
- package/dist-client/label-studio-label-page.js.map +1 -0
- package/dist-client/label-studio-project-create.d.ts +16 -0
- package/dist-client/label-studio-project-create.js +235 -0
- package/dist-client/label-studio-project-create.js.map +1 -0
- package/dist-client/label-studio-project-list.d.ts +16 -0
- package/dist-client/label-studio-project-list.js +222 -0
- package/dist-client/label-studio-project-list.js.map +1 -0
- package/dist-client/label-studio-wrapper.d.ts +57 -0
- package/dist-client/label-studio-wrapper.js +304 -0
- package/dist-client/label-studio-wrapper.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +14 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-server/controller/label-studio-role-mapper.d.ts +35 -0
- package/dist-server/controller/label-studio-role-mapper.js +65 -0
- package/dist-server/controller/label-studio-role-mapper.js.map +1 -0
- package/dist-server/controller/user-provisioning-service.d.ts +66 -0
- package/dist-server/controller/user-provisioning-service.js +264 -0
- package/dist-server/controller/user-provisioning-service.js.map +1 -0
- package/dist-server/index.d.ts +7 -0
- package/dist-server/index.js +19 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/route/label-studio-sso.d.ts +2 -0
- package/dist-server/route/label-studio-sso.js +156 -0
- package/dist-server/route/label-studio-sso.js.map +1 -0
- package/dist-server/route/webhook.d.ts +65 -0
- package/dist-server/route/webhook.js +248 -0
- package/dist-server/route/webhook.js.map +1 -0
- package/dist-server/route.d.ts +1 -0
- package/dist-server/route.js +21 -0
- package/dist-server/route.js.map +1 -0
- package/dist-server/service/ai-prediction-service.d.ts +27 -0
- package/dist-server/service/ai-prediction-service.js +222 -0
- package/dist-server/service/ai-prediction-service.js.map +1 -0
- package/dist-server/service/dataset-labeling-integration.d.ts +44 -0
- package/dist-server/service/dataset-labeling-integration.js +512 -0
- package/dist-server/service/dataset-labeling-integration.js.map +1 -0
- package/dist-server/service/external-data-source-service.d.ts +78 -0
- package/dist-server/service/external-data-source-service.js +415 -0
- package/dist-server/service/external-data-source-service.js.map +1 -0
- package/dist-server/service/index.d.ts +12 -0
- package/dist-server/service/index.js +27 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/label-studio-sso-service.d.ts +38 -0
- package/dist-server/service/label-studio-sso-service.js +98 -0
- package/dist-server/service/label-studio-sso-service.js.map +1 -0
- package/dist-server/service/ml/ml-backend-service.d.ts +23 -0
- package/dist-server/service/ml/ml-backend-service.js +153 -0
- package/dist-server/service/ml/ml-backend-service.js.map +1 -0
- package/dist-server/service/prediction/prediction-management.d.ts +32 -0
- package/dist-server/service/prediction/prediction-management.js +299 -0
- package/dist-server/service/prediction/prediction-management.js.map +1 -0
- package/dist-server/service/project/project-management.d.ts +36 -0
- package/dist-server/service/project/project-management.js +309 -0
- package/dist-server/service/project/project-management.js.map +1 -0
- package/dist-server/service/task/task-management.d.ts +42 -0
- package/dist-server/service/task/task-management.js +372 -0
- package/dist-server/service/task/task-management.js.map +1 -0
- package/dist-server/service/user-provisioning/user-sync-mutation.d.ts +28 -0
- package/dist-server/service/user-provisioning/user-sync-mutation.js +111 -0
- package/dist-server/service/user-provisioning/user-sync-mutation.js.map +1 -0
- package/dist-server/service/webhook/webhook-management.d.ts +21 -0
- package/dist-server/service/webhook/webhook-management.js +134 -0
- package/dist-server/service/webhook/webhook-management.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/dist-server/types/dataset-labeling-types.d.ts +71 -0
- package/dist-server/types/dataset-labeling-types.js +259 -0
- package/dist-server/types/dataset-labeling-types.js.map +1 -0
- package/dist-server/types/label-studio-types.d.ts +128 -0
- package/dist-server/types/label-studio-types.js +494 -0
- package/dist-server/types/label-studio-types.js.map +1 -0
- package/dist-server/types/prediction-types.d.ts +39 -0
- package/dist-server/types/prediction-types.js +121 -0
- package/dist-server/types/prediction-types.js.map +1 -0
- package/dist-server/utils/annotation-exporter.d.ts +104 -0
- package/dist-server/utils/annotation-exporter.js +261 -0
- package/dist-server/utils/annotation-exporter.js.map +1 -0
- package/dist-server/utils/label-config-builder.d.ts +117 -0
- package/dist-server/utils/label-config-builder.js +286 -0
- package/dist-server/utils/label-config-builder.js.map +1 -0
- package/dist-server/utils/label-studio-api-client.d.ts +180 -0
- package/dist-server/utils/label-studio-api-client.js +401 -0
- package/dist-server/utils/label-studio-api-client.js.map +1 -0
- package/dist-server/utils/media-url-extractor.d.ts +45 -0
- package/dist-server/utils/media-url-extractor.js +152 -0
- package/dist-server/utils/media-url-extractor.js.map +1 -0
- package/dist-server/utils/task-transformer.d.ts +108 -0
- package/dist-server/utils/task-transformer.js +260 -0
- package/dist-server/utils/task-transformer.js.map +1 -0
- package/package.json +47 -0
- package/server/SERVER_STRUCTURE.md +351 -0
- package/server/controller/label-studio-role-mapper.ts +76 -0
- package/server/controller/user-provisioning-service.ts +340 -0
- package/server/index.ts +19 -0
- package/server/route/label-studio-sso.ts +194 -0
- package/server/route/webhook.ts +304 -0
- package/server/route.ts +35 -0
- package/server/service/ai-prediction-service.ts +239 -0
- package/server/service/dataset-labeling-integration.ts +590 -0
- package/server/service/external-data-source-service.ts +438 -0
- package/server/service/index.ts +24 -0
- package/server/service/label-studio-sso-service.ts +108 -0
- package/server/service/labeling-scenario-service.ts.deprecated +566 -0
- package/server/service/ml/ml-backend-service.ts +127 -0
- package/server/service/prediction/prediction-management.ts +281 -0
- package/server/service/project/project-management.ts +284 -0
- package/server/service/task/task-management.ts +363 -0
- package/server/service/user-provisioning/user-sync-mutation.ts +80 -0
- package/server/service/webhook/webhook-management.ts +109 -0
- package/server/tsconfig.json +11 -0
- package/server/types/dataset-labeling-types.ts +181 -0
- package/server/types/global.d.ts +23 -0
- package/server/types/label-studio-types.ts +346 -0
- package/server/types/prediction-types.ts +86 -0
- package/server/types/scenario-types.ts.deprecated +362 -0
- package/server/utils/annotation-exporter.ts +340 -0
- package/server/utils/label-config-builder.ts +340 -0
- package/server/utils/label-studio-api-client.ts +487 -0
- package/server/utils/media-url-extractor.ts +193 -0
- package/server/utils/task-transformer.ts +342 -0
- package/test-ai-prediction.js +268 -0
- package/test-dataset-integration.js +449 -0
- package/test-simple.js +89 -0
- package/things-factory.config.js +12 -0
package/SETUP_GUIDE.md
ADDED
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
# Things-Factory & Label Studio Custom 통합 설정 가이드
|
|
2
|
+
|
|
3
|
+
Things-Factory에서 Label Studio Custom (SSO Edition)을 iframe으로 통합하고 SSO를 사용하는 완전한 설정 가이드입니다.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📋 사전 요구사항
|
|
8
|
+
|
|
9
|
+
- Things-Factory 서버 (9.1.0+)
|
|
10
|
+
- Label Studio Custom Docker 이미지: `ghcr.io/aidoop/label-studio-custom:1.20.0-sso.38`
|
|
11
|
+
- Docker & Docker Compose 설치
|
|
12
|
+
- PostgreSQL 13+ (Docker로 실행 가능)
|
|
13
|
+
- 관리자 권한
|
|
14
|
+
- HTTPS 사용 권장 (프로덕션 필수)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 🐳 0단계: Label Studio Custom Docker 설치
|
|
19
|
+
|
|
20
|
+
### Docker Compose로 빠른 설치
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# 1. 프로젝트 디렉토리 생성
|
|
24
|
+
mkdir label-studio-deployment
|
|
25
|
+
cd label-studio-deployment
|
|
26
|
+
|
|
27
|
+
# 2. docker-compose.yml 작성
|
|
28
|
+
cat > docker-compose.yml << 'EOF'
|
|
29
|
+
version: "3.8"
|
|
30
|
+
|
|
31
|
+
services:
|
|
32
|
+
postgres:
|
|
33
|
+
image: postgres:13.18
|
|
34
|
+
container_name: label-studio-postgres
|
|
35
|
+
restart: unless-stopped
|
|
36
|
+
|
|
37
|
+
environment:
|
|
38
|
+
POSTGRES_DB: labelstudio
|
|
39
|
+
POSTGRES_USER: postgres
|
|
40
|
+
POSTGRES_PASSWORD: dev_postgres_2024
|
|
41
|
+
PGDATA: /var/lib/postgresql/data/pgdata
|
|
42
|
+
|
|
43
|
+
volumes:
|
|
44
|
+
- postgres_data:/var/lib/postgresql/data
|
|
45
|
+
|
|
46
|
+
ports:
|
|
47
|
+
- "5432:5432"
|
|
48
|
+
|
|
49
|
+
networks:
|
|
50
|
+
- labelstudio
|
|
51
|
+
|
|
52
|
+
labelstudio:
|
|
53
|
+
image: ghcr.io/aidoop/label-studio-custom:1.20.0-sso.38
|
|
54
|
+
container_name: label-studio-app
|
|
55
|
+
restart: unless-stopped
|
|
56
|
+
|
|
57
|
+
depends_on:
|
|
58
|
+
- postgres
|
|
59
|
+
|
|
60
|
+
environment:
|
|
61
|
+
# Database
|
|
62
|
+
DJANGO_DB: default
|
|
63
|
+
POSTGRES_HOST: postgres
|
|
64
|
+
POSTGRES_PORT: 5432
|
|
65
|
+
POSTGRES_DB: labelstudio
|
|
66
|
+
POSTGRES_USER: postgres
|
|
67
|
+
POSTGRES_PASSWORD: dev_postgres_2024
|
|
68
|
+
|
|
69
|
+
# Django
|
|
70
|
+
DEBUG: false
|
|
71
|
+
LOG_LEVEL: INFO
|
|
72
|
+
|
|
73
|
+
# SSO Configuration
|
|
74
|
+
JWT_SSO_NATIVE_USER_ID_CLAIM: user_id
|
|
75
|
+
JWT_SSO_COOKIE_NAME: ls_auth_token
|
|
76
|
+
JWT_SSO_TOKEN_PARAM: token
|
|
77
|
+
SSO_TOKEN_EXPIRY: 600
|
|
78
|
+
|
|
79
|
+
# Label Studio
|
|
80
|
+
LABEL_STUDIO_HOST: http://label.hatiolab.localhost:8080
|
|
81
|
+
|
|
82
|
+
# Cookie Settings (서브도메인 공유)
|
|
83
|
+
SESSION_COOKIE_DOMAIN: .hatiolab.localhost
|
|
84
|
+
CSRF_COOKIE_DOMAIN: .hatiolab.localhost
|
|
85
|
+
|
|
86
|
+
# iframe Security Headers
|
|
87
|
+
CSP_FRAME_ANCESTORS: "'self' http://localhost:3000 http://hatiolab.localhost:3000"
|
|
88
|
+
|
|
89
|
+
# Other
|
|
90
|
+
FEATURE_FLAGS_OFFLINE: true
|
|
91
|
+
STORAGE_PERSISTENCE: true
|
|
92
|
+
|
|
93
|
+
volumes:
|
|
94
|
+
- labelstudio_data:/label-studio/data
|
|
95
|
+
|
|
96
|
+
ports:
|
|
97
|
+
- "8080:8080"
|
|
98
|
+
|
|
99
|
+
healthcheck:
|
|
100
|
+
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
|
101
|
+
interval: 30s
|
|
102
|
+
timeout: 10s
|
|
103
|
+
retries: 3
|
|
104
|
+
start_period: 60s
|
|
105
|
+
|
|
106
|
+
networks:
|
|
107
|
+
- labelstudio
|
|
108
|
+
|
|
109
|
+
volumes:
|
|
110
|
+
postgres_data:
|
|
111
|
+
driver: local
|
|
112
|
+
|
|
113
|
+
labelstudio_data:
|
|
114
|
+
driver: local
|
|
115
|
+
|
|
116
|
+
networks:
|
|
117
|
+
labelstudio:
|
|
118
|
+
driver: bridge
|
|
119
|
+
EOF
|
|
120
|
+
|
|
121
|
+
# 3. 실행
|
|
122
|
+
docker compose up -d
|
|
123
|
+
|
|
124
|
+
# 4. 로그 확인
|
|
125
|
+
docker compose logs -f labelstudio
|
|
126
|
+
|
|
127
|
+
# 5. Admin 사용자 생성 (최초 1회)
|
|
128
|
+
docker compose exec labelstudio python manage.py createsuperuser
|
|
129
|
+
# → Email: admin@hatiolab.io
|
|
130
|
+
# → Username: admin
|
|
131
|
+
# → Password: admin (또는 원하는 패스워드)
|
|
132
|
+
|
|
133
|
+
# 6. API 토큰 발급
|
|
134
|
+
# http://label.hatiolab.localhost:8080 접속
|
|
135
|
+
# Account Settings → Access Token → Create new token
|
|
136
|
+
# 생성된 토큰을 복사 (예: 2c00d45b8318a11f59e04c7233d729f3f17664e8)
|
|
137
|
+
|
|
138
|
+
# 7. .env 파일에 API 토큰 추가 (선택사항)
|
|
139
|
+
cat > .env << 'EOF'
|
|
140
|
+
LABEL_STUDIO_API_TOKEN=2c00d45b8318a11f59e04c7233d729f3f17664e8
|
|
141
|
+
EOF
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 접속 확인
|
|
145
|
+
|
|
146
|
+
- **Label Studio**: http://label.hatiolab.localhost:8080
|
|
147
|
+
- **Health Check**: http://label.hatiolab.localhost:8080/health
|
|
148
|
+
- **PostgreSQL**: localhost:5432
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 🔧 1단계: Things-Factory 설정
|
|
153
|
+
|
|
154
|
+
### 1.1 모듈 빌드
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Things-Factory 프로젝트 디렉토리로 이동
|
|
158
|
+
cd /path/to/things-factory
|
|
159
|
+
|
|
160
|
+
# integration-label-studio 모듈 빌드
|
|
161
|
+
cd packages/integration-label-studio
|
|
162
|
+
yarn build
|
|
163
|
+
|
|
164
|
+
# 루트로 돌아가기
|
|
165
|
+
cd ../..
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### 1.2 설정 파일 작성
|
|
169
|
+
|
|
170
|
+
`config/label-studio.config.js` 파일 생성:
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
module.exports = {
|
|
174
|
+
labelStudio: {
|
|
175
|
+
serverUrl: process.env.LABEL_STUDIO_URL || 'http://localhost:8080',
|
|
176
|
+
apiToken: process.env.LABEL_STUDIO_API_TOKEN || '',
|
|
177
|
+
interfaces: 'panel,controls,annotations:menu' // 표시할 UI 요소
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 1.3 환경 변수 설정
|
|
183
|
+
|
|
184
|
+
`.env` 파일에 추가:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# Label Studio 서버 URL
|
|
188
|
+
LABEL_STUDIO_URL=https://label-studio.example.com
|
|
189
|
+
|
|
190
|
+
# Label Studio API 토큰 (사용자 동기화용)
|
|
191
|
+
LABEL_STUDIO_API_TOKEN=your-api-token-here
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 1.4 Things-Factory 재시작
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
cd /path/to/things-factory
|
|
198
|
+
yarn workspace @things-factory/[APP_NAME] run serve:dev
|
|
199
|
+
# 또는 프로덕션
|
|
200
|
+
yarn workspace @things-factory/[APP_NAME] run serve
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## 📦 2단계: Label Studio SSO 패키지 설치
|
|
206
|
+
|
|
207
|
+
### 2.1 label-studio-sso 패키지 설치
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Label Studio 가상환경 활성화
|
|
211
|
+
source /path/to/label-studio/venv/bin/activate
|
|
212
|
+
|
|
213
|
+
# 패키지 설치
|
|
214
|
+
pip install label-studio-sso
|
|
215
|
+
|
|
216
|
+
# 설치 확인
|
|
217
|
+
pip list | grep label-studio-sso
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 2.2 Label Studio 설정 수정
|
|
221
|
+
|
|
222
|
+
`label_studio/core/settings/base.py` 파일 수정:
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
# INSTALLED_APPS에 추가
|
|
226
|
+
INSTALLED_APPS = [
|
|
227
|
+
'django.contrib.admin',
|
|
228
|
+
'django.contrib.auth',
|
|
229
|
+
'django.contrib.contenttypes',
|
|
230
|
+
'django.contrib.sessions',
|
|
231
|
+
'django.contrib.messages',
|
|
232
|
+
'django.contrib.staticfiles',
|
|
233
|
+
|
|
234
|
+
# ... 기존 앱들 ...
|
|
235
|
+
|
|
236
|
+
'label_studio_sso', # ✅ 추가
|
|
237
|
+
]
|
|
238
|
+
|
|
239
|
+
# AUTHENTICATION_BACKENDS에 추가 (최상단에 배치)
|
|
240
|
+
AUTHENTICATION_BACKENDS = [
|
|
241
|
+
'label_studio_sso.backends.JWTAuthenticationBackend', # ✅ 추가 (최우선)
|
|
242
|
+
'rules.permissions.ObjectPermissionBackend',
|
|
243
|
+
'django.contrib.auth.backends.ModelBackend',
|
|
244
|
+
]
|
|
245
|
+
|
|
246
|
+
# MIDDLEWARE에 추가 (AuthenticationMiddleware 바로 다음)
|
|
247
|
+
MIDDLEWARE = [
|
|
248
|
+
'corsheaders.middleware.CorsMiddleware',
|
|
249
|
+
'django.middleware.security.SecurityMiddleware',
|
|
250
|
+
'django.contrib.sessions.middleware.SessionMiddleware',
|
|
251
|
+
'django.middleware.locale.LocaleMiddleware',
|
|
252
|
+
'core.middleware.DisableCSRF',
|
|
253
|
+
'django.middleware.csrf.CsrfViewMiddleware',
|
|
254
|
+
'core.middleware.XApiKeySupportMiddleware',
|
|
255
|
+
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
|
256
|
+
'label_studio_sso.middleware.JWTAutoLoginMiddleware', # ✅ 추가
|
|
257
|
+
'django.contrib.messages.middleware.MessageMiddleware',
|
|
258
|
+
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
|
259
|
+
# ... 나머지 미들웨어 ...
|
|
260
|
+
]
|
|
261
|
+
|
|
262
|
+
# JWT SSO 설정
|
|
263
|
+
JWT_SSO_SECRET = os.getenv('JWT_SSO_SECRET')
|
|
264
|
+
JWT_SSO_ALGORITHM = 'HS256'
|
|
265
|
+
JWT_SSO_TOKEN_PARAM = 'token'
|
|
266
|
+
JWT_SSO_EMAIL_CLAIM = 'email'
|
|
267
|
+
JWT_SSO_AUTO_CREATE_USERS = False # Things-Factory 사용자 동기화 사용
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### 2.3 Label Studio 재시작
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
# systemd 사용 시
|
|
274
|
+
sudo systemctl restart label-studio
|
|
275
|
+
|
|
276
|
+
# 수동 실행 시
|
|
277
|
+
python label_studio/manage.py runserver 0.0.0.0:8080
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## 👥 3단계: Label Studio API 토큰 생성
|
|
283
|
+
|
|
284
|
+
### 3.1 Label Studio에서 API 토큰 생성
|
|
285
|
+
|
|
286
|
+
1. Label Studio에 로그인
|
|
287
|
+
2. **Account Settings** → **Access Token** 메뉴 이동
|
|
288
|
+
3. **"Create new token"** 클릭
|
|
289
|
+
4. 생성된 토큰 복사 (예: `a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6`)
|
|
290
|
+
|
|
291
|
+
### 3.2 Things-Factory 환경 변수에 추가
|
|
292
|
+
|
|
293
|
+
`.env` 파일의 `LABEL_STUDIO_API_TOKEN`에 복사한 토큰 추가:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
LABEL_STUDIO_API_TOKEN=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## 👥 4단계: 사용자 권한 설정 및 동기화
|
|
302
|
+
|
|
303
|
+
### 4.1 Label Studio 권한 부여
|
|
304
|
+
|
|
305
|
+
Things-Factory에서 사용자에게 `label-studio` 권한을 부여합니다.
|
|
306
|
+
|
|
307
|
+
**Things-Factory Admin UI**:
|
|
308
|
+
|
|
309
|
+
1. Users 메뉴 → 사용자 선택
|
|
310
|
+
2. "Granted Roles" 탭
|
|
311
|
+
3. `label-studio` 권한이 포함된 역할 추가
|
|
312
|
+
|
|
313
|
+
### 4.2 사용자 동기화
|
|
314
|
+
|
|
315
|
+
Things-Factory GraphQL Playground에서 사용자를 Label Studio로 동기화:
|
|
316
|
+
|
|
317
|
+
**전체 사용자 동기화 (관리자용)**:
|
|
318
|
+
|
|
319
|
+
```graphql
|
|
320
|
+
mutation {
|
|
321
|
+
syncAllUsersToLabelStudio {
|
|
322
|
+
total
|
|
323
|
+
created
|
|
324
|
+
updated
|
|
325
|
+
deactivated
|
|
326
|
+
skipped
|
|
327
|
+
errors
|
|
328
|
+
results {
|
|
329
|
+
success
|
|
330
|
+
email
|
|
331
|
+
action
|
|
332
|
+
lsUserId
|
|
333
|
+
lsPermissions
|
|
334
|
+
error
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**현재 사용자만 동기화**:
|
|
341
|
+
|
|
342
|
+
```graphql
|
|
343
|
+
mutation {
|
|
344
|
+
syncMyUserToLabelStudio {
|
|
345
|
+
success
|
|
346
|
+
email
|
|
347
|
+
action
|
|
348
|
+
lsUserId
|
|
349
|
+
lsPermissions
|
|
350
|
+
error
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**예상 출력**:
|
|
356
|
+
|
|
357
|
+
```json
|
|
358
|
+
{
|
|
359
|
+
"data": {
|
|
360
|
+
"syncAllUsersToLabelStudio": {
|
|
361
|
+
"total": 10,
|
|
362
|
+
"created": 5,
|
|
363
|
+
"updated": 3,
|
|
364
|
+
"deactivated": 2,
|
|
365
|
+
"skipped": 0,
|
|
366
|
+
"errors": 0,
|
|
367
|
+
"results": [
|
|
368
|
+
{
|
|
369
|
+
"success": true,
|
|
370
|
+
"email": "user@example.com",
|
|
371
|
+
"action": "created",
|
|
372
|
+
"lsUserId": "123",
|
|
373
|
+
"lsPermissions": "Staff (Labeling only)",
|
|
374
|
+
"error": null
|
|
375
|
+
}
|
|
376
|
+
]
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## ✅ 5단계: 통합 검증
|
|
385
|
+
|
|
386
|
+
### 5.1 Things-Factory에서 접근
|
|
387
|
+
|
|
388
|
+
1. Things-Factory 로그인
|
|
389
|
+
2. 메뉴에서 **"Label Studio"** 클릭
|
|
390
|
+
3. iframe에 Label Studio가 로드되어야 함
|
|
391
|
+
4. **자동으로 로그인되어야 함** (별도 로그인 없이)
|
|
392
|
+
|
|
393
|
+
### 5.2 JWT 토큰 확인
|
|
394
|
+
|
|
395
|
+
**브라우저 개발자 도구**에서 iframe URL 확인:
|
|
396
|
+
|
|
397
|
+
```
|
|
398
|
+
https://label-studio.example.com/?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...&interfaces=panel,controls,annotations:menu
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**localStorage에서 토큰 확인**:
|
|
402
|
+
|
|
403
|
+
```javascript
|
|
404
|
+
// 브라우저 콘솔에서
|
|
405
|
+
localStorage.getItem('access-token')
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### 5.3 Label Studio 로그 확인
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
tail -f /var/log/label-studio/label-studio.log | grep "JWT"
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
**성공 메시지**:
|
|
415
|
+
|
|
416
|
+
```
|
|
417
|
+
INFO: JWT token verified for email: user@example.com
|
|
418
|
+
INFO: User found: user@example.com
|
|
419
|
+
INFO: User auto-logged in: user@example.com
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
**실패 메시지**:
|
|
423
|
+
|
|
424
|
+
```
|
|
425
|
+
ERROR: JWT_SSO_SECRET is not configured
|
|
426
|
+
ERROR: JWT token signature verification failed
|
|
427
|
+
WARNING: User not found in Label Studio: user@example.com
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## 🔍 문제 해결
|
|
433
|
+
|
|
434
|
+
### 문제 1: "JWT token signature verification failed"
|
|
435
|
+
|
|
436
|
+
**원인**: Things-Factory와 Label Studio의 `JWT_SSO_SECRET`이 다름
|
|
437
|
+
|
|
438
|
+
**해결**:
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
# 1. Things-Factory 시크릿 확인
|
|
442
|
+
cd /path/to/things-factory
|
|
443
|
+
cat .env | grep JWT_SSO_SECRET
|
|
444
|
+
|
|
445
|
+
# 2. Label Studio 시크릿 확인
|
|
446
|
+
echo $JWT_SSO_SECRET
|
|
447
|
+
|
|
448
|
+
# 3. 두 값이 동일한지 확인
|
|
449
|
+
# 다르면 둘 중 하나를 수정하고 양쪽 모두 재시작
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### 문제 2: iframe에 "Refused to connect" 에러
|
|
453
|
+
|
|
454
|
+
**원인**: Label Studio의 X-Frame-Options 설정
|
|
455
|
+
|
|
456
|
+
**해결**:
|
|
457
|
+
|
|
458
|
+
```python
|
|
459
|
+
# Label Studio settings.py
|
|
460
|
+
X_FRAME_OPTIONS = 'ALLOWALL' # 또는 특정 도메인 허용
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### 문제 3: 사용자가 Label Studio에 없음
|
|
464
|
+
|
|
465
|
+
**원인**: 사용자 동기화가 안됨
|
|
466
|
+
|
|
467
|
+
**해결**:
|
|
468
|
+
|
|
469
|
+
```graphql
|
|
470
|
+
# Things-Factory GraphQL
|
|
471
|
+
mutation {
|
|
472
|
+
syncMyUserToLabelStudio {
|
|
473
|
+
success
|
|
474
|
+
email
|
|
475
|
+
action
|
|
476
|
+
lsUserId
|
|
477
|
+
error
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
또는 Label Studio에서 수동 생성:
|
|
483
|
+
|
|
484
|
+
```bash
|
|
485
|
+
cd /path/to/label-studio
|
|
486
|
+
python manage.py createsuperuser --email user@example.com
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### 문제 4: HTTPS에서만 작동
|
|
490
|
+
|
|
491
|
+
**원인**: JWT 토큰이 URL에 포함되므로 보안상 HTTPS 필요
|
|
492
|
+
|
|
493
|
+
**해결**:
|
|
494
|
+
|
|
495
|
+
- 개발: `http://localhost` 사용 (로컬호스트는 예외)
|
|
496
|
+
- 프로덕션: 반드시 HTTPS 사용
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## 📊 설정 확인 체크리스트
|
|
501
|
+
|
|
502
|
+
### Things-Factory
|
|
503
|
+
|
|
504
|
+
```bash
|
|
505
|
+
# 1. 환경 변수 확인
|
|
506
|
+
cat .env | grep LABEL_STUDIO
|
|
507
|
+
|
|
508
|
+
# 2. 모듈 빌드 확인
|
|
509
|
+
ls -la packages/integration-label-studio/dist-server/
|
|
510
|
+
ls -la packages/integration-label-studio/dist-client/
|
|
511
|
+
|
|
512
|
+
# 3. 설정 파일 확인
|
|
513
|
+
cat config/label-studio.config.js
|
|
514
|
+
|
|
515
|
+
# 4. 서버 재시작
|
|
516
|
+
yarn workspace @things-factory/[APP_NAME] run serve:dev
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### Label Studio
|
|
520
|
+
|
|
521
|
+
```bash
|
|
522
|
+
# 1. 패키지 설치 확인
|
|
523
|
+
pip list | grep label-studio-sso
|
|
524
|
+
|
|
525
|
+
# 2. 환경 변수 확인
|
|
526
|
+
echo $JWT_SSO_SECRET
|
|
527
|
+
|
|
528
|
+
# 3. 설정 파일 확인
|
|
529
|
+
grep -A 5 "label_studio_sso" label_studio/core/settings/base.py
|
|
530
|
+
|
|
531
|
+
# 4. 서버 재시작
|
|
532
|
+
sudo systemctl restart label-studio
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
537
|
+
## 🔐 보안 고려사항
|
|
538
|
+
|
|
539
|
+
### 1. JWT 시크릿 보안
|
|
540
|
+
|
|
541
|
+
- **절대 Git에 커밋하지 마세요**
|
|
542
|
+
- `.gitignore`에 `.env` 추가
|
|
543
|
+
- 프로덕션에서는 환경 변수 또는 비밀 관리 도구 사용
|
|
544
|
+
|
|
545
|
+
### 2. HTTPS 필수
|
|
546
|
+
|
|
547
|
+
- 프로덕션에서는 반드시 HTTPS 사용
|
|
548
|
+
- JWT 토큰이 URL에 포함되므로 중간자 공격 방지 필요
|
|
549
|
+
|
|
550
|
+
### 3. 토큰 유효 기간
|
|
551
|
+
|
|
552
|
+
- Things-Factory JWT 토큰 유효 기간: 5-10분 권장
|
|
553
|
+
- 만료 후 재로그인 필요
|
|
554
|
+
|
|
555
|
+
### 4. CORS 설정
|
|
556
|
+
|
|
557
|
+
```python
|
|
558
|
+
# Label Studio settings.py
|
|
559
|
+
CORS_ALLOWED_ORIGINS = [
|
|
560
|
+
'https://things-factory.example.com',
|
|
561
|
+
]
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
566
|
+
## 📚 추가 문서
|
|
567
|
+
|
|
568
|
+
- [README.md](./README.md) - 모듈 개요
|
|
569
|
+
- [USER_SYNC_GUIDE.md](./USER_SYNC_GUIDE.md) - 사용자 동기화 가이드
|
|
570
|
+
- [label-studio-sso README](https://github.com/hatiolab/label-studio-sso) - SSO 패키지 문서
|
|
571
|
+
- [label-studio-sso CONFIGURATION](https://github.com/hatiolab/label-studio-sso/blob/main/CONFIGURATION.md) - 상세 설정
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
**문서 버전**: 1.0
|
|
576
|
+
**작성일**: 2025-10-02
|
|
577
|
+
**최종 업데이트**: 2025-10-02
|