본문으로 건너뛰기
중급약 28분

Jira 실전 ②: JQL과 저장된 필터로 원하는 것만 꺼내기

수천 건의 업무 항목에서 지금 필요한 것만 뽑아내는 언어를 익힌다. 기본 문법부터 이력 검색(WAS·CHANGED), 그리고 QA가 매일 쓰는 쿼리 12선까지.

  • #Jira
  • #JQL
  • #필터
  • #검색
  • #결함관리

개념

검색을 못 하면 도구를 쓰는 게 아니다

업무 항목이 200건일 때는 눈으로 훑어도 된다. 2,000건이 되면 불가능해진다. 그리고 실무 프로젝트는 1년이면 그 규모가 된다.

QA에게 검색은 편의 기능이 아니라 일의 시작점 이다. 하루를 시작할 때 필요한 질문들을 떠올려보자.

  • 내가 검증해야 하는데 아직 안 본 것은?
  • 어제 배포에 들어간 수정 중 검증이 안 끝난 것은?
  • 한 번 고쳤다가 다시 열린 결함은?
  • 두 달째 아무도 손대지 않은 결함은?

이 질문들에 매번 손으로 답하면 하루가 간다. JQL로 한 번 써두면 클릭 한 번이 된다. 이 레슨이 다루는 것이 그 전환이다.

JQL의 기본 구조

JQL(Jira Query Language) 은 업무 항목을 검색하는 질의 언어다. 기본 형태는 단순하다.

field  operator  value
  • field — 검색할 필드 (assignee, status, priority, project…)
  • operator — 비교 연산자 (=, !=, ~, IN, IS, >, <…)
  • value — 값 (사용자명, 상태, 날짜…)

조건을 AND·OR·NOT 으로 엮고 괄호로 묶는다.

project = "SHOP" AND issuetype = Bug AND status = "In Progress"
  AND priority IN ("Highest", "High")

앞 레슨에서 본 대로 JQL은 여전히 issue·issuetype 을 쓴다. 화면 용어가 '업무 항목'으로 바뀌어도 쿼리는 그대로다.

검색 화면에는 기본 검색(드롭다운으로 조건 선택)과 JQL 모드가 있다. 기본 검색으로 시작해 JQL로 전환하면 문법을 빠르게 익힐 수 있다 — 드롭다운으로 조건을 고른 뒤 JQL 모드로 바꾸면 같은 조건이 문장으로 보인다.

연산자 — 자주 쓰는 것부터

연산자의미예
=정확히 일치status = "To Do"
!=일치하지 않음priority != Low
~텍스트 부분 일치summary ~ "결제"
!~부분 일치하지 않음description !~ "deprecated"
IN여러 값 중 하나priority IN (Highest, High)
NOT IN여러 값 중 어느 것도 아님status NOT IN (Done, Closed)
IS / IS NOT비어 있는지assignee IS EMPTY
> < >= <=크기·날짜 비교created >= "2026-08-01"

~ 는 텍스트 검색이라 완전 일치가 아니다. 그래서 summary ~ "로그인" 은 "로그인 실패", "소셜 로그인 오류"를 모두 잡는다. 넓게 훑을 때 쓰고, 정확히 세야 하는 집계에는 쓰지 않는다.

IS EMPTY 는 QA에게 특히 유용하다. 비어 있으면 안 되는 필드가 비어 있는 것을 찾는 용도 이기 때문이다. 담당자 없는 결함, 픽스 버전 없이 닫힌 결함처럼.

함수 — 날짜와 사용자를 손으로 쓰지 않기

함수의미
currentUser()지금 로그인한 사용자
now()현재 시각
startOfDay() / endOfDay()오늘의 시작·끝
startOfWeek() / startOfMonth()이번 주·이번 달의 시작

인자를 넣어 상대 시점을 만들 수 있다 — startOfDay(-7) 은 7일 전 0시다.

currentUser() 를 쓰는 습관이 중요하다. 필터에 자기 계정 이름을 하드코딩하면 그 필터는 나만 쓸 수 있고, 팀에 공유하는 순간 무용지물이 된다. assignee = currentUser() 로 써두면 한 벌의 필터를 팀 전체가 각자의 것으로 쓴다.

