티스토리 뷰

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 재실행.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday