issues

Sentivex Incidents Ticket API

GET/api/issues

프로젝트 이슈 목록 조회(GET) 및 신규 이슈 생성(POST)을 담당한다.

API 라우트: /api/issues 프로젝트 이슈 목록 조회(GET) 및 신규 이슈 생성(POST)을 담당한다. GET 주요 기능: - (sortOrder, id) ASC 기반 커서 페이지네이션 — 리스트·타임라인·캘린더 뷰에서 사용 - parentId 필터: 상세 시트 내 자식 이슈 조회 - rootsOnly=1: 트리 lazy-load 최상위 fetch (자식 있음 여부를 childCount 로 전달) - 각 행에 상태(status)·담당자(assignee) JOIN 포함 POST 주요 기능: - 이슈 키(projectKey-N) 자동 발급 (projects.issueCounter 원자적 증가) - 상태 미지정 시 프로젝트 기본 상태 자동 배정 - 형제 이슈 중 최대 sortOrder + 1000 을 초기 정렬값으로 설정 - 활동 로그 기록(logActivity) + SSE 실시간 이벤트 발행(publishProjectEvent) - description 은 sanitizeRichHtml 로 XSS 방지 처리 권한: 프로젝트 접근 가능 멤버 이상 (requireUser + requireProjectAccess) @author jijuta ([email protected]) @since 2026-05-03 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용

Responses

200 성공401 미인증(JWT 쿠키 필요)403 권한 없음404 없음
cURL
curl -X GET https://sit.in-bridge.com/api/issues \
  -H "Authorization: Bearer $TOKEN"
JavaScript
const res = await fetch("https://sit.in-bridge.com/api/issues", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${token}`
  }
});
const data = await res.json();
POST/api/issues

프로젝트 이슈 목록 조회(GET) 및 신규 이슈 생성(POST)을 담당한다.

API 라우트: /api/issues 프로젝트 이슈 목록 조회(GET) 및 신규 이슈 생성(POST)을 담당한다. GET 주요 기능: - (sortOrder, id) ASC 기반 커서 페이지네이션 — 리스트·타임라인·캘린더 뷰에서 사용 - parentId 필터: 상세 시트 내 자식 이슈 조회 - rootsOnly=1: 트리 lazy-load 최상위 fetch (자식 있음 여부를 childCount 로 전달) - 각 행에 상태(status)·담당자(assignee) JOIN 포함 POST 주요 기능: - 이슈 키(projectKey-N) 자동 발급 (projects.issueCounter 원자적 증가) - 상태 미지정 시 프로젝트 기본 상태 자동 배정 - 형제 이슈 중 최대 sortOrder + 1000 을 초기 정렬값으로 설정 - 활동 로그 기록(logActivity) + SSE 실시간 이벤트 발행(publishProjectEvent) - description 은 sanitizeRichHtml 로 XSS 방지 처리 권한: 프로젝트 접근 가능 멤버 이상 (requireUser + requireProjectAccess) @author jijuta ([email protected]) @since 2026-05-03 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용

Request body

projectIdstring<uuid>required
titlestringrequired
descriptionstring
typeenumrequired
epicstorytasksubtaskbug
priorityanyrequired
statusIdstring<uuid>
assigneeIdstring<uuid>
parentIdstring<uuid>
startDatestring
dueDatestring
storyPointsany
repoPathstring

Responses

200 성공400 입력 검증 실패(zod)401 미인증(JWT 쿠키 필요)403 권한 없음404 없음
cURL
curl -X POST https://sit.in-bridge.com/api/issues \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"projectId":"00000000-0000-0000-0000-000000000000","title":"string","description":"string","type":"epic","priority":null,"statusId":"00000000-0000-0000-0000-000000000000","assigneeId":"00000000-0000-0000-0000-000000000000","parentId":"00000000-0000-0000-0000-000000000000","startDate":"string","dueDate":"string","storyPoints":null,"repoPath":"string"}'
JavaScript
const res = await fetch("https://sit.in-bridge.com/api/issues", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${token}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "projectId": "00000000-0000-0000-0000-000000000000",
    "title": "string",
    "description": "string",
    "type": "epic",
    "priority": null,
    "statusId": "00000000-0000-0000-0000-000000000000",
    "assigneeId": "00000000-0000-0000-0000-000000000000",
    "parentId": "00000000-0000-0000-0000-000000000000",
    "startDate": "string",
    "dueDate": "string",
    "storyPoints": null,
    "repoPath": "string"
  })
});
const data = await res.json();
GET/api/issues/{issueId}

API 라우트: GET | PATCH | DELETE /api/issues/[issueId]

API 라우트: GET | PATCH | DELETE /api/issues/[issueId] 단일 이슈의 상세 조회, 수정, 소프트 삭제를 처리한다. GET: 이슈 상세(상태·담당자·부모 join) + 댓글 목록(최신순)을 반환한다. 결과는 Redis 에 15 초 캐시된다. 캐시 히트 시에도 권한 검사는 항상 수행한다. PATCH: updateIssueSchema 에 정의된 필드를 부분 업데이트한다. description 은 sanitizeRichHtml 로 XSS 를 제거한 후 저장한다. 담당자가 새로 지정되면 해당 사용자에게 인앱 알림을 전송한다. DELETE: 물리 삭제 없이 deletedAt 타임스탬프만 기록(소프트 삭제)한다. 목록 조회에서 isNull(deletedAt) 필터로 자동 제외된다. 권한: 모든 메서드에서 프로젝트 멤버여야 한다. 부작용: - Redis 캐시 무효화(PATCH/DELETE) - activity_logs 기록 - SSE(publishProjectEvent) 실시간 브로드캐스트 @author jijuta ([email protected]) @since 2026-05-03 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용

Path parameters

issueIdstringrequired

Responses

200 성공401 미인증(JWT 쿠키 필요)403 권한 없음404 없음
cURL
curl -X GET https://sit.in-bridge.com/api/issues/{issueId} \
  -H "Authorization: Bearer $TOKEN"
JavaScript
const res = await fetch("https://sit.in-bridge.com/api/issues/{issueId}", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${token}`
  }
});
const data = await res.json();
PATCH/api/issues/{issueId}