이력 검색 — QA에게 가장 값진 기능

여기가 이 레슨의 핵심이다. 대부분의 사람은 현재 상태 만 검색한다. 그런데 QA의 질문은 종종 과거 를 향한다.

연산자무엇을 찾는가
WAS과거에 그 값이었던 적이 있는 항목
WAS NOT과거에 그 값이 아니었던 항목
WAS IN과거에 목록 중 하나였던 항목
CHANGED값이 변경된 이력이 있는 항목

CHANGED 에는 세부 조건을 붙일 수 있다.

status CHANGED FROM "Done" TO "Reopened" AFTER startOfMonth()
status CHANGED TO "In Progress" BY currentUser() DURING ("2026-09-01", "2026-09-05")

왜 이게 QA에게 결정적인가. 모듈 6(레슨 5)에서 배운 품질 지표 중 여럿이 이력 없이는 계산되지 않기 때문이다.

  • 재오픈율 — "Done이었다가 다시 열린 것"은 현재 상태만으로 알 수 없다
  • 결함 탈출률 — "릴리즈 이후에 발견됐는가"는 생성 시점과 릴리즈 시점의 관계다
  • 핑퐁 결함 — 개발과 QA 사이를 여러 번 오간 항목은 프로세스 문제의 신호다
  • 조용히 닫힌 결함 — 검증 상태를 거치지 않고 Done으로 간 항목

마지막 항목은 특히 중요하다. status WAS NOT "In QA" AND status = Done 같은 쿼리 하나로 검증 없이 종료된 결함 을 찾아낼 수 있다. 이건 프로세스 감사이고, 대개 결과가 놀랍다.

QA가 매일 쓰는 JQL 12선

바로 복사해 쓸 수 있는 형태로 정리한다. 프로젝트 키와 상태 이름은 조직에 맞게 바꿔야 한다.

일상 업무

-- 1. 내가 검증해야 할 것
project = SHOP AND status = "Ready for QA" AND assignee = currentUser()
ORDER BY priority DESC, updated ASC
 
-- 2. 내가 등록한 결함 중 아직 안 닫힌 것
project = SHOP AND reporter = currentUser() AND status NOT IN (Done, Closed)
 
-- 3. 오늘 상태가 바뀐 것 (데일리 스크럼 준비용)
project = SHOP AND status CHANGED AFTER startOfDay()
 
-- 4. 이번 스프린트에서 열린 결함
project = SHOP AND issuetype = Bug AND sprint IN openSprints()

품질 감시

-- 5. 재오픈된 결함 (프로세스 문제의 신호)
project = SHOP AND issuetype = Bug
  AND status CHANGED FROM "Done" TO "Reopened" AFTER startOfMonth(-1)
 
-- 6. 검증 단계를 건너뛰고 닫힌 결함
project = SHOP AND issuetype = Bug AND status = Done
  AND status WAS NOT "In QA"
 
-- 7. 2개월 이상 방치된 결함
project = SHOP AND issuetype = Bug AND status NOT IN (Done, Closed)
  AND updated <= -60d ORDER BY created ASC
 
-- 8. 담당자 없는 높은 우선순위 결함
project = SHOP AND issuetype = Bug AND priority IN (Highest, High)
  AND assignee IS EMPTY

릴리즈·리포트

-- 9. 이번 릴리즈 범위 (픽스 버전 기준)
project = SHOP AND fixVersion = "v2.4.0"
 
-- 10. 릴리즈 이후 발견된 결함 (결함 탈출 후보)
project = SHOP AND issuetype = Bug AND created >= "2026-09-01"
  AND affectedVersion = "v2.4.0"
 
-- 11. 특정 기능 영역의 결함 (결함 밀도 계산용)
project = SHOP AND issuetype = Bug AND component = "결제"
  AND created >= startOfMonth(-3)
 
-- 12. 특정 에픽 아래 전부 (범위 확인용)
"Epic Link" = SHOP-41 OR parent = SHOP-41

