본문으로 건너뛰기

Dataset (학습 데이터셋)

LLM/VLM 파인튜닝용 학습 데이터셋을 관리하는 API입니다 (Epic #2527). 데이터셋은 워크스페이스 격리 하에 Iceberg 테이블(iceberg.ws_<슬러그>.ds_* — 워크스페이스 스키마)로 저장되며, 버전은 Iceberg snapshot ID 고정 방식입니다 — 설계 배경은 ADR-0027 참조. prefix: /api/v1/datasets.

  • modality: image / image_text / text / video (v1.2+) — audio 는 스키마 예약
  • UI 가이드: 학습 데이터셋 (/datasets)

데이터셋 CRUD

MethodPath권한요청/응답 요지
POST/api/v1/datasetsanalyst생성 (201) — body: name/description/modality. PG 카탈로그 행 + Iceberg 테이블 DDL + 생성자에게 table-scope DataGrant 자동 발급. 이름 중복 409
GET/api/v1/datasetsviewer목록 — limit(≤500)/offset, 워크스페이스 가시성 적용. items[]/total
GET/api/v1/datasets/{dataset_id}viewer단건 상세. 교차 워크스페이스 접근은 404 (IDOR-safe)
DELETE/api/v1/datasets/{dataset_id}analyst동기 DROP + partial failure 표면화 — deleted/target_dropped/drop_error. DROP 실패 시 행은 status='deleting' 으로 보존되며 동일 DELETE 재호출로 재시도

적재 (파일 / JSONL)

MethodPath권한요청/응답 요지
POST/api/v1/datasets/{dataset_id}/files?split=&label=analyst이미지·비디오 다중 업로드 (split/label 은 image·video 공통 기본값 — zip 폴더/metadata.jsonl 이 우선, v1.2+) (multipart/form-data, image·video modality — zip 은 image 전용, video 는 .mp4/.webm 개별 파일 단건 ≤100MB, v1.2+) → S3 + Iceberg 적재. 응답: accepted[]/duplicates[]/rejected[]/rows_added/resulting_snapshot_id
POST/api/v1/datasets/{dataset_id}/jsonlanalystJSONL 승격 (text modality 전용, .jsonl/.ndjson). 쿼리: dry_run(쓰기 없는 미리보기) / mask_pii(PII 마스킹 적재) / split(레코드에 값이 없을 때의 기본값, v1.2+). 지원 키: text/messages/prompt+response(별칭 completion, v1.2+)/chosen+rejected. 응답: subformat(plain/messages/prompt_response/dpo)/rows_added/raw_uri(Bronze 원본 보존)/resulting_snapshot_id
POST/api/v1/datasets/{dataset_id}/uploadsanalyst청크 업로드 세션 개시 (v1.2+, ADR-0042) — body: filename(.parquet)/declared_bytes/declared_sha256. 쿼터 선판정 413·상한 기본 5GB
PUT/api/v1/datasets/{dataset_id}/uploads/{session_id}/parts/{n}analystpart 릴레이 (raw body ≤45MB, 순차) — 선언 초과 413
POST/api/v1/datasets/{dataset_id}/uploads/{session_id}/completeanalystMPU 조립 + sha256 재해시 검증 + parquet 승격 (불일치 409)
DELETE/api/v1/datasets/{dataset_id}/uploads/{session_id}analyst세션 중단 (204) — 만료 세션은 GC 가 24h TTL 로 정리
GET/api/v1/datasets/{dataset_id}/statsviewer통계 — row_count/split_stats/label_stats

resulting_snapshot_id 는 이번 적재가 만든 Iceberg snapshot 의 10진 문자열입니다 (JS Number 정밀도 보호). 버전 고정 시 이 값을 그대로 사용합니다.

행 조회 / 삭제

MethodPath권한요청/응답 요지
GET/api/v1/datasets/{dataset_id}/rowsviewer행 조회 — keyset pagination (limit/after/split/label). 응답: columns/items/next_cursor
GET/api/v1/datasets/{dataset_id}/versions/{version}/rowsviewer버전 고정 행 조회 — FOR VERSION AS OF snapshot 재현
GET/api/v1/datasets/{dataset_id}/blob/{content_hash}viewer이미지·비디오 바이트 프록시 (`variant=original
DELETE/api/v1/datasets/{dataset_id}/rowsanalyst행 삭제 — body: record_ids[] (1~1000). PII 삭제권/오염 데이터 제거. 응답: requested/resulting_snapshot_id

버전 (snapshot 고정)

MethodPath권한요청/응답 요지
POST/api/v1/datasets/{dataset_id}/versionsanalyst버전 생성 (201) — body: snapshot_id(적재 응답의 resulting_snapshot_id)/note/pii_masked. snapshot 시점 row_count/split_stats 실측 기록. 무효 snapshot 은 422
GET/api/v1/datasets/{dataset_id}/versionsviewer버전 목록 (최신 우선)

Export (Gold 산출)

MethodPath권한요청/응답 요지
POST/api/v1/datasets/{dataset_id}/exportsanalyst버전 고정 JSONL export 요청 (202) — body: version. 백그라운드 실행 후 상태 폴링. 응답의 dataset_version_uri(gend://datasets/{id}/versions/{v}) 를 학습 잡이 MLflow run tag gend.dataset_version 으로 기록하면 dataset→model 계보가 남습니다
GET/api/v1/datasets/{dataset_id}/exportsviewerexport 목록
GET/api/v1/datasets/{dataset_id}/exports/{export_id}viewerexport 상태/결과 — status/export_uri/row_count/error_message
GET/api/v1/datasets/{dataset_id}/exports/{export_id}/downloadviewerexport 산출물 바이트 프록시 (v1.2+) — 인가 후 스트리밍, S3 비노출. ?part=N(총수 X-Export-Part-Count 헤더)·Range 단일 범위(206/416)·미완료 export 409

사용량 · 스토리지 쿼터 (v1.2+)

워크스페이스 단위 스토리지 쿼터(#2989 M0). 사용량은 적재 원장(bytes_added) 합계 — files 는 실제 저장된 blob+썸네일 바이트, JSONL/Parquet 는 Bronze 원본 바이트 기준입니다.

MethodPath권한요청/응답 요지
GET/api/v1/datasets/usageviewer활성 워크스페이스 사용량 — used_bytes/soft_limit_bytes/hard_limit_bytes(0=무제한)/remaining_bytes(무제한이면 null)/soft_exceeded/hard_exceeded/per_user[](created_by 별 breakdown)
POST/api/v1/datasets/quota-increaseanalyst쿼터 증설 승인 신청 (201) — body: soft_limit_bytes/hard_limit_bytes(절대값)/reason. 같은 ws 대기 중 신청 존재 시 409. 승인은 POST /api/v1/approvals/{id}/decide (admin) — 승인 시 쿼터 자동 upsert
GET/api/v1/admin/dataset-quotasadmin전체 워크스페이스 쿼터 매트릭스
PUT/api/v1/admin/dataset-quotas/{workspace_id}admin쿼터 upsert — body: soft_limit_bytes/hard_limit_bytes (0=무제한, 둘 다 >0 이면 soft≤hard 강제)
DELETE/api/v1/admin/dataset-quotas/{workspace_id}admin쿼터 해제 (204) — 이후 GEND_DATASET_DEFAULT_QUOTA_BYTES 기본값 적용 (기본 0=무제한)
  • hard 초과: 업로드(/files·/jsonl)가 413 으로 거부됩니다 — detail 에 "쿼터" 문구가 있어 파일 크기 상한 413 과 구분됩니다.
  • soft 초과: 업로드는 수행되고 응답의 quota_warning 필드에 경고가 실립니다.
  • dry_run=true JSONL 미리보기는 쓰기가 없어 쿼터 판정을 하지 않습니다.
  • 운영 절차는 스토리지 쿼터 관리 참조.

인증 · 권한

JWT Bearer 토큰이 필요합니다. 조회는 viewer, 생성/적재/삭제/버전/export 는 analyst 이상이 필요합니다. 모든 경로에 워크스페이스 격리(scope)가 적용되며, 다른 워크스페이스의 데이터셋 ID 로 접근하면 존재 여부를 노출하지 않고 404 를 반환합니다.

에러 코드

코드설명
400잘못된 입력 — modality 불일치, 파일 수 초과, 잘못된 content_hash/variant, 행 삭제 검증 실패
403워크스페이스에 해당 네임스페이스의 write 바인딩이 없음(v1.2+) — 데이터셋 생성·적재·행 삭제·데이터셋 삭제에 적용됩니다. 정리 경로(청크 세션 abort)는 예외입니다. 관리자에게 바인딩 발급을 요청하세요
404데이터셋/버전/blob/export 없음 (교차 워크스페이스 포함)
409같은 이름의 데이터셋 존재, 삭제 진행 중(deleting) 데이터셋에 쓰기, 또는 미완료 export 다운로드
413파일/요청 합산 크기 상한 초과, 또는 워크스페이스 스토리지 쿼터(hard) 초과 (v1.2+ — detail 의 "쿼터" 문구로 구분)
416Range 불만족 — blob·export download (Content-Range: bytes */N 반환)
422JSONL 파싱 실패, 무효 snapshot_id, 무효 split/label(공백·제어문자·64자 초과, v1.2+)
502Trino/Iceberg 적재·조회 실패
503워크스페이스 해석 불가 (기본 테넌트 부재)