API 라우트: GET | PATCH | DELETE /api/issues/[issueId]

API 라우트: GET | PATCH | DELETE /api/issues/[issueId] 단일 이슈의 상세 조회, 수정, 소프트 삭제를 처리한다. GET: 이슈 상세(상태·담당자·부모 join) + 댓글 목록(최신순)을 반환한다. 결과는 Redis 에 15 초 캐시된다. 캐시 히트 시에도 권한 검사는 항상 수행한다. PATCH: updateIssueSchema 에 정의된 필드를 부분 업데이트한다. description 은 sanitizeRichHtml 로 XSS 를 제거한 후 저장한다. 담당자가 새로 지정되면 해당 사용자에게 인앱 알림을 전송한다. DELETE: 물리 삭제 없이 deletedAt 타임스탬프만 기록(소프트 삭제)한다. 목록 조회에서 isNull(deletedAt) 필터로 자동 제외된다. 권한: 모든 메서드에서 프로젝트 멤버여야 한다. 부작용: - Redis 캐시 무효화(PATCH/DELETE) - activity_logs 기록 - SSE(publishProjectEvent) 실시간 브로드캐스트 @author jijuta ([email protected]) @since 2026-05-03 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용

Path parameters

issueIdstringrequired

Request body

titlestring
descriptionstring
statusIdstring<uuid>
typeenum
epicstorytasksubtaskbug
priorityany
assigneeIdstring<uuid>
parentIdstring<uuid>
startDatestring
dueDatestring
storyPointsany
sprintIdstring<uuid>

Responses