12번은 Jira 버전·플랜에 따라 필드 이름이 다르다(parent, "Epic Link", portfolioChildIssuesOf() 등). 자동완성이 제안하는 필드명을 쓰는 것이 가장 확실하다 — 필드명을 입력하고 스페이스를 누르면 사용 가능한 연산자와 값이 뜬다.

필터로 저장하고 공유하기

쿼리를 매번 다시 쓰는 것은 낭비다. 검색 결과 화면에서 필터 저장 을 하면 이름·설명·권한을 지정해 보관할 수 있다.

저장할 때 신경 쓸 것이 권한 이다.

설정결과
조회자(Viewers)누가 이 필터를 볼 수 있는가
편집자(Editors)누가 이 필터를 수정할 수 있는가

필터를 공유하지 않으면 대시보드에서도 안 보인다. 다음 레슨에서 대시보드를 만들 때 "가젯에서 내 필터가 안 보인다"는 문제를 자주 겪는데, 원인의 대부분이 공유 설정이다. 팀 대시보드에 쓸 필터는 팀 또는 프로젝트 단위로 공유 해두는 것이 기본이다.

이름 짓기에도 규칙을 두면 좋다. 필터가 30개를 넘어가면 목록에서 찾기가 어려워진다. [QA] 재오픈 결함 - 월간 처럼 용도 접두어 + 대상 + 주기 형식이 실무에서 잘 작동한다.

필터는 여러 곳의 재료가 된다

저장된 필터는 검색에만 쓰이지 않는다. 이게 JQL을 배울 가치의 절반이다.

              저장된 필터 (JQL)
                     │
    ┌────────────┬───┴────┬──────────────┐
    ▼            ▼        ▼              ▼
  대시보드      보드       자동화 규칙     구독(이메일)
  가젯의 원천   필터 조건   트리거 조건    정기 리포트
  • 대시보드 가젯 — 다음 레슨의 주제. 대부분의 가젯이 필터를 입력으로 받는다
  • 보드 — 보드에 어떤 항목을 표시할지가 JQL로 정의된다
  • 자동화 규칙 — "이 조건에 맞는 항목이 생기면 담당자에게 알림" 같은 규칙
  • 구독 — 필터 결과를 정해진 주기로 메일 발송

즉 JQL 한 줄을 잘 써두면 그것이 대시보드가 되고 알림이 되고 리포트가 된다. QA가 "매주 월요일에 방치된 결함 목록을 팀에 공유"하는 일을 수작업으로 하고 있다면, 그건 필터 하나와 구독 설정으로 끝나는 일이다.

함정 몇 가지

1) 상태·필드 이름은 조직마다 다르다. status = "In QA" 는 그 상태가 있는 프로젝트에서만 동작한다. 남의 블로그에서 가져온 JQL이 안 되는 이유의 대부분이 이것이다. 자동완성으로 실제 값을 확인한다.

2) 하드코딩된 사용자·날짜. assignee = "kim.qa" 나 created >= "2026-09-01" 은 그 순간에만 맞다. currentUser() 와 상대 날짜(-7d, startOfMonth())를 쓴다.

3) ~ 로 집계하지 않는다. 부분 일치는 의도치 않은 항목을 포함한다. 지표 계산에는 컴포넌트·레이블 같은 구조화된 필드 를 쓴다. 이건 모듈 6 레슨 5의 결함 밀도 계산이 정확해지려면 반드시 필요한 습관이다.

4) 삭제된 필터가 대시보드를 깨뜨린다. 공유된 필터를 지우면 그것을 쓰는 가젯과 보드가 함께 죽는다. 정리할 때는 참조하는 곳이 있는지 먼저 확인한다.

실무에서 왜 필요한가

JQL을 쓸 줄 아는 QA와 못 쓰는 QA는 회의에서 다른 말을 한다. "결함이 좀 쌓인 것 같습니다"와 "결제 컴포넌트에 60일 이상 방치된 High 이상 결함이 14건이고, 그중 5건은 담당자가 없습니다"의 차이다. 후자는 반박이 아니라 대응을 부른다.

