attachments

Sentivex Incidents Ticket API

GET/api/attachments

API 라우트: POST|GET /api/attachments

API 라우트: POST|GET /api/attachments 첨부파일 메타데이터 등록(POST)과 목록 조회(GET)를 담당한다. 실제 파일 바이너리는 이 라우트가 처리하지 않는다 — 클라이언트가 MinIO presigned PUT URL로 직접 업로드한 뒤, 이 엔드포인트로 메타를 등록한다. 첨부 대상(attachable): issue | page | comment 최대 파일 크기: 50 MB (createSchema sizeBytes 상한) 권한: JWT 로그인 필수 + 해당 프로젝트 멤버십 필수. @author jijuta ([email protected]) @since 2026-05-03 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용 @updated 2026-06-07 — #41 storagePath 가 projectId prefix 로 시작하는지 검증(cross-project IDOR 차단)

Responses

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

API 라우트: POST|GET /api/attachments

API 라우트: POST|GET /api/attachments 첨부파일 메타데이터 등록(POST)과 목록 조회(GET)를 담당한다. 실제 파일 바이너리는 이 라우트가 처리하지 않는다 — 클라이언트가 MinIO presigned PUT URL로 직접 업로드한 뒤, 이 엔드포인트로 메타를 등록한다. 첨부 대상(attachable): issue | page | comment 최대 파일 크기: 50 MB (createSchema sizeBytes 상한) 권한: JWT 로그인 필수 + 해당 프로젝트 멤버십 필수. @author jijuta ([email protected]) @since 2026-05-03 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용 @updated 2026-06-07 — #41 storagePath 가 projectId prefix 로 시작하는지 검증(cross-project IDOR 차단)

Request body

projectIdstring<uuid>required
namestringrequired
mimeTypestring
sizeBytesanyrequired
storagePathstringrequired
attachableTypeanyrequired
attachableIdstring<uuid>required

Responses

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

API 라우트: GET|DELETE /api/attachments/[attachmentId]

API 라우트: GET|DELETE /api/attachments/[attachmentId] 개별 첨부파일에 대한 두 가지 작업을 담당한다. - GET : MinIO presigned URL(15분 유효)을 발급해 파일 다운로드 링크를 반환. - DELETE: MinIO 오브젝트와 DB 메타데이터를 모두 삭제하고 활동 로그 기록. 권한: JWT 로그인 필수 + 해당 첨부파일이 속한 프로젝트 멤버십 필수. 경로 파라미터: attachmentId (UUID) @author jijuta ([email protected]) @since 2026-05-03 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용

Path parameters

attachmentIdstringrequired

Responses

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

API 라우트: GET|DELETE /api/attachments/[attachmentId]

API 라우트: GET|DELETE /api/attachments/[attachmentId] 개별 첨부파일에 대한 두 가지 작업을 담당한다. - GET : MinIO presigned URL(15분 유효)을 발급해 파일 다운로드 링크를 반환. - DELETE: MinIO 오브젝트와 DB 메타데이터를 모두 삭제하고 활동 로그 기록. 권한: JWT 로그인 필수 + 해당 첨부파일이 속한 프로젝트 멤버십 필수. 경로 파라미터: attachmentId (UUID) @author jijuta ([email protected]) @since 2026-05-03 @updated 2026-06-07 — JSDoc 표준(@author/@since/@param 등) 적용

Path parameters

attachmentIdstringrequired

Responses

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

POST /api/attachments/presigned

Request body

projectIdstring<uuid>required
filenamestringrequired
contentTypestringrequired
sizeBytesanyrequired

Responses

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