200 성공400 입력 검증 실패(zod)401 미인증(JWT 쿠키 필요)403 권한 없음404 없음
cURL
curl -X PATCH https://sit.in-bridge.com/api/issues/{issueId} \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"string","description":"string","statusId":"00000000-0000-0000-0000-000000000000","type":"epic","priority":null,"assigneeId":"00000000-0000-0000-0000-000000000000","parentId":"00000000-0000-0000-0000-000000000000","startDate":"string","dueDate":"string","storyPoints":null,"sprintId":"00000000-0000-0000-0000-000000000000"}'
JavaScript
const res = await fetch("https://sit.in-bridge.com/api/issues/{issueId}", {
  method: "PATCH",
  headers: {
    "Authorization": `Bearer ${token}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "title": "string",
    "description": "string",
    "statusId": "00000000-0000-0000-0000-000000000000",
    "type": "epic",
    "priority": null,
    "assigneeId": "00000000-0000-0000-0000-000000000000",
    "parentId": "00000000-0000-0000-0000-000000000000",
    "startDate": "string",
    "dueDate": "string",
    "storyPoints": null,
    "sprintId": "00000000-0000-0000-0000-000000000000"
  })
});
const data = await res.json();
DELETE/api/issues/{issueId}

API 라우트: GET | PATCH | DELETE /api/issues/[issueId]

API 라우트: GET | PATCH | DELETE /api/issues/[issueId] 단일 이슈의 상세 조회, 수정, 소프트 삭제를 처리한다. GET: 이슈 상세(상태·담당자·부모 join) + 댓글 목록(최신순)을 반환한다. 결과는 Redis 에 15 초 캐시된다. 캐시 히트 시에도 권한 검사는 항상 수행한다. PATCH: updateIssueSchema 에 정의된 필드를 부분 업데이트한다. description 은 sanitizeRichHtml 로 XSS 를 제거한 후 저장한다. 담당자가 새로 지정되면 해당 사용자에게 인앱 알림을 전송한다. DELETE: 물리 삭제 없이 deletedAt 타임스탬프만 기록(소프트 삭제)한다. 목록 조회에서 isNull(deletedAt) 필터로 자동 제외된다. 권한: 모든 메서드에서 프로젝트 멤버여야 한다. 부작용: - Redis 캐시 무효화(PATCH/DELETE) - activity_logs 기록 - SSE(publishProjectEvent) 실시간 브로드캐스트 @author jijuta ([email protected]) @since 2026-05-03 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용

Path parameters

issueIdstringrequired

Responses

200 성공401 미인증(JWT 쿠키 필요)403 권한 없음404 없음
cURL
curl -X DELETE https://sit.in-bridge.com/api/issues/{issueId} \
  -H "Authorization: Bearer $TOKEN"
JavaScript
const res = await fetch("https://sit.in-bridge.com/api/issues/{issueId}", {
  method: "DELETE",
  headers: {
    "Authorization": `Bearer ${token}`
  }
});
const data = await res.json();
POST/api/issues/{issueId}/comments

특정 이슈에 댓글을 작성한다.

API 라우트: POST /api/issues/[issueId]/comments 특정 이슈에 댓글을 작성한다. - POST: 댓글 생성. 이슈 소프트-삭제 여부 확인 → 프로젝트 접근 권한 확인 → DB insert. 성공 시 이슈 상세 캐시 무효화, 활동 로그 기록, 이슈 작성자에게 알림 발송. 권한: 로그인 사용자 + 해당 프로젝트 접근 권한 (requireProjectAccess). 부작용: - issueComments 테이블 insert - issueById 캐시 삭제 (cacheDel) - activity_logs 기록 (logActivity) - 이슈 작성자에게 인앱 알림 (notify) — 본인 댓글이면 생략 @author jijuta ([email protected]) @since 2026-05-03 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용

Path parameters

issueIdstringrequired

Request body

contentstringrequired

Responses

200 성공400 입력 검증 실패(zod)401 미인증(JWT 쿠키 필요)403 권한 없음404 없음
cURL
curl -X POST https://sit.in-bridge.com/api/issues/{issueId}/comments \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"string"}'
JavaScript
const res = await fetch("https://sit.in-bridge.com/api/issues/{issueId}/comments", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${token}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "content": "string"
  })
});
const data = await res.json();
GET/api/issues/{issueId}/labels

특정 이슈의 라벨을 조회하거나 토글(추가/제거)한다.

API 라우트: GET/POST /api/issues/[issueId]/labels 특정 이슈의 라벨을 조회하거나 토글(추가/제거)한다. - GET : 이슈에 붙은 라벨 목록 반환 (id·name·color). - POST: { labelId } 를 받아 이미 붙어있으면 제거, 없으면 추가하는 토글 방식. 변경 후 활동 로그 기록 + Redis SSE 이벤트로 실시간 동기화. 권한: 로그인 사용자 + 해당 프로젝트 접근 권한 (requireProjectAccess). 부작용: - issueLabels 테이블 insert 또는 delete - activity_logs 기록 (logActivity) - Redis Pub/Sub 으로 프로젝트 이벤트 발행 (publishProjectEvent → SSE 구독자에게 전파) @author jijuta ([email protected]) @since 2026-05-03 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용

Path parameters

issueIdstringrequired

Responses

200 성공401 미인증(JWT 쿠키 필요)403 권한 없음404 없음
cURL
curl -X GET https://sit.in-bridge.com/api/issues/{issueId}/labels \
  -H "Authorization: Bearer $TOKEN"
JavaScript
const res = await fetch("https://sit.in-bridge.com/api/issues/{issueId}/labels", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${token}`
  }
});
const data = await res.json();
POST/api/issues/{issueId}/labels