그리고 이 능력은 품질 지표를 실제로 굴리는 유일한 방법 이기도 하다. 모듈 6 레슨 5에서 배운 결함 밀도·탈출률·재오픈율은 개념만으로는 아무것도 아니다. 매달 같은 기준으로 숫자를 뽑을 수 있어야 추세가 되고, 그 추세가 있어야 개선을 말할 수 있다. JQL이 그 뽑아내는 도구다.

한 가지 더. JQL은 프로세스 감사 도구다. "검증 없이 닫힌 결함", "핑퐁이 3회 이상인 결함" 같은 쿼리는 팀의 프로세스가 실제로 지켜지고 있는지를 드러낸다. 이런 것을 조용히 확인하고 데이터로 제시할 수 있는 사람은 QA밖에 없다.

실습 과제

과제 1 — 기본 검색을 JQL로 옮기기 (12분)

Jira 검색 화면에서 기본 검색(드롭다운) 으로 아래 조건을 만든 뒤, JQL 모드로 전환해 생성된 쿼리를 적는다.

  1. 우리 프로젝트의 Bug 중 아직 완료되지 않은 것
  2. 그중 우선순위가 High 이상인 것
  3. 그중 최근 30일 안에 갱신된 것

각 단계에서 결과 건수도 함께 기록한다. 조건이 하나 늘 때마다 건수가 어떻게 줄어드는지 보는 것이 이 과제의 목적이다.

과제 2 — 우리 팀 감사 쿼리 만들기 (20분)

본문의 '품질 감시' 쿼리 4개(5~8번)를 우리 조직의 상태 이름에 맞게 고쳐서 실행하고, 결과를 적는다.

쿼리우리 조직 버전결과 건수예상과 달랐던 점
재오픈된 결함
검증 건너뛴 결함
60일 방치 결함
담당자 없는 고우선순위
해설 보기

'검증 건너뛴 결함' 쿼리에서 예상보다 큰 숫자가 나오는 조직이 많다. 그런데 그 결과를 그대로 "프로세스가 안 지켜집니다"라고 보고하면 안 된다. 원인이 여러 가지이기 때문이다.

  • 실제로 검증을 건너뛴 경우
  • 검증 상태를 거치지 않는 워크플로가 따로 있는 경우(핫픽스 등)
  • 상태 이름이 중간에 바뀌어 과거 이력이 다른 이름으로 남은 경우

세 번째가 특히 함정이다. 워크플로를 개편한 조직에서는 이력 검색 결과가 왜곡된다. 숫자를 보고하기 전에 표본 몇 건을 열어 확인하는 습관 이 필요하다. 모듈 18c에서 배우는 교차검증의 태도가 여기서도 그대로 쓰인다.

'60일 방치 결함' 결과는 대개 두 부류로 갈린다 — 정말 고쳐야 하는데 잊힌 것과, 사실상 고치지 않기로 결정됐지만 닫지 않은 것. 후자는 상태를 정리하는 것만으로도 지표가 정확해진다.

과제 3 — 필터 저장하고 공유하기 (12분)

과제 2에서 만든 쿼리 중 가장 유용한 것 하나를 필터로 저장한다.

  1. 이름 규칙을 정해서 붙인다(용도 접두어 + 대상 + 주기)
  2. 조회자·편집자 권한을 팀 단위로 설정한다
  3. 저장된 필터를 다시 열어 결과가 같은지 확인한다
  4. 다른 팀원 계정으로 보이는지 확인한다(또는 확인할 방법을 적는다)

currentUser() 를 쓴 필터라면 4번에서 결과가 사람마다 다르게 나오는 것이 정상이다 — 그게 이 함수를 쓰는 이유다.

과제 4 — 주간 리포트를 자동화하기 (15분)

"매주 월요일 아침, 지난주에 새로 등록된 결함과 방치된 결함 목록을 팀에 공유한다"는 업무를 수작업 없이 만드는 방법을 설계한다.

  • 필요한 필터 2개의 JQL을 쓴다
  • 각 필터의 공유 범위를 정한다
  • 전달 방식을 고른다(필터 구독 / 대시보드 / 자동화 규칙)
  • 이 자동화가 실패할 수 있는 경우 를 두 가지 적는다
