티스토리 뷰
1. 개요
| 목적 | Jira의 프로젝트·이슈·스프린트·댓글·첨부파일·사용자 데이터를 CIRA DB로 일회성 이관하여, CIRA에서 기존 Jira 이력과 구조를 그대로 활용할 수 있게 함. |
| 스크립트 | scripts/jira-migrate.ts |
| 실행 환경 | Node + Prisma + tsx. .env에 CIRA DB 연결 정보와 Jira API 설정 필요. |
2. 마이그레이션 단계 (1~7) — 무엇을 어떻게 옮기는지
2.1 1단계: 사용자 (Users)
- Jira API: /api/3/users/search 페이지네이션으로 전체 사용자 조회.
- 처리: accountType === "atlassian" 인 사용자만 대상.
- 이메일:
- Jira에서 emailAddress가 있으면 그대로 사용.
- 없으면 placeholder 이메일 jira-{accountId}@migrated.local 로 CIRA 사용자 생성 (아래 “이슈·조치” 참고).
- 비밀번호: 공통 임시 비밀번호 ChangeMe1234! (bcrypt 해시) 부여. 첫 로그인 후 변경 안내 필요.
- 매핑: Jira accountId → CIRA user.id 를 userMap에 저장. 이후 담당자·리포터·댓글 작성자 매핑에 사용.
2.2 2단계: 조직 (Organization)
- 지정한 조직명·slug(JIRA_ORG_NAME, JIRA_ORG_SLUG, 기본값 "Jira Import" / "jira-import")로 CIRA 조직 1개 생성.
- 1단계에서 마이그레이션된 모든 사용자를 해당 조직 멤버(orgMember, role: MEMBER)로 추가.
2.3 3단계: 프로젝트 (Projects)
- Jira API: /api/3/project 로 프로젝트 목록 조회.
- CIRA: 조직 하위에 프로젝트 생성 (name, key, description).
동일 orgId + key 가 있으면 재사용하고, projectMap(Jira project id/key → CIRA project id) 갱신.
2.4 4단계: 스프린트 (Sprints)
- Jira API: /agile/1.0/board → 보드별 /agile/1.0/board/{boardId}/sprint 로 스프린트 조회 (Jira Software 사용 시).
- CIRA: 프로젝트별로 스프린트 생성 (name, goal, startDate, endDate, state → PLANNING/ACTIVE/COMPLETED).
- 매핑: Jira 스프린트 id → CIRA sprint id 를 sprintMap에 저장. 5단계 이슈에서 스프린트 연결에 사용.
2.5 5단계: 이슈 (Issues)
- 조회: 프로젝트별로 JQL project={key} ORDER BY created ASC 로 이슈 검색.
nextPageToken 기반 API(/api/3/search/jql) 사용, 0건이면 레거시 startAt API로 재시도.
- 필드 매핑:
- 제목(summary), 설명(description), 타입(issuetype → EPIC/STORY/TASK/BUG), 상태(status), 우선순위(priority),
- 스토리 포인트(customfield_10031 등), dueDate, reporter/assignee(accountId → userMap).
- 설명(description):
- renderedFields.description(HTML) 우선 사용, 없으면 이슈 상세 API로 HTML 조회.
- HTML 내 Jira 이미지 경로는 Jira 도메인 기준 절대 URL로 변환.
- HTML 없으면 ADF(Atlassian Document Format) → plain text 변환.
- 스프린트:
- 이슈의 customfield_10020(스프린트 배열)에서 active 우선, 없으면 completeDate 최신 1개 선택.
- 해당 스프린트의 name을 CIRA 이슈의 jiraSprintName에 저장하고, sprintMap으로 sprintId 연결.
- 보드/백로그는 이 jiraSprintName과 스프린트 name 매칭으로 동작 (HANDOVER 12.4절).
- 부모-자식:
- 서브태스크: JQL로 Sub-task 조회 후 parent.key → CIRA 이슈 parentId 연결.
- 에픽-스토리: Epic Link로 연결된 이슈들을 조회해 동일하게 parentId 연결.
- 레이블: 이슈의 labels를 CIRA label + issueLabel로 생성·연결.
- 실행 시: 같은 CIRA 프로젝트에 기존 이슈가 있으면 해당 프로젝트 이슈 전부 삭제 후 해당 프로젝트 이슈만 재수입(댓글/첨부 등은 cascade 삭제).
2.6 6단계: 댓글 (Comments)
- Jira API: 이슈별로 /api/3/issue/{key}?fields=comment&expand=renderedFields 로 댓글 + 렌더된 HTML 조회.
- 정렬: created 기준 오름차순. 부모 댓글 먼저 생성한 뒤 parentId로 대댓글 연결 (Jira의 parent/parentId → CIRA comment.parentId).
- 본문: 렌더된 HTML 있으면 사용(이미지 URL 보정), 없으면 ADF → plain text.
- 작성자: author.accountId → userMap. 매핑 실패 시 fallback으로 userMap의 첫 사용자 사용.
2.7 7단계: 첨부파일 (Attachments)
- Jira API: 이슈별 fields.attachment 조회.
- CIRA: 파일 바이너리는 이관하지 않고, 메타데이터만 저장 (name, content URL, size, mimeType, createdAt).
실제 파일은 Jira URL 참조용으로만 사용.
3. 실행 방법
3.1 사전 준비
- 환경 변수 (.env 예시):
- DATABASE_URL: CIRA DB 연결 문자열
- JIRA_DOMAIN: 예) yourcompany.atlassian.net
- JIRA_EMAIL: Jira API 사용 계정 이메일
- JIRA_API_TOKEN: Atlassian API 토큰
- (선택) JIRA_ORG_NAME, JIRA_ORG_SLUG: CIRA 조직 이름·slug
- DB 스키마:
Prisma 스키마가 대상 DB에 반영되어 있어야 함.Issue.jiraSprintName, Comment.parentId 등 마이그레이션에 필요한 컬럼이 포함된 migration이 적용되어 있어야 함.
- 권장:
공용/운영 DB면 실행 전 백업 또는 테스트 DB에서 1회 실행 후 본 DB 적용.
3.2 명령어
- 스크립트는 1→2→3→4→5→6→7 순서로 실행되며, 콘솔에 단계별 로그 출력.
- 마이그레이션된 사용자 임시 비밀번호: ChangeMe1234! (스크립트 내 TEMP_PASSWORD).
placeholder 이메일(jira-*@migrated.local)로 생성된 사용자는 실제 사용 전 DB에서 이메일 수동 수정 필요.
4. 마이그레이션 중 발생한 이슈 및 조치 (동료 정리 반영)
4.1 사용자 1명만 마이그레이션되는 현상
- 증상: 스크립트 실행 시 CIRA 사용자가 1명만 생성됨.
- 원인:
코드에서 emailAddress가 있을 때만 사용자를 insert 하도록 되어 있었고,Jira API는 프로필/프라이버시 설정에 따라 emailAddress를 비워서 내려주는 경우가 많음.그래서 이메일이 있는 사용자 1명만 CIRA에 생성됨.
- 조치:
emailAddress가 비어 있으면 placeholder 이메일 jira-{accountId}@migrated.local 로 CIRA 사용자 생성하도록 수정.해당 사용자들은 실제 서비스 사용 전 DBeaver 등으로 이메일을 실제 Jira/회사 이메일로 수동 수정하고, 팀 정책에 따라 테스트 시 일부만 수정해 사용하기로 함 (동료 댓글 내용 반영).
4.2 로컬 DB 마이그레이션 시 jiraSprintName 누락 오류
- 증상: 로컬 DB에서 마이그레이션 테스트 중 jiraSprintName 관련 오류 발생.
- 원인:
Prisma migration 파일에 issues.jiraSprintName 컬럼 정의가 누락되어 있었음.(댓글 대댓글용 comments.parentId 등도 같은 migration에 포함.)
- 조치:
누락된 컬럼을 migration 파일에 추가하고 migration 재정비 완료.(prisma/migrations/20260225071216_add_issue_jira_sprint_name/migration.sql 에 issues.jiraSprintName, comments.parentId 등 반영.)
4.3 깨끗한 상태에서 재마이그레이션하는 방법
- 방법:
Jira 데이터를 처음부터 다시 넣고 싶을 때는npx prisma migrate reset 실행 후 위 3.2 순서대로 스키마 적용 및 npx tsx scripts/jira-migrate.ts 실행.
- 주의:
migrate reset은 DB를 초기화하므로, 사용 중인 DB면 반드시 확인 후 실행.
5. 참고 사항
- 재실행:
같은 조직/프로젝트에 스크립트를 여러 번 돌리면 이슈는 “삭제 후 재생성”되지만, 사용자·조직·프로젝트·스프린트는 재사용/중복 가능. 일회성 설계이므로 재실행 시 데이터 정책과 코드 확인 후 진행할 것.
- 스프린트 노출:
이슈의 jiraSprintName과 CIRA 스프린트 name 매칭으로 보드/백로그가 동작함. 상세는 docs/HANDOVER.md 12.4절 참고.
- 트러블슈팅:
- 댓글 작성자 매핑 실패: 스크립트 내 userMap/fallback 처리 확인.
- Prisma generate 오류: npx prisma generate 재실행.
'[WEB]' 카테고리의 다른 글
| [OpenAI/Cloudflare R2/Vite]네이버 블로그 자동 발행 크롬 익스텐션 개발기 (0) | 2026.05.07 |
|---|---|
| Prisma란? 기존 MySQL과의 차이, 마이그레이션까지 정리 (0) | 2026.03.10 |
| Prisma의 네이티브 Query Engine 구조가 Alpine 환경에서 야기한 런타임 멈춤 이슈 정리 (0) | 2026.02.25 |
| Next.js 프로젝트에서 Docker·Prisma·DB가 어떻게 연결되는지 (0) | 2026.02.11 |
| Next.js 프로젝트 AWS 배포 시 고민한 것들 – App Runner, ECS, Lambda, EKS (0) | 2026.02.11 |
- Total
- Today
- Yesterday