특정 이슈의 라벨을 조회하거나 토글(추가/제거)한다.

API 라우트: GET/POST /api/issues/[issueId]/labels 특정 이슈의 라벨을 조회하거나 토글(추가/제거)한다. - GET : 이슈에 붙은 라벨 목록 반환 (id·name·color). - POST: { labelId } 를 받아 이미 붙어있으면 제거, 없으면 추가하는 토글 방식. 변경 후 활동 로그 기록 + Redis SSE 이벤트로 실시간 동기화. 권한: 로그인 사용자 + 해당 프로젝트 접근 권한 (requireProjectAccess). 부작용: - issueLabels 테이블 insert 또는 delete - activity_logs 기록 (logActivity) - Redis Pub/Sub 으로 프로젝트 이벤트 발행 (publishProjectEvent → SSE 구독자에게 전파) @author jijuta ([email protected]) @since 2026-05-03 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용

Path parameters

issueIdstringrequired

Request body

labelIdstring<uuid>required

Responses

200 성공400 입력 검증 실패(zod)401 미인증(JWT 쿠키 필요)403 권한 없음404 없음
cURL
curl -X POST https://sit.in-bridge.com/api/issues/{issueId}/labels \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"labelId":"00000000-0000-0000-0000-000000000000"}'
JavaScript
const res = await fetch("https://sit.in-bridge.com/api/issues/{issueId}/labels", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${token}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "labelId": "00000000-0000-0000-0000-000000000000"
  })
});
const data = await res.json();
POST/api/issues/{issueId}/links

API 라우트: GET|POST /api/issues/[issueId]/links

API 라우트: GET|POST /api/issues/[issueId]/links 이슈 간 관계(링크) 목록 조회 및 생성. 링크는 항상 양방향으로 저장된다(source→target, target→source 짝 row). GET 은 해당 이슈가 source 인 outgoing 링크만 반환하며, 대상 이슈 메타를 join 해 포함한다. POST 는 트랜잭션으로 두 방향 모두 INSERT 하고, 중복 시 409 를 반환한다. 권한: 해당 이슈의 프로젝트 멤버여야 한다. 부작용(POST): - activity_logs 에 issue.link_added 기록 - SSE(publishProjectEvent) 로 실시간 브로드캐스트 @author jijuta ([email protected]) @since 2026-05-12 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용 @updated 2026-06-07 — #62 targetId 직접 전달 시 같은 프로젝트 소속 검증(cross-project 연결 IDOR 차단)

Path parameters

issueIdstringrequired

Responses

200 성공401 미인증(JWT 쿠키 필요)403 권한 없음404 없음
cURL
curl -X POST https://sit.in-bridge.com/api/issues/{issueId}/links \
  -H "Authorization: Bearer $TOKEN"