해설 보기

실패 경우로 자주 나오는 좋은 답들이다 — (1) 상태 이름이 바뀌면 필터가 조용히 0건을 반환한다(오류가 아니라 빈 결과라서 눈치채기 어렵다), (2) 필터를 만든 사람이 퇴사해 권한이 사라진다, (3) 프로젝트가 분리되면서 필터 조건 밖으로 항목이 이동한다.

(1)이 특히 위험하다. 0건이 "문제가 없음"인지 "필터가 깨짐"인지 구분되지 않는다. 실무 대응은 간단하다 — 리포트에 전체 건수 같은 대조 지표를 하나 넣어두면, 그 숫자가 0이 되는 순간 필터 문제임을 알 수 있다.

자가 체크리스트

  • JQL의 기본 구조(field operator value)와 AND·OR·NOT 결합을 쓸 수 있다
  • =, ~, IN, IS EMPTY 의 차이를 설명하고 상황에 맞게 고를 수 있다
  • ~ 를 지표 집계에 쓰면 안 되는 이유를 말할 수 있다
  • currentUser() 를 쓰는 것과 사용자명을 하드코딩하는 것의 차이를 설명할 수 있다
  • 상대 날짜(-7d, startOfMonth())로 필터를 시간에 독립적으로 만들 수 있다
  • WAS·CHANGED 로 과거 이력을 검색할 수 있다
  • 재오픈율·검증 누락처럼 이력 없이는 계산할 수 없는 지표를 예로 들 수 있다
  • 저장된 필터의 조회자·편집자 권한이 대시보드 가젯에 미치는 영향을 안다
  • 필터가 대시보드·보드·자동화·구독의 공통 재료가 된다는 것을 설명할 수 있다
  • 남의 JQL이 우리 조직에서 안 도는 가장 흔한 이유를 말할 수 있다
  • 필터가 0건을 반환할 때 '문제 없음'과 '필터 깨짐'을 구분할 방법을 설계할 수 있다

흔한 실수

  • 현재 상태만 검색한다. QA의 질문 상당수는 과거를 향한다. WAS· CHANGED 를 모르면 재오픈·검증 누락 같은 지표를 아예 만들 수 없다.
  • 사용자명과 절대 날짜를 하드코딩한다. 공유하는 순간 무용지물이 되고, 다음 달에 다시 고쳐야 한다.
  • ~ 로 지표를 집계한다. 부분 일치는 의도치 않은 항목을 포함한다. 집계에는 컴포넌트·레이블 같은 구조화된 필드를 쓴다.
  • 필터를 공유하지 않고 대시보드를 만들려 한다. 가젯 목록에 필터가 나타나지 않는 문제의 대부분이 공유 설정이다.
  • 남의 JQL을 그대로 붙여 넣는다. 상태·필드 이름은 조직마다 다르다. 자동완성으로 실제 값을 확인한다.
  • 0건 결과를 '문제 없음'으로 읽는다. 필터가 깨져도 0건이다. 대조 지표를 함께 둔다.
  • 감사 쿼리 결과를 검증 없이 보고한다. 워크플로 개편·상태 이름 변경이 이력을 왜곡한다. 표본 몇 건을 열어 확인한 뒤 말한다.
  • 필터를 정리 없이 쌓는다. 30개가 넘으면 찾을 수 없고, 지우면 대시보드가 깨진다. 이름 규칙과 주기적 정리가 필요하다.

참고 자료

낯선 말 풀이

이 레슨에 나온 약어입니다. 본문에서도 처음 나올 때 점선으로 표시해 두었습니다 (제목과 링크 글자는 그대로 둡니다).

QA — 품질보증
만든 것이 쓸 만한지 확인하고, 애초에 덜 망가지게 만드는 방법을 정하는 일. "테스트"는 그 일의 일부다.
JQL — 지라 질의 언어
결함 관리 도구에서 "이런 조건인 건만 보여 달라"고 적는 말.

용어집 전체 보기