JavaScript
const res = await fetch("https://sit.in-bridge.com/api/issues/{issueId}/links", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${token}`
  }
});
const data = await res.json();
PATCH/api/issues/{issueId}/move

이슈를 계층 트리 안에서 이동시키고 sort_order 를 분수 정렬(fractional indexing)로 재계산한다.

API 라우트: PATCH /api/issues/[issueId]/move 이슈를 계층 트리 안에서 이동시키고 sort_order 를 분수 정렬(fractional indexing)로 재계산한다. 세 가지 이동 모드를 지원한다: - child : 지정한 부모(parentId 또는 relativeToId)의 자식 끝에 추가 - before : relativeToId 이슈 바로 앞(형제) 위치 - after : relativeToId 이슈 바로 뒤(형제) 위치 사이클 방지를 위해 자손이 자신의 조상이 되는 이동은 재귀 CTE 로 차단한다. 권한: 해당 이슈의 프로젝트 멤버여야 한다. 부작용: - Redis 캐시 무효화(cacheKeys.issueById) - activity_logs 에 issue.moved 기록 - SSE(publishProjectEvent) 로 실시간 브로드캐스트 @author jijuta ([email protected]) @since 2026-05-04 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용

Path parameters

issueIdstringrequired

Responses

200 성공401 미인증(JWT 쿠키 필요)403 권한 없음404 없음
cURL
curl -X PATCH https://sit.in-bridge.com/api/issues/{issueId}/move \
  -H "Authorization: Bearer $TOKEN"
JavaScript
const res = await fetch("https://sit.in-bridge.com/api/issues/{issueId}/move", {
  method: "PATCH",
  headers: {
    "Authorization": `Bearer ${token}`
  }
});
const data = await res.json();
GET/api/issues/{issueId}/watch

특정 이슈에 대한 "구독(watch)" 기능을 담당한다.

API 라우트: /api/issues/[issueId]/watch 특정 이슈에 대한 "구독(watch)" 기능을 담당한다. 구독한 사용자는 이슈 변경(댓글·상태·담당자 등) 시 알림을 수신한다. - GET : 요청자의 구독 여부 + 전체 구독자 수 반환 - POST : 구독 토글 — 이미 구독 중이면 해제, 미구독이면 구독 등록 권한: 프로젝트 멤버 이상 (requireProjectAccess) @author jijuta ([email protected]) @since 2026-05-12 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용

Path parameters

issueIdstringrequired

Responses

200 성공401 미인증(JWT 쿠키 필요)403 권한 없음404 없음
cURL
curl -X GET https://sit.in-bridge.com/api/issues/{issueId}/watch \
  -H "Authorization: Bearer $TOKEN"
JavaScript
const res = await fetch("https://sit.in-bridge.com/api/issues/{issueId}/watch", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${token}`
  }
});
const data = await res.json();
POST/api/issues/{issueId}/watch

특정 이슈에 대한 "구독(watch)" 기능을 담당한다.

API 라우트: /api/issues/[issueId]/watch 특정 이슈에 대한 "구독(watch)" 기능을 담당한다. 구독한 사용자는 이슈 변경(댓글·상태·담당자 등) 시 알림을 수신한다. - GET : 요청자의 구독 여부 + 전체 구독자 수 반환 - POST : 구독 토글 — 이미 구독 중이면 해제, 미구독이면 구독 등록 권한: 프로젝트 멤버 이상 (requireProjectAccess) @author jijuta ([email protected]) @since 2026-05-12 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용

Path parameters

issueIdstringrequired

Responses

200 성공401 미인증(JWT 쿠키 필요)403 권한 없음404 없음
cURL
curl -X POST https://sit.in-bridge.com/api/issues/{issueId}/watch \
  -H "Authorization: Bearer $TOKEN"
JavaScript
const res = await fetch("https://sit.in-bridge.com/api/issues/{issueId}/watch", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${token}`
  }
});
const data = await res.json();
GET/api/issues/by-key

이슈 key → id 조회.

GET /api/issues/by-key?projectId=X&key=DFX-5 — 이슈 key → id 조회. 별도 상세 페이지(/issues/[key])가 key 로 진입해 id 를 얻어 상세를 렌더하기 위함.

Responses

200 성공401 미인증(JWT 쿠키 필요)403 권한 없음404 없음
cURL
curl -X GET https://sit.in-bridge.com/api/issues/by-key \
  -H "Authorization: Bearer $TOKEN"
JavaScript
const res = await fetch("https://sit.in-bridge.com/api/issues/by-key", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${token}`
  }
});
const data = await res.json();