KISA 신고 4건(KVE-2026-1886/1887/1893/1894)을 검증하고, 미수정 2건과 동종 결함 전수 조사에서 나온 결함을 함께 조치했다. 권한 게이트 (KVE-2026-1893) - NHN KCP 관리자 주문 연동 7경로가 admin 보유 여부만 보고 세부 권한을 보지 않아, 업무 권한 없는 관리자가 주문번호·결제정보·수령인 연락처를 조회하고 에스크로 배송등록까지 할 수 있었다. 조회는 orders.read, 등록은 orders.update, 설정성 경로는 settings.read 로 게이트해 다른 PG 연동과 강도를 맞췄다. - 마케팅 채널 저장은 코어 플러그인 설정과 같은 저장소를 덮어쓰는 우회 경로라 core.plugins.update 를 부착했다. 첨부 해시 노출 (KVE-2026-1894 잔재) - 비밀글의 썸네일 URL 이 목록·상세 응답에 그대로 실려 첨부 해시가 노출됐다. 이미지 서빙은 이미 차단돼 있었으나 식별값 자체가 나갔다. 첨부 목록과 같은 게이트를 써서 값만 가리고 필드는 유지한다. 경쟁 조건 (KVE-2026-1886 + 전수 조사) - 쿠폰 차감을 조회 후 갱신에서 조건부 UPDATE 로 바꿔 1회 제한 쿠폰의 동시 사용을 막고, 선점당한 주문은 409 로 되돌린다. - 라이브 병렬 재현에서 그 롤백이 동작하지 않는 것을 확인했다. Action 훅 기본값이 큐 래핑 + afterCommit 이라 금전 처리가 호출자 커밋 뒤에 실행되고 있었다. 쿠폰·적립금 차감/복원 5개 구독에 sync 를 선언했고, 회귀 테스트는 손 등록이 아니라 실제 등록 경로를 태워 고정했다. - 동시 부분취소의 취소 누적 컬럼 lost update, 적립 lot 의 read-modify-write, 주문옵션당 적립 lot 중복 생성을 각각 행 잠금·컬럼 연산·유니크 제약으로 막았다. 기설치본의 중복 lot 은 인덱스 생성 전에 금액을 합산해 한 줄로 통합한다. 규정·문서 - sync 판정 기준을 hooks.md 에 명문화하고 /AGENTS.md Listener 표와 coverage manifest 에 반영했다. 같은 증상을 다시 만났을 때의 진단 경로를 트러블슈팅 사례로 남겼다.
112 KiB
Board API 레퍼런스
소유: module
sirsoft-board· 생성:php artisan api:docgen(실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
TL;DR (5초 요약)
1. 이 문서는 실제 API 호출로 실측한 Board 엔드포인트 레퍼런스입니다
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 요청 예시(raw HTTP) + 실측 응답 필드 표 + 응답 예시(envelope)
3. 응답 필드의 예시값·응답 예시 JSON 은 실제 호출 응답에서 관측된 값입니다
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
5. 설명(TODO) 칸은 사람이 채웁니다
비밀글 서버측 게이팅 (KVE-2026-1914)
비밀글(is_secret)의 원문은 작성자 본인 또는 게시판 관리 권한(posts.read-secret/manager)을 가진 요청에만 제공됩니다. 판정은 SecretContentGate(SSoT)가 담당하며 게시글 상세 외 다음 경로에도 동일하게 적용됩니다.
- 댓글 목록(
GET .../posts/{postId}/comments): 부모 게시글이 비밀글이고 열람 권한이 없으면 빈 목록(200)을 반환합니다. - 첨부 서빙(
GET .../attachment/{hash},.../attachment/{hash}/preview): 부모 게시글이 비밀글이고 열람 권한이 없으면403. 첨부 요청은 상세와 분리된 요청이라 비밀번호 검증(password_verified)은 적용되지 않으며 작성자/관리 권한만 인정합니다. - 상세/목록 응답: 비열람자에게
content·title·reply·attachments가 마스킹됩니다.
목록·검색의 총 건수와 답변·댓글 상한
게시판 목록에 search 를 얹으면 내부 검색이 수행됩니다. 매칭이 아주 많을 수 있으므로 총
건수는 상한까지만 세며, 상한을 넘으면 응답의 pagination 에 정확도가 함께 실립니다
(total_relation / total_is_exact / result_cap). 이때 last_page 는 null 이고
has_more_pages 는 그대로 정확하므로, 마지막 페이지 점프만 감춰지고 다음 페이지 이동은
끝까지 열려 있습니다. 상세 규약은 pagination.md 를 참고하세요.
검색어에 + - * " < > 같은 문자가 들어와도 오류가 나지 않습니다. 코어 정제기가
FULLTEXT 연산자를 제거한 뒤 검색하며, 연산자만 입력한 경우에는 오류 대신 빈 결과를 돌려줍니다.
게시글 상세 응답의 답변 트리와 댓글 목록에도 같은 상한이 적용됩니다. 한 글에 답변·댓글이 극단적으로 많은 경우 그 지점에서 끊기며, 총 건수는 목록 응답의 집계로 확인할 수 있습니다.
POST /api/modules/sirsoft-board/admin/board/{slug}/attachments
- 라우트명:
api.modules.sirsoft-board.admin.board.attachments.upload - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\AttachmentController@upload - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.attachments.upload
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| file | body | file | 예 | — | 업로드 파일 |
| post_id | body | integer | 아니오 | min 1 | post 식별자 |
| collection | body | string | 아니오 | max 100 | 첨부 컬렉션 그룹명 (첨부를 용도별로 묶는 키, 미지정 시 default) |
| temp_key | body | string | 아니오 | max 64 | 게시글 작성 전 임시 업로드 세션 키. post_id가 없을 때 이 키로 첨부를 임시 보관했다가 게시글 저장 시점에 연결합니다 (쿼리스트링으로 보내면 body로 병합). |
이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (
sirsoft-board.attachment.upload_validation_rules).
요청 예시
POST /api/modules/sirsoft-board/admin/board/{slug}/attachments HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
Content-Type: multipart/form-data; boundary=----G7ExampleBoundary
------G7ExampleBoundary
Content-Disposition: form-data; name="file"; filename="example.pdf"
Content-Type: application/octet-stream
(바이너리 파일 내용)
------G7ExampleBoundary
Content-Disposition: form-data; name="post_id"
1
------G7ExampleBoundary
Content-Disposition: form-data; name="collection"
예시값
------G7ExampleBoundary
Content-Disposition: form-data; name="temp_key"
예시값
------G7ExampleBoundary--
응답 필드 (data 내부)
단건 응답: data 객체의 필드. FileUploader 컴포넌트 호환을 위해 파일 메타는 data.data 로 한 번 더 감싸집니다.
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| data | object | {"id":1,"hash":"apidocsmpl1", ...} |
업로드된 첨부파일 메타 객체 (아래 하위 필드) |
| data.id | integer | 1 |
첨부파일 기본 키 (게시판별 첨부 테이블의 내부 식별자) |
| data.hash | string | apidocsmpl1 |
첨부파일 해시 식별자 (다운로드/미리보기 URL 에 사용) |
| data.original_filename | string | apidoc-sample.png |
사용자가 업로드한 원본 파일명 |
| data.stored_filename | string | — |
스토리지에 실제 저장된 파일명 (충돌 방지용 내부 파일명) |
| data.mime_type | string | image/png |
업로드 파일의 MIME 타입 |
| data.size | integer | 2048 |
파일 크기 (바이트) |
| data.url | string | /api/modules/sirsoft-board/boards/apidoc-sample-board/attachment/apidocsmpl1 |
첨부파일 접근 URL (AttachmentService::getUrl() 산물) |
| data.order | integer | 0 |
첨부파일 표시 순서 (0 부터 오름차순) |
| data.created_at | string | 2026-07-08 10:41:34 |
업로드(생성) 일시 |
응답 예시
HTTP/1.1 201
{
"success": true,
"message": "파일이 업로드되었습니다.",
"data": {
"data": {
"id": 1,
"hash": "apidocsmpl1",
"original_filename": "apidoc-sample.png",
"stored_filename": "apidocsmpl1.png",
"mime_type": "image/png",
"size": 2048,
"url": "/api/modules/sirsoft-board/boards/apidoc-sample-board/attachment/apidocsmpl1",
"order": 0,
"created_at": "2026-07-08 10:41:34"
}
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.attachments.upload)이 없는 경우 |
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 (슬러그에 해당하는 게시판 없음 — 게시판을 찾을 수 없습니다.) |
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (error.errors 에 필드별 메시지) |
| 500 | Internal Server Error | 업로드 처리 실패 (파일 업로드에 실패했습니다.) |
설명 게시판 관리자가 게시글 첨부파일 1건을 업로드합니다. auth:sanctum + admin + 게시판별 attachments.upload 권한이 필요하며, AttachmentService::upload()가 게시판별 동적 첨부 테이블에 저장합니다. post_id가 있으면 해당 게시글에 즉시 귀속되고, 없으면 temp_key로 임시 업로드되어 게시글 작성/수정 저장 시점에 연결됩니다. 응답은 FileUploader 컴포넌트 호환을 위해 data.data로 한 번 더 감싸 파일 메타(hash·url·order 등)를 반환합니다.
첨부 개수는 게시판 설정 max_file_count 를 기준으로 직접 업로드 · 미리 올려 둔 파일 연결(attachment_ids) · 임시 업로드 연결(temp_key) · 이미 연결된 첨부 를 모두 합산해 판정합니다. 상한을 넘으면 422(errors.code = attachment_limit_exceeded)를 반환하며, 이 판정은 업로드 엔드포인트뿐 아니라 게시글 생성·수정 저장 시점에도 동일하게 적용됩니다. max_file_count 가 0 이면 개수를 제한하지 않습니다.
GET /api/modules/sirsoft-board/admin/board/{slug}/attachments/download/{hash}
- 라우트명:
api.modules.sirsoft-board.admin.board.attachments.download - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\AttachmentController@download - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.attachments.download
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| hash | path | string | 예 | — | 대상 리소스의 해시 식별자 |
요청 예시
GET /api/modules/sirsoft-board/admin/board/{slug}/attachments/download/{hash} HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
응답 필드 (data 내부)
이 엔드포인트는 JSON 봉투를 반환하지 않습니다. 성공 시 파일 본문을 그대로 내려주는 StreamedResponse(바이너리 스트림)이며, data 구조가 없습니다. 실패 시에만 JSON 에러 봉투가 반환됩니다.
응답 예시
HTTP/1.1 200
Content-Type: image/png
Content-Disposition: attachment; filename="apidoc-sample.png"
(바이너리 파일 내용)
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.attachments.download)이 없는 경우 |
| 404 | Not Found | 슬러그에 해당하는 게시판이 없거나(게시판을 찾을 수 없습니다.), 해시에 해당하는 첨부가 없거나(파일을 찾을 수 없습니다.), 실제 파일이 스토리지에 없는 경우 |
| 500 | Internal Server Error | 다운로드 처리 실패 (파일 다운로드에 실패했습니다.) |
설명 게시판 관리자가 첨부파일을 해시로 조회해 다운로드합니다. auth:sanctum + admin + 게시판별 attachments.download 권한이 필요하며, AttachmentService::getByHash()로 대상을 찾은 뒤 download()가 파일 스트림 응답을 생성합니다. 해시에 해당하는 첨부가 없거나 실제 파일이 없으면 404를 반환하고, JSON이 아닌 StreamedResponse로 파일 본문을 직접 전송합니다.
PATCH /api/modules/sirsoft-board/admin/board/{slug}/attachments/reorder
- 라우트명:
api.modules.sirsoft-board.admin.board.attachments.reorder - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\AttachmentController@reorder - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.attachments.upload
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| order | body | array | 예 | min 1 | 첨부파일 순서 배열. FileUploader가 보내는 [{id, order}] 형태로, 각 원소의 id(첨부 ID)와 order(0 이상 정수)를 담아 표시 순서를 지정합니다. |
이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (
sirsoft-board.attachment.reorder_validation_rules).
요청 예시
PATCH /api/modules/sirsoft-board/admin/board/{slug}/attachments/reorder HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
Content-Type: application/json
{
"order": [
"예시값"
]
}
응답 필드 (data 내부)
이 엔드포인트는 data 를 반환하지 않습니다 (성공 메시지만 — data 는 null).
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "첨부파일 순서가 변경되었습니다.",
"data": null
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.attachments.upload)이 없는 경우 |
| 404 | Not Found | 슬러그에 해당하는 게시판이 없는 경우 (게시판을 찾을 수 없습니다.) |
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (error.errors 에 필드별 메시지) |
| 500 | Internal Server Error | 순서 변경 처리 실패 (첨부파일 순서 변경에 실패했습니다.) |
설명 게시판 관리자가 게시글 첨부파일들의 표시 순서를 일괄 변경합니다. auth:sanctum + admin + 게시판별 attachments.upload 권한이 필요하며, FileUploader가 보낸 [{id, order}] 배열을 [ID => order] 매핑으로 변환해 AttachmentService::reorder()가 게시판별 첨부 테이블의 order 값을 갱신합니다.
DELETE /api/modules/sirsoft-board/admin/board/{slug}/attachments/{id}
- 라우트명:
api.modules.sirsoft-board.admin.board.attachments.destroy - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\AttachmentController@destroy - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.attachments.upload
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| id | path | string | 예 | — | 대상 리소스의 식별자 |
요청 예시
DELETE /api/modules/sirsoft-board/admin/board/{slug}/attachments/{id} HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
응답 필드 (data 내부)
이 엔드포인트는 data 를 반환하지 않습니다 (성공 메시지만 — data 는 null).
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "파일이 삭제되었습니다.",
"data": null
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.attachments.upload)이 없는 경우 |
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
설명 게시판 관리자가 첨부파일 1건을 삭제합니다. auth:sanctum + admin + 게시판별 attachments.upload 권한이 필요하며, AttachmentService::getById()로 대상 존재를 확인한 뒤 delete()가 게시판별 첨부 테이블 레코드와 실제 파일을 함께 제거합니다. 첨부가 없으면 404, 삭제 실패 시 500을 반환합니다.
GET /api/modules/sirsoft-board/admin/board/{slug}/posts
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.index - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@index - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.posts.read
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
| search | query | string | 아니오 | max 255 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
요청 예시
GET /api/modules/sirsoft-board/admin/board/{slug}/posts?page=1&per_page=1&search=%EC%98%88%EC%8B%9C%EA%B0%92 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
응답 필드 (data 내부)
목록 응답: data.data[] 배열 항목의 필드 + data.pagination.
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| id | integer | 237 |
기본 키 (내부 식별자) |
| category | null | null |
게시글 분류(카테고리) 문자열. 게시판이 카테고리를 쓰지 않거나 미지정 시 null (최대 50자). |
| author | object | {"uuid":"a231747f-e82e-4cf2-9ae1-a261849dce40","name":"AP… |
작성자 사용자 객체 (uuid/name — author 관계 파생) |
| is_notice | boolean | false |
notice 여부 |
| is_secret | boolean | false |
secret 여부 |
| content_mode | string | html |
본문 편집 모드. html(위지윅/HTML) 또는 text(평문)이며, 요약·썸네일 추출과 렌더링 방식을 결정합니다. 미지정 시 text. |
| is_new | boolean | true |
new 여부 |
| status | string | published |
게시글 상태 코드. published(게시됨) / blinded(블라인드) / deleted(삭제됨) 중 하나이며, status_label이 사람이 읽는 라벨입니다. |
| status_label | string | 게시됨 |
상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
| view_count | integer | 43 |
view 개수 (집계) |
| comment_count | integer | 0 |
comment 개수 (집계) |
| reply_count | integer | 0 |
reply 개수 (집계) |
| attachment_count | integer | 0 |
attachment 개수 (집계) |
| has_attachment | boolean | false |
attachment 여부 |
| thumbnail | string | /api/modules/sirsoft-board/boards/api… |
썸네일 이미지 URL/경로 — /api/modules/sirsoft-board/boards/{slug}/attachment/{hash}/preview 형식 (첫 이미지 첨부의 미리보기 서빙 URL). 비밀글은 열람 권한이 없으면 null 로 내려간다(첨부 해시 노출 차단 — 필드 자체는 유지) |
| parent_id | null | null |
parent 식별자 (연관 리소스 참조) |
| depth | integer | 0 |
계층 트리에서의 깊이 (0 = 최상위, 하위로 갈수록 증가) |
| is_reply | boolean | false |
reply 여부 |
| created_at | string | 2026-07-07 09:34:50 |
생성 일시 |
| created_at_formatted | string | 4시간 전 |
created_at 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
| is_author | boolean | true |
author 여부 |
| is_guest_post | boolean | false |
guest post 여부 |
| slug | string | apidoc-sample-board |
게시판 슬러그 (URL/테이블명) |
| title | string | API 문서 샘플 게시글 |
제목 |
| deleted_at | null | null |
소프트 삭제 일시 (미삭제 시 null) |
| content_preview | string | API 레퍼런스 실측용 완전 샘플 게시글 본문입니다. |
목록용 본문 요약(태그 제거 후 앞 150자). 블라인드·비밀글은 원문 유출 방지를 위해 권한과 무관하게 빈 문자열을 반환합니다. |
| row_type | string | normal |
목록 행 유형. notice(공지) / reply(답변글) / normal(일반) 중 하나로, 목록 렌더링 시 행 스타일과 순번 표시를 분기합니다. |
| number | integer | 1 |
목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
| show_category | boolean | false |
목록에 카테고리 열을 노출할지 여부. 게시판 설정(show_category)에서 파생되어 각 행에 부여됩니다. |
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "게시글 목록을 조회했습니다.",
"data": {
"data": [
{
"id": 1,
"category": null,
"author": {
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"name": "API 문서 샘플 사용자",
"email": "apidoc-sample-user@example.com",
"avatar": null,
"status": "active",
"status_label": "활성",
"is_guest": false
},
"is_notice": false,
"is_secret": "{MASKED}",
"content_mode": "html",
"is_new": true,
"status": "published",
"status_label": "게시됨",
"view_count": 43,
"comment_count": 0,
"reply_count": 0,
"attachment_count": 0,
"has_attachment": false,
"thumbnail": "/api/modules/sirsoft-board/boards/apidoc-sample-board/attachment/apidocsmpl1/preview",
"parent_id": null,
"depth": 0,
"is_reply": false,
"created_at": "2026-07-08 10:41:34",
"created_at_formatted": "4시간 전",
"is_author": true,
"is_guest_post": false,
"slug": "apidoc-sample-board",
"title": "API 문서 샘플 게시글",
"deleted_at": null,
"content_preview": "API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.",
"row_type": "normal",
"number": 1,
"show_category": false
}
],
"pagination": {
"total": 1,
"all_total": 1,
"count": 1,
"per_page": 25,
"current_page": 1,
"last_page": 1,
"from": 1,
"to": 1,
"has_more_pages": false
},
"board": {
"slug": "apidoc-sample-board",
"name": "API 문서 샘플 게시판",
"type": "basic",
"categories": [],
"show_category": false,
"settings": {
"use_file_upload": true,
"use_comment": true,
"use_reply": true,
"use_report": true,
"secret_mode": "{MASKED}",
"per_page": 20,
"per_page_mobile": 15,
"order_by": "created_at",
"order_direction": "DESC"
}
},
"abilities": {
"can_read": true,
"can_write": true,
"can_read_secret": "{MASKED}",
"can_read_comments": true,
"can_write_comments": true,
"can_upload": true,
"can_download": true,
"can_manage": true
}
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.posts.read)이 없는 경우 |
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (error.errors 에 필드별 메시지) |
설명 게시판 관리자가 특정 게시판의 게시글 목록을 조회합니다. auth:sanctum + admin + 게시판별 posts.read 권한이 필요하며, 요청 파라미터로 검색·상태·정렬·페이지네이션이 적용됩니다(PostService::buildListParams). 추가로 admin.manage 권한이 있으면 소프트 삭제된 게시글까지 포함해 조회하며, 응답에는 공지 고정 처리 후의 일반 게시글 총 건수(캐시 기반)와 관리자용 게시판 정보(boardInfo)가 함께 담깁니다.
POST /api/modules/sirsoft-board/admin/board/{slug}/posts
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.store - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@store - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.posts.write
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (
sirsoft-board.post.store_validation_rules).
요청 예시
POST /api/modules/sirsoft-board/admin/board/{slug}/posts HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
응답 필드 (data 내부)
단건 응답: data 객체의 필드 (PostResource — 게시글 수정(PUT) 응답과 동일한 구조).
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| id | integer | 1 |
기본 키 (내부 식별자) |
| category | null | null |
게시글 분류(카테고리) 문자열. 게시판이 카테고리를 쓰지 않거나 미지정 시 null (최대 50자). |
| author | object | {"uuid":"a234c2b1-…","name":"API 문서 샘플 사용자"} |
작성자 사용자 객체 (uuid/name — author 관계 파생) |
| is_notice | boolean | false |
공지 게시글 여부 |
| is_secret | boolean | false |
비밀글 여부 |
| content_mode | string | html |
본문 편집 모드. html(위지윅/HTML) 또는 text(평문). |
| is_new | boolean | true |
신규(NEW) 표시 대상 여부 (게시판 new_display_hours 기준) |
| status | string | published |
게시글 상태 코드. published / blinded / deleted 중 하나. |
| status_label | string | 게시됨 |
상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
| view_count | integer | 0 |
조회수 (집계) |
| comment_count | integer | 0 |
댓글 수 (집계) |
| reply_count | integer | 0 |
답변글 수 (집계) |
| attachment_count | integer | 0 |
첨부파일 수 (집계) |
| has_attachment | boolean | false |
첨부파일 보유 여부 |
| thumbnail | null | null |
썸네일 이미지 URL/경로 (없으면 null) |
| parent_id | null | null |
원글 ID (답변글일 때만 값 존재) |
| depth | integer | 0 |
계층 트리에서의 깊이 (0 = 최상위) |
| is_reply | boolean | false |
답변글 여부 |
| created_at | string | 2026-07-08 10:41:34 |
생성 일시 |
| created_at_formatted | string | 방금 전 |
created_at 값의 표시용 포맷 문자열 |
| is_author | boolean | true |
현재 사용자가 작성자인지 여부 |
| is_guest_post | boolean | false |
비회원 작성 게시글 여부 |
| title | string | API 문서 샘플 게시글 |
제목 |
| content | string | <p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p> |
본문 내용 |
| user_id | string | a234c2b1-cde8-437f-b28b-23323be2b98d |
작성자 사용자 식별자 |
| trigger_type | string | user |
상태 변경을 유발한 주체 (report/admin/system/auto_hide/user/cascade) |
| updated_at | string | 2026-07-08 10:41:34 |
최종 수정 일시 |
| deleted_at | null | null |
소프트 삭제 일시 (미삭제 시 null) |
| ip_address | string | 127.0.0.1 |
작성 요청이 발생한 IP 주소 |
| action_logs | array | [] |
블라인드/복원/삭제 처리 이력 목록. admin.manage 권한 보유자에게만 노출. |
| board | null | null |
소속 게시판 정보 객체. board 관계 미로드 시 null. |
| navigation | null | null |
이전/다음 게시글 이동 정보. 쓰기 응답에서는 계산하지 않아 null. |
| parent | null | null |
원글 객체 (parent 관계 파생) |
| comments | null | null |
댓글 목록. comments 관계 미로드 시 null. |
| attachments | null | null |
첨부파일 목록. attachments 관계 미로드 시 null. |
| replies | null | null |
답변글 목록. replies 관계 미로드 시 null. |
| is_already_reported | boolean | false |
현재 사용자가 이미 신고한 게시글인지 여부 |
| is_owner | boolean | true |
현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
| abilities | object | {"can_read":true,"can_write":true,…} |
현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 |
응답 예시
HTTP/1.1 201
{
"success": true,
"message": "게시글이 등록되었습니다.",
"data": {
"id": 1,
"category": null,
"author": {
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"name": "API 문서 샘플 사용자",
"email": "apidoc-sample-user@example.com",
"avatar": null,
"status": "active",
"status_label": "활성",
"is_guest": false
},
"is_notice": false,
"is_secret": false,
"content_mode": "html",
"is_new": true,
"status": "published",
"status_label": "게시됨",
"view_count": 0,
"comment_count": 0,
"reply_count": 0,
"attachment_count": 0,
"has_attachment": false,
"thumbnail": null,
"parent_id": null,
"depth": 0,
"is_reply": false,
"created_at": "2026-07-08 10:41:34",
"created_at_formatted": "방금 전",
"is_author": true,
"is_guest_post": false,
"title": "API 문서 샘플 게시글",
"content": "<p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p>",
"user_id": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"trigger_type": "user",
"updated_at": "2026-07-08 10:41:34",
"deleted_at": null,
"ip_address": "127.0.0.1",
"action_logs": [],
"board": null,
"navigation": null,
"parent": null,
"comments": null,
"attachments": null,
"replies": null,
"is_already_reported": false,
"is_owner": true,
"abilities": {
"can_read": true,
"can_write": true,
"can_read_secret": true,
"can_read_comments": true,
"can_write_comments": true,
"can_upload": true,
"can_download": true,
"can_manage": true
}
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.posts.write)이 없는 경우 |
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (error.errors 에 필드별 메시지). 제목/본문 길이, 금지 키워드, 작성 쿨다운, 원글(parent_id) 유효성 위반 포함 |
| 500 | Internal Server Error | 게시글 생성 처리 실패 (게시글 등록에 실패했습니다.) |
설명 게시판 관리자가 새 게시글을 작성합니다. auth:sanctum + admin + 게시판별 posts.write 권한이 필요하며, StorePostRequest 검증을 거친 값에 작성자(Auth::id())와 요청 IP가 자동으로 채워집니다. 업로드 파일과 첨부파일 ID 배열은 본문에서 분리되어 PostService::createPost()로 전달되고, 성공 시 생성된 게시글 리소스를 201로 반환합니다.
GET /api/modules/sirsoft-board/admin/board/{slug}/posts/form-data
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.form-data - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@getFormData - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.posts.write
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| post_id | query | integer | 아니오 | min 1 | post 식별자 |
| parent_id | query | integer | 아니오 | min 1 | parent 식별자 |
요청 예시
GET /api/modules/sirsoft-board/admin/board/{slug}/posts/form-data?post_id=1&parent_id=1 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
응답 필드 (data 내부)
단건 응답: data 객체의 필드.
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| title | string | `` | ���목 |
| content | string | `` | 본문 내용 |
| content_mode | string | text |
본문 편집 모드. html(위지윅/HTML) 또는 text(평문)이며, 폼 초기값은 text입니다. |
| category | null | null |
게시글 분류(카테고리) 문자열. 게시판이 카테고리를 쓰지 않거나 미지정 시 null (최대 50자). |
| is_notice | boolean | false |
notice 여부 |
| is_secret | boolean | false |
secret 여부 |
| parent_id | null | null |
parent 식별자 (연관 리소스 참조) |
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "게시글 폼 데이터를 조회했습니다.",
"data": {
"title": "",
"content": "",
"content_mode": "text",
"category": null,
"is_notice": false,
"is_secret": "{MASKED}",
"parent_id": null
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.posts.write)이 없는 경우 |
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (error.errors 에 필드별 메시지). 제목/본문 길이, 금지 키워드, 작성 쿨다운, 원글(parent_id) 유효성 위반 포함 |
설명 게시글 작성/수정/답변글 폼에 미리 채울 입력 데이터를 반환합니다. auth:sanctum + admin + 게시판별 posts.write 권한이 필요하며, 쿼리 파라미터에 따라 분기합니다. post_id가 있으면 기존 게시글 데이터(수정 모드), parent_id가 있으면 제목에 Re:를 붙이고 원글 카테고리·비밀글 여부를 물려받은 답변글 기본값(답글 허용 게시판만, 아니면 404), 둘 다 없으면 빈 폼(게시판 secret_mode가 always면 비밀글 기본값)을 돌려줍니다.
GET /api/modules/sirsoft-board/admin/board/{slug}/posts/form-meta
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.form-meta - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@getFormMeta - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.posts.write
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
요청 예시
GET /api/modules/sirsoft-board/admin/board/{slug}/posts/form-meta HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
응답 필드 (data 내부)
단건 응답: data 객체의 필드.
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| board | object | {"id":12,"name":"API 문서 샘플 게시판","slug":"apidoc-sample-boa… |
폼 화면 표시에 필요한 게시판 정보 객체(이름·슬러그·댓글/답글/비밀글 설정 등). 사용자 권한(abilities)과 함께 항상 포함됩니다. |
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "게시글 폼 메타 데이터를 조회했습니다.",
"data": {
"board": {
"id": 1,
"name": "API 문서 샘플 게시판",
"slug": "apidoc-sample-board",
"is_active": true,
"type": "basic",
"description": "",
"per_page": 20,
"per_page_mobile": 15,
"order_by": "created_at",
"order_direction": "DESC",
"categories": [],
"show_view_count": true,
"secret_mode": "{MASKED}",
"use_comment": true,
"use_reply": true,
"max_reply_depth": 5,
"use_report": true,
"comment_order": "ASC",
"max_comment_depth": 10,
"min_title_length": 2,
"max_title_length": 200,
"min_content_length": 10,
"max_content_length": 10000,
"min_comment_length": 2,
"max_comment_length": 1000,
"blocked_keywords": [],
"use_file_upload": true,
"max_file_size": 10,
"max_file_count": 5,
"allowed_extensions": [
"jpg",
"jpeg",
"png",
"gif",
"pdf",
"zip"
],
"add_to_menu": null,
"new_display_hours": 24,
"board_managers": [],
"board_steps": [],
"board_manager_ids": [],
"board_step_ids": [],
"notify_author": true,
"notify_admin_on_post": true,
"created_at": "2026-07-08 10:41:34",
"updated_at": "2026-07-08 10:41:34",
"permissions": null,
"category_post_counts": null,
"posts_count": 0,
"user_abilities": {
"can_read": true,
"can_write": true,
"can_read_secret": "{MASKED}",
"can_read_comments": true,
"can_write_comments": true,
"can_upload": true,
"can_download": true,
"can_manage": true
},
"abilities": {
"can_create": true,
"can_update": true,
"can_delete": true
}
}
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.posts.write)이 없는 경우 |
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
설명 게시글 폼 화면 표시용 메타 데이터(읽기 전용)를 반환합니다. auth:sanctum + admin + 게시판별 posts.write 권한이 필요하며, 게시판 정보와 사용자 권한(abilities)을 항상 포함합니다. post_id가 있으면 작성자·작성일·첨부파일과 원글 정보를 덧붙이고(수정 모드), parent_id가 있으면 원글 정보를 포함하되 블라인드/삭제된 원글에는 답글 작성이 차단됩니다(각각 403).
DELETE /api/modules/sirsoft-board/admin/board/{slug}/posts/{id}
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.destroy - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@destroy - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.posts.write|sirsoft-board.{slug}.admin.manage
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| id | path | string | 예 | — | 대상 리소스의 식별자 |
요청 예시
DELETE /api/modules/sirsoft-board/admin/board/{slug}/posts/{id} HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
응답 필드 (data 내부)
단건 응답: data 객체의 필드.
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| id | integer | 1 |
기본 키 (내부 식별자) |
| category | null | null |
게시글 분류(카테고리) 문자열. 게시판이 카테고리를 쓰지 않거나 미지정 시 null (최대 50자). |
| author | object | {"uuid":"a234c2b1-cde8-437f-b28b-23323be2b98d","name":"AP… |
작성자 사용자 객체 (uuid/name — author 관계 파생) |
| is_notice | boolean | false |
notice 여부 |
| is_secret | boolean | false |
secret 여부 |
| content_mode | string | html |
본문 편집 모드. html(위지윅/HTML) 또는 text(평문)이며, 요약·썸네일 추출과 렌더링 방식을 결정합니다. 미지정 시 text. |
| is_new | boolean | true |
new 여부 |
| status | string | deleted |
상태 값 (도메인별 상태 집합 — 사람이 읽는 라벨은 status_label, UI 변형은 status_variant 참조) |
| status_label | string | 삭제됨 |
상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
| view_count | integer | 43 |
view 개수 (집계) |
| comment_count | integer | 0 |
comment 개수 (집계) |
| reply_count | integer | 0 |
reply 개수 (집계) |
| attachment_count | integer | 0 |
attachment 개수 (집계) |
| has_attachment | boolean | false |
attachment 여부 |
| thumbnail | null | null |
썸네일 이미지 URL/경로 |
| parent_id | null | null |
parent 식별자 (연관 리소스 참조) |
| depth | integer | 0 |
계층 트리에서의 깊이 (0 = 최상위, 하위로 갈수록 증가) |
| is_reply | boolean | false |
reply 여부 |
| created_at | string | 2026-07-08 10:41:34 |
생성 일시 |
| created_at_formatted | string | 4시간 전 |
created_at 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
| is_author | boolean | true |
author 여부 |
| is_guest_post | boolean | false |
guest post 여부 |
| title | string | API 문서 샘플 게시글 |
제목 |
| content | string | <p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p> |
본문 내용 |
| user_id | string | a234c2b1-cde8-437f-b28b-23323be2b98d |
user 식별자 (연관 리소스 참조) |
| trigger_type | string | admin |
동작을 유발한 방식/주체 구분 값 |
| updated_at | string | 2026-07-08 15:01:43 |
최종 수정 일시 |
| deleted_at | string | 2026-07-08 15:01:43 |
소프트 삭제 일시 (미삭제 시 null) |
| ip_address | string | 127.0.0.1 |
요청/행위가 발생한 IP 주소 |
| action_logs | array | [{"action":"delete","reason":null,"admin_name":"API 문서 샘플… |
블라인드/복원/삭제 등 처리 이력 목록(항목별 action·reason·admin_name·created_at). admin.manage 권한 보유자에게만 노출되며, 민감 필드(admin_id·ip_address)는 제외됩니다. 비권한자에게는 null. |
| board | null | null |
소속 게시판 정보 객체(슬러그·이름·유형·댓글/답글/신고 사용 여부·조회수 표시·최대 답글/댓글 깊이·신고 사유 목록). board 관계가 로드된 경우에만 채워지며, 아니면 null. |
| navigation | null | null |
이전/다음 게시글 이동 정보(prev·next). 상세 로드 시 계산되며, 쓰기 응답처럼 인접 게시글을 계산하지 않은 경우 null. |
| parent | null | null |
상위 항목 객체 (parent 관계 파생) |
| comments | null | null |
게시글에 달린 댓글 목록(CommentResource 컬렉션). comments 관계가 로드된 경우에만 채워지며, 아니면 null. |
| attachments | null | null |
게시글 첨부파일 목록(AttachmentResource 컬렉션). attachments 관계가 로드된 경우에만 채워지며, 아니면 null(비밀글·삭제글은 권한에 따라 빈 배열 또는 연쇄 삭제분만 노출). |
| replies | null | null |
이 게시글에 달린 답변글 목록(PostResource 컬렉션, 재귀). replies 관계가 로드된 경우에만 채워지며, 아니면 null. |
| is_already_reported | boolean | false |
already reported 여부 |
| is_owner | boolean | true |
현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
| abilities | object | {"can_read":true,"can_write":true,"can_read_secret":true,… |
현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "게시글이 삭제되었습니다.",
"data": {
"id": 1,
"category": null,
"author": {
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"name": "API 문서 샘플 사용자",
"email": "apidoc-sample-user@example.com",
"avatar": null,
"status": "active",
"status_label": "활성",
"is_guest": false
},
"is_notice": false,
"is_secret": "{MASKED}",
"content_mode": "html",
"is_new": true,
"status": "deleted",
"status_label": "삭제됨",
"view_count": 43,
"comment_count": 0,
"reply_count": 0,
"attachment_count": 0,
"has_attachment": false,
"thumbnail": null,
"parent_id": null,
"depth": 0,
"is_reply": false,
"created_at": "2026-07-08 10:41:34",
"created_at_formatted": "4시간 전",
"is_author": true,
"is_guest_post": false,
"title": "API 문서 샘플 게시글",
"content": "<p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p>",
"user_id": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"trigger_type": "admin",
"updated_at": "2026-07-08 15:01:43",
"deleted_at": "2026-07-08 15:01:43",
"ip_address": "127.0.0.1",
"action_logs": [
{
"action": "delete",
"reason": null,
"admin_name": "API 문서 샘플 사용자",
"created_at": "2026-07-08 06:01:43"
}
],
"board": null,
"navigation": null,
"parent": null,
"comments": null,
"attachments": null,
"replies": null,
"is_already_reported": false,
"is_owner": true,
"abilities": {
"can_read": true,
"can_write": true,
"can_read_secret": "{MASKED}",
"can_read_comments": true,
"can_write_comments": true,
"can_upload": true,
"can_download": true,
"can_manage": true
}
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.posts.write|sirsoft-board.{slug}.admin.manage)이 없는 경우 |
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
| 422 | Unprocessable Entity | 게시판의 답글 삭제 정책(reply_delete_policy)이 block 이고 대상 글에 살아 있는 답글이 있는 경우 (답글이 달린 글은 삭제할 수 없습니다. 답글을 먼저 삭제해 주세요. — sirsoft-board::validation.post.delete.has_replies) |
설명 게시판 관리자가 게시글 1건을 소프트 삭제합니다. auth:sanctum + admin 인증이 필요하며, 라우트 권한은 posts.write 또는 manage입니다. 컨트롤러가 대상 게시글을 조회한 뒤 세분화된 권한 분기를 적용합니다: admin.manage는 모든 글(비회원 글 포함)을, admin.posts.write는 본인 글만 삭제할 수 있으며 이미 삭제된 글의 재처리는 admin.manage가 필요합니다. PostService::deletePost()가 'admin' 컨텍스트로 소프트 삭제를 수행합니다. 삭제 동작은 게시판의 답글 삭제 정책(reply_delete_policy)을 따릅니다 — cascade(기본)에서는 원글 삭제 시 살아 있는 답글 트리(및 그 답글들의 댓글·첨부)가 함께 소프트 삭제되고 이후 원글을 복원하면 연쇄 삭제분(trigger_type='cascade')만 선택 복원되며, block 에서는 살아 있는 직계 답글이 있으면 before_delete 훅 발화 전에 차단되어(부수효과 없음) 422 를 반환합니다.
GET /api/modules/sirsoft-board/admin/board/{slug}/posts/{id}
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.show - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@show - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.posts.read
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| id | path | string | 예 | — | 대상 리소스의 식별자 |
요청 예시
GET /api/modules/sirsoft-board/admin/board/{slug}/posts/{id} HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
응답 필드 (data 내부)
단건 응답: data 객체의 필드.
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| id | integer | 237 |
기본 키 (내부 식별자) |
| category | null | null |
게시글 분류(카테고리) 문자열. 게시판이 카테고리를 쓰지 않거나 미지정 시 null (최대 50자). |
| author | object | {"uuid":"a231747f-e82e-4cf2-9ae1-a261849dce40","name":"AP… |
작성자 사용자 객체 (uuid/name — author 관계 파생) |
| is_notice | boolean | false |
notice 여부 |
| is_secret | boolean | false |
secret 여부 |
| content_mode | string | html |
본문 편집 모드. html(위지윅/HTML) 또는 text(평문)이며, 요약·썸네일 추출과 렌더링 방식을 결정합니다. 미지정 시 text. |
| is_new | boolean | true |
new 여부 |
| status | string | published |
게시글 상태 코드. published(게시됨) / blinded(블라인드) / deleted(삭제됨) 중 하나이며, status_label이 사람이 읽는 라벨입니다. |
| status_label | string | 게시됨 |
상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
| view_count | integer | 43 |
view 개수 (집계) |
| comment_count | integer | 0 |
comment 개수 (집계) |
| reply_count | integer | 0 |
reply 개수 (집계) |
| attachment_count | integer | 0 |
attachment 개수 (집계) |
| has_attachment | boolean | false |
attachment 여부 |
| thumbnail | string | /api/modules/sirsoft-board/boards/api… |
썸네일 이미지 URL/경로 — /api/modules/sirsoft-board/boards/{slug}/attachment/{hash}/preview 형식 (첫 이미지 첨부의 미리보기 서빙 URL). 비밀글은 열람 권한이 없으면 null 로 내려간다(첨부 해시 노출 차단 — 필드 자체는 유지) |
| parent_id | null | null |
parent 식별자 (연관 리소스 참조) |
| depth | integer | 0 |
계층 트리에서의 깊이 (0 = 최상위, 하위로 갈수록 증가) |
| is_reply | boolean | false |
reply 여부 |
| created_at | string | 2026-07-07 09:34:50 |
생성 일시 |
| created_at_formatted | string | 4시간 전 |
created_at 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
| is_author | boolean | true |
author 여부 |
| is_guest_post | boolean | false |
guest post 여부 |
| title | string | API 문서 샘플 게시글 |
제목 |
| content | string | <p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p> |
본문 내용 |
| user_id | string | a231747f-e82e-4cf2-9ae1-a261849dce40 |
user 식별자 (연관 리소스 참조) |
| trigger_type | string | user |
상태 변경(삭제/블라인드 등)을 유발한 주체. report(신고) / admin(관리자 직권) / system(시스템) / auto_hide(신고 누적 자동 블라인드) / user(사용자 직접) / cascade(상위 삭제 연쇄) 중 하나입니다. |
| updated_at | string | 2026-07-07 09:39:03 |
최종 수정 일시 |
| deleted_at | null | null |
소프트 삭제 일시 (미삭제 시 null) |
| ip_address | string | 127.0.0.1 |
요청/행위가 발생한 IP 주소 |
| action_logs | array | [] |
블라인드/복원/삭제 등 처리 이력 목록(항목별 action·reason·admin_name·created_at). admin.manage 권한 보유자에게만 노출되며, 민감 필드(admin_id·ip_address)는 제외됩니다. 비권한자에게는 null. |
| board | object | {"slug":"apidoc-sample-board","name":"API 문서 샘플 게시판","typ… |
소속 게시판 정보 객체(슬러그·이름·유형·댓글/답글/신고 사용 여부·조회수 표시·최대 답글/댓글 깊이·신고 사유 목록). board 관계가 로드된 경우에만 채워지며, 아니면 null. |
| navigation | object | {"prev":null,"next":null} |
이전/다음 게시글 이동 정보. prev·next 키에 인접 게시글 요약(없으면 null)이 담기며, 상세 로드 시 함께 계산됩니다. |
| parent | null | null |
상위 항목 객체 (parent 관계 파생) |
| comments | array | [{"id":760,"post_id":237,"parent_id":null,"content":"API … |
게시글에 달린 댓글 목록(CommentResource 컬렉션). comments 관계가 로드된 경우에만 채워지며, 각 항목에 신고 여부가 사전 로드되어 담깁니다. |
| comments_truncated | boolean | false |
댓글 목록이 상한에서 끊겼는지 여부. true 면 comments 에 실린 것이 전부가 아닙니다 |
| comments_total | integer|null | 12 |
댓글 총 건수. 끊기지 않았으면 comments 길이와 같고, 끊겼으면 상한값(그 이상)입니다 |
| comments_total_is_exact | boolean | true |
위 총 건수가 정확한지 여부. false 면 "N건 이상" 으로 표기합니다 |
| attachments | array | [{"id":155,"hash":"apidocsmpl1","original_filename":"apid… |
게시글 첨부파일 목록(AttachmentResource 컬렉션). 비밀글은 열람 권한이 없으면 빈 배열, 삭제된 게시글은 관리 권한이 없으면 연쇄 삭제된 첨부만 노출됩니다. |
| replies | array | [] |
이 게시글에 달린 답변글 목록(PostResource 컬렉션, 재귀). replies 관계가 로드된 경우에만 채워지며, 아니면 null. |
| is_already_reported | boolean | false |
already reported 여부 |
| is_owner | boolean | true |
현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
| abilities | object | {"can_read":true,"can_write":true,"can_read_secret":true,… |
현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "게시글 목록을 조회했습니다.",
"data": {
"id": 1,
"category": null,
"author": {
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"name": "API 문서 샘플 사용자",
"email": "apidoc-sample-user@example.com",
"avatar": null,
"status": "active",
"status_label": "활성",
"is_guest": false
},
"is_notice": false,
"is_secret": "{MASKED}",
"content_mode": "html",
"is_new": true,
"status": "published",
"status_label": "게시됨",
"view_count": 44,
"comment_count": 0,
"reply_count": 0,
"attachment_count": 0,
"has_attachment": false,
"thumbnail": "/api/modules/sirsoft-board/boards/apidoc-sample-board/attachment/apidocsmpl1/preview",
"parent_id": null,
"depth": 0,
"is_reply": false,
"created_at": "2026-07-08 10:41:34",
"created_at_formatted": "4시간 전",
"is_author": true,
"is_guest_post": false,
"title": "API 문서 샘플 게시글",
"content": "<p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p>",
"user_id": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"trigger_type": "user",
"updated_at": "2026-07-08 15:01:44",
"deleted_at": null,
"ip_address": "127.0.0.1",
"action_logs": [],
"board": {
"slug": "apidoc-sample-board",
"name": "API 문서 샘플 게시판",
"type": "basic",
"use_comment": true,
"use_reply": true,
"use_report": true,
"show_view_count": true,
"max_reply_depth": 5,
"max_comment_depth": 10,
"report_types": [
{
"value": "abuse",
"label": "욕설/비방"
},
{
"value": "hate_speech",
"label": "혐오 발언"
},
{
"value": "spam",
"label": "스팸/광고"
},
{
"value": "copyright",
"label": "저작권 침해"
},
{
"value": "privacy",
"label": "개인정보 노출"
},
{
"value": "misinformation",
"label": "허위정보"
},
{
"value": "sexual",
"label": "성적인 콘텐츠"
},
{
"value": "violence",
"label": "폭력적인 콘텐츠"
},
{
"value": "other",
"label": "기타"
}
]
},
"navigation": {
"prev": null,
"next": null
},
"parent": null,
"comments": [
{
"id": 1,
"post_id": 1,
"parent_id": null,
"content": "API 문서 샘플 댓글입니다.",
"author": {
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"name": "API 문서 샘플 사용자",
"email": "apidoc-sample-user@example.com",
"avatar": null,
"status": "active",
"status_label": "활성",
"is_guest": false
},
"is_secret": "{MASKED}",
"status": "published",
"status_label": "게시됨",
"depth": 0,
"replies_count": 0,
"created_at": "2026-07-08 10:41:34",
"created_at_formatted": "4시간 전",
"updated_at": "2026-07-08 10:41:34",
"deleted_at": null,
"is_cascade_deleted": false,
"ip_address": null,
"action_logs": [],
"is_author": true,
"is_guest_comment": false,
"is_already_reported": false,
"is_owner": true,
"abilities": {
"can_read": true,
"can_write": true,
"can_manage": true
}
}
],
"attachments": [
{
"id": 1,
"hash": "apidocsmpl1",
"original_filename": "apidoc-sample.png",
"mime_type": "image/png",
"size": 2048,
"size_formatted": "2 KB",
"collection": "default",
"order": 0,
"download_url": "/api/modules/sirsoft-board/boards/apidoc-sample-board/attachment/apidocsmpl1",
"preview_url": "/api/modules/sirsoft-board/boards/apidoc-sample-board/attachment/apidocsmpl1/preview",
"is_image": true,
"meta": null
}
],
"replies": [],
"is_already_reported": false,
"is_owner": true,
"abilities": {
"can_read": true,
"can_write": true,
"can_read_secret": "{MASKED}",
"can_read_comments": true,
"can_write_comments": true,
"can_upload": true,
"can_download": true,
"can_manage": true
}
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.posts.read)이 없는 경우 |
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
설명 게시판 관리자가 게시글 상세를 조회합니다. auth:sanctum + admin + 게시판별 posts.read 권한이 필요하며, 삭제된 게시글은 admin.manage 권한이 있어야 열람할 수 있습니다(없으면 403). PostService::loadPostDetail()이 조회수 증가·댓글·이전/다음 게시글까지 로드하며, 응답에는 댓글별 신고 여부를 N+1 없이 일괄 사전 로드해 담습니다.
PUT /api/modules/sirsoft-board/admin/board/{slug}/posts/{id}
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.update - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@update - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.posts.write
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| id | path | string | 예 | — | 대상 리소스의 식별자 |
이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (
sirsoft-board.post.update_validation_rules).
요청 예시
PUT /api/modules/sirsoft-board/admin/board/{slug}/posts/{id} HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
응답 필드 (data 내부)
단건 응답: data 객체의 필드.
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| id | integer | 1 |
기본 키 (내부 식별자) |
| category | null | null |
게시글 분류(카테고리) 문자열. 게시판이 카테고리를 쓰지 않거나 미지정 시 null (최대 50자). |
| author | object | {"uuid":"a234c2b1-cde8-437f-b28b-23323be2b98d","name":"AP… |
작성자 사용자 객체 (uuid/name — author 관계 파생) |
| is_notice | boolean | false |
notice 여부 |
| is_secret | boolean | false |
secret 여부 |
| content_mode | string | html |
본문 편집 모드. html(위지윅/HTML) 또는 text(평문)이며, 요약·썸네일 추출과 렌더링 방식을 결정합니다. 미지정 시 text. |
| is_new | boolean | true |
new 여부 |
| status | string | published |
상태 값 (도메인별 상태 집합 — 사람이 읽는 라벨은 status_label, UI 변형은 status_variant 참조) |
| status_label | string | 게시됨 |
상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
| view_count | integer | 44 |
view 개수 (집계) |
| comment_count | integer | 0 |
comment 개수 (집계) |
| reply_count | integer | 0 |
reply 개수 (집계) |
| attachment_count | integer | 0 |
attachment 개수 (집계) |
| has_attachment | boolean | false |
attachment 여부 |
| thumbnail | null | null |
썸네일 이미지 URL/경로 |
| parent_id | null | null |
parent 식별자 (연관 리소스 참조) |
| depth | integer | 0 |
계층 트리에서의 깊이 (0 = 최상위, 하위로 갈수록 증가) |
| is_reply | boolean | false |
reply 여부 |
| created_at | string | 2026-07-08 10:41:34 |
생성 일시 |
| created_at_formatted | string | 4시간 전 |
created_at 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
| is_author | boolean | true |
author 여부 |
| is_guest_post | boolean | false |
guest post 여부 |
| title | string | API 문서 샘플 게시글 |
제목 |
| content | string | <p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p> |
본문 내용 |
| user_id | string | a234c2b1-cde8-437f-b28b-23323be2b98d |
user 식별자 (연관 리소스 참조) |
| trigger_type | string | user |
동작을 유발한 방식/주체 구분 값 |
| updated_at | string | 2026-07-08 15:01:44 |
최종 수정 일시 |
| deleted_at | null | null |
소프트 삭제 일시 (미삭제 시 null) |
| ip_address | string | 127.0.0.1 |
요청/행위가 발생한 IP 주소 |
| action_logs | array | [] |
블라인드/복원/삭제 등 처리 이력 목록(항목별 action·reason·admin_name·created_at). admin.manage 권한 보유자에게만 노출되며, 민감 필드(admin_id·ip_address)는 제외됩니다. 비권한자에게는 null. |
| board | null | null |
소속 게시판 정보 객체(슬러그·이름·유형·댓글/답글/신고 사용 여부·조회수 표시·최대 답글/댓글 깊이·신고 사유 목록). board 관계가 로드된 경우에만 채워지며, 아니면 null. |
| navigation | null | null |
이전/다음 게시글 이동 정보(prev·next). 상세 로드 시 계산되며, 쓰기 응답처럼 인접 게시글을 계산하지 않은 경우 null. |
| parent | null | null |
상위 항목 객체 (parent 관계 파생) |
| comments | null | null |
게시글에 달린 댓글 목록(CommentResource 컬렉션). comments 관계가 로드된 경우에만 채워지며, 아니면 null. |
| attachments | null | null |
게시글 첨부파일 목록(AttachmentResource 컬렉션). attachments 관계가 로드된 경우에만 채워지며, 아니면 null(비밀글·삭제글은 권한에 따라 빈 배열 또는 연쇄 삭제분만 노출). |
| replies | null | null |
이 게시글에 달린 답변글 목록(PostResource 컬렉션, 재귀). replies 관계가 로드된 경우에만 채워지며, 아니면 null. |
| is_already_reported | boolean | false |
already reported 여부 |
| is_owner | boolean | true |
현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
| abilities | object | {"can_read":true,"can_write":true,"can_read_secret":true,… |
현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "게시글이 수정되었습니다.",
"data": {
"id": 1,
"category": null,
"author": {
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"name": "API 문서 샘플 사용자",
"email": "apidoc-sample-user@example.com",
"avatar": null,
"status": "active",
"status_label": "활성",
"is_guest": false
},
"is_notice": false,
"is_secret": "{MASKED}",
"content_mode": "html",
"is_new": true,
"status": "published",
"status_label": "게시됨",
"view_count": 44,
"comment_count": 0,
"reply_count": 0,
"attachment_count": 0,
"has_attachment": false,
"thumbnail": null,
"parent_id": null,
"depth": 0,
"is_reply": false,
"created_at": "2026-07-08 10:41:34",
"created_at_formatted": "4시간 전",
"is_author": true,
"is_guest_post": false,
"title": "API 문서 샘플 게시글",
"content": "<p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p>",
"user_id": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"trigger_type": "user",
"updated_at": "2026-07-08 15:01:44",
"deleted_at": null,
"ip_address": "127.0.0.1",
"action_logs": [],
"board": null,
"navigation": null,
"parent": null,
"comments": null,
"attachments": null,
"replies": null,
"is_already_reported": false,
"is_owner": true,
"abilities": {
"can_read": true,
"can_write": true,
"can_read_secret": "{MASKED}",
"can_read_comments": true,
"can_write_comments": true,
"can_upload": true,
"can_download": true,
"can_manage": true
}
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.posts.write)이 없는 경우 |
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (error.errors 에 필드별 메시지) |
설명 게시판 관리자가 게시글을 수정합니다. auth:sanctum + admin + 게시판별 posts.write 권한이 필요하며, 컨트롤러가 대상 게시글을 조회한 뒤 세분화된 권한을 적용합니다: 일반 글은 admin.manage(타인 글) 또는 admin.write(본인 글), 이미 삭제된 글은 admin.manage가 필요합니다. UpdatePostRequest 검증 값에서 첨부파일 ID 배열을 분리해 PostService::updatePost()로 전달하고, 갱신된 게시글 리소스를 반환합니다.
PATCH /api/modules/sirsoft-board/admin/board/{slug}/posts/{id}/blind
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.blind - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@blind - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.manage
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| id | path | string | 예 | — | 대상 리소스의 식별자 |
| reason | body | string | 아니오 | max 1000 | 블라인드 처리 사유(최대 1000자). 처리 이력(action_logs)에 기록되며, 미지정 시 빈 문자열로 저장됩니다. |
요청 예시
PATCH /api/modules/sirsoft-board/admin/board/{slug}/posts/{id}/blind HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
Content-Type: application/json
{
"reason": "예시값"
}
응답 필드 (data 내부)
단건 응답: data 객체의 필드.
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| id | integer | 1 |
기본 키 (내부 식별자) |
| category | null | null |
게시글 분류(카테고리) 문자열. 게시판이 카테고리를 쓰지 않거나 미지정 시 null (최대 50자). |
| author | object | {"uuid":"a234c2b1-cde8-437f-b28b-23323be2b98d","name":"AP… |
작성자 사용자 객체 (uuid/name — author 관계 파생) |
| is_notice | boolean | false |
notice 여부 |
| is_secret | boolean | false |
secret 여부 |
| content_mode | string | html |
본문 편집 모드. html(위지윅/HTML) 또는 text(평문)이며, 요약·썸네일 추출과 렌더링 방식을 결정합니다. 미지정 시 text. |
| is_new | boolean | true |
new 여부 |
| status | string | blinded |
상태 값 (도메인별 상태 집합 — 사람이 읽는 라벨은 status_label, UI 변형은 status_variant 참조) |
| status_label | string | 블라인드 |
상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
| view_count | integer | 44 |
view 개수 (집계) |
| comment_count | integer | 0 |
comment 개수 (집계) |
| reply_count | integer | 0 |
reply 개수 (집계) |
| attachment_count | integer | 0 |
attachment 개수 (집계) |
| has_attachment | boolean | false |
attachment 여부 |
| thumbnail | null | null |
썸네일 이미지 URL/경로 |
| parent_id | null | null |
parent 식별자 (연관 리소스 참조) |
| depth | integer | 0 |
계층 트리에서의 깊이 (0 = 최상위, 하위로 갈수록 증가) |
| is_reply | boolean | false |
reply 여부 |
| created_at | string | 2026-07-08 10:41:34 |
생성 일시 |
| created_at_formatted | string | 4시간 전 |
created_at 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
| is_author | boolean | true |
author 여부 |
| is_guest_post | boolean | false |
guest post 여부 |
| title | string | API 문서 샘플 게시글 |
제목 |
| content | string | <p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p> |
본문 내용 |
| user_id | string | a234c2b1-cde8-437f-b28b-23323be2b98d |
user 식별자 (연관 리소스 참조) |
| trigger_type | string | user |
동작을 유발한 방식/주체 구분 값 |
| updated_at | string | 2026-07-08 15:01:44 |
최종 수정 일시 |
| deleted_at | null | null |
소프트 삭제 일시 (미삭제 시 null) |
| ip_address | string | 127.0.0.1 |
요청/행위가 발생한 IP 주소 |
| action_logs | array | [{"action":"blind","reason":"실측 예시값","admin_name":"API 문서… |
블라인드/복원/삭제 등 처리 이력 목록(항목별 action·reason·admin_name·created_at). admin.manage 권한 보유자에게만 노출되며, 민감 필드(admin_id·ip_address)는 제외됩니다. 비권한자에게는 null. |
| board | null | null |
소속 게시판 정보 객체(슬러그·이름·유형·댓글/답글/신고 사용 여부·조회수 표시·최대 답글/댓글 깊이·신고 사유 목록). board 관계가 로드된 경우에만 채워지며, 아니면 null. |
| navigation | null | null |
이전/다음 게시글 이동 정보(prev·next). 상세 로드 시 계산되며, 쓰기 응답처럼 인접 게시글을 계산하지 않은 경우 null. |
| parent | null | null |
상위 항목 객체 (parent 관계 파생) |
| comments | null | null |
게시글에 달린 댓글 목록(CommentResource 컬렉션). comments 관계가 로드된 경우에만 채워지며, 아니면 null. |
| attachments | null | null |
게시글 첨부파일 목록(AttachmentResource 컬렉션). attachments 관계가 로드된 경우에만 채워지며, 아니면 null(비밀글·삭제글은 권한에 따라 빈 배열 또는 연쇄 삭제분만 노출). |
| replies | null | null |
이 게시글에 달린 답변글 목록(PostResource 컬렉션, 재귀). replies 관계가 로드된 경우에만 채워지며, 아니면 null. |
| is_already_reported | boolean | false |
already reported 여부 |
| is_owner | boolean | true |
현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
| abilities | object | {"can_read":true,"can_write":true,"can_read_secret":true,… |
현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "게시글이 블라인드 처리되었습니다.",
"data": {
"id": 1,
"category": null,
"author": {
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"name": "API 문서 샘플 사용자",
"email": "apidoc-sample-user@example.com",
"avatar": null,
"status": "active",
"status_label": "활성",
"is_guest": false
},
"is_notice": false,
"is_secret": "{MASKED}",
"content_mode": "html",
"is_new": true,
"status": "blinded",
"status_label": "블라인드",
"view_count": 44,
"comment_count": 0,
"reply_count": 0,
"attachment_count": 0,
"has_attachment": false,
"thumbnail": null,
"parent_id": null,
"depth": 0,
"is_reply": false,
"created_at": "2026-07-08 10:41:34",
"created_at_formatted": "4시간 전",
"is_author": true,
"is_guest_post": false,
"title": "API 문서 샘플 게시글",
"content": "<p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p>",
"user_id": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"trigger_type": "user",
"updated_at": "2026-07-08 15:01:44",
"deleted_at": null,
"ip_address": "127.0.0.1",
"action_logs": [
{
"action": "blind",
"reason": "실측 예시값",
"admin_name": "API 문서 샘플 사용자",
"created_at": "2026-07-08 06:01:44"
}
],
"board": null,
"navigation": null,
"parent": null,
"comments": null,
"attachments": null,
"replies": null,
"is_already_reported": false,
"is_owner": true,
"abilities": {
"can_read": true,
"can_write": true,
"can_read_secret": "{MASKED}",
"can_read_comments": true,
"can_write_comments": true,
"can_upload": true,
"can_download": true,
"can_manage": true
}
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.manage)이 없는 경우 |
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (error.errors 에 필드별 메시지) |
설명 게시판 관리자가 게시글을 블라인드 처리합니다. auth:sanctum + admin + 게시판별 admin.manage 권한이 필요하며, 선택적 reason(최대 1000자)을 사유로 받아 PostService::blindPost()가 게시글 상태를 블라인드로 전환합니다. 소프트 삭제와 달리 게시글을 숨기되 관리 목적으로 보존하는 처리이며, 복원(restore)으로 되돌릴 수 있습니다.
PATCH /api/modules/sirsoft-board/admin/board/{slug}/posts/{id}/restore
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.restore - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@restore - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.manage
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| id | path | string | 예 | — | 대상 리소스의 식별자 |
| reason | body | string | 아니오 | max 1000 | 블라인드 복원 사유(최대 1000자). 처리 이력(action_logs)에 기록되며, 미지정 시 null로 전달됩니다. |
요청 예시
PATCH /api/modules/sirsoft-board/admin/board/{slug}/posts/{id}/restore HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
Content-Type: application/json
{
"reason": "예시값"
}
응답 필드 (data 내부)
단건 응답: data 객체의 필드 (PostResource — 복원된 게시글. 게시글 수정(PUT) 응답과 동일한 구조이며, status 가 published 로 되돌아가고 action_logs 에 restore 이력이 1건 추가됩니다).
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| id | integer | 1 |
기본 키 (내부 식별자) |
| category | null | null |
게시글 분류(카테고리) 문자열 (미지정 시 null) |
| author | object | {"uuid":"a234c2b1-…","name":"API 문서 샘플 사용자"} |
작성자 사용자 객체 (uuid/name — author 관계 파생) |
| is_notice | boolean | false |
공지 게시글 여부 |
| is_secret | boolean | false |
비밀글 여부 |
| content_mode | string | html |
본문 편집 모드 (html / text) |
| is_new | boolean | true |
신규(NEW) 표시 대상 여부 |
| status | string | published |
복원 후 게시글 상태 (published 로 되돌아감) |
| status_label | string | 게시됨 |
상태의 사람이 읽는 라벨 |
| view_count | integer | 44 |
조회수 (집계) |
| comment_count | integer | 0 |
댓글 수 (집계) |
| reply_count | integer | 0 |
답변글 수 (집계) |
| attachment_count | integer | 0 |
첨부파일 수 (집계) |
| has_attachment | boolean | false |
첨부파일 보유 여부 |
| thumbnail | null | null |
썸네일 이미지 URL/경로 |
| parent_id | null | null |
원글 ID (답변글일 때만 값 존재) |
| depth | integer | 0 |
계층 트리에서의 깊이 |
| is_reply | boolean | false |
답변글 여부 |
| created_at | string | 2026-07-08 10:41:34 |
생성 일시 |
| created_at_formatted | string | 4시간 전 |
created_at 값의 표시용 포맷 문자열 |
| is_author | boolean | true |
현재 사용자가 작성자인지 여부 |
| is_guest_post | boolean | false |
비회원 작성 게시글 여부 |
| title | string | API 문서 샘플 게시글 |
제목 |
| content | string | <p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p> |
본문 내용 |
| user_id | string | a234c2b1-cde8-437f-b28b-23323be2b98d |
작성자 사용자 식별자 |
| trigger_type | string | admin |
상태 변경을 유발한 주체 (복원은 관리자 직권이므로 admin) |
| updated_at | string | 2026-07-08 15:01:45 |
최종 수정 일시 |
| deleted_at | null | null |
소프트 삭제 일시 (복원 후 null) |
| ip_address | string | 127.0.0.1 |
작성 요청이 발생한 IP 주소 |
| action_logs | array | [{"action":"restore","reason":null,"admin_name":"API 문서 샘플 사용자","created_at":"2026-07-08 06:01:45"}] |
블라인드/복원/삭제 처리 이력 목록. admin.manage 권한 보유자에게만 노출. |
| board | null | null |
소속 게시판 정보 객체 (관계 미로드 시 null) |
| navigation | null | null |
이전/다음 게시글 이동 정보 (쓰기 응답은 미계산 → null) |
| parent | null | null |
원글 객체 (parent 관계 파생) |
| comments | null | null |
댓글 목록 (관계 미로드 시 null) |
| attachments | null | null |
첨부파일 목록 (관계 미로드 시 null) |
| replies | null | null |
답변글 목록 (관계 미로드 시 null) |
| is_already_reported | boolean | false |
현재 사용자가 이미 신고한 게시글인지 여부 |
| is_owner | boolean | true |
현재 인증 사용자가 이 리소스의 소유자인지 여부 |
| abilities | object | {"can_read":true,"can_write":true,…} |
현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 |
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "게시글이 복원되었습니다.",
"data": {
"id": 1,
"category": null,
"author": {
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"name": "API 문서 샘플 사용자",
"email": "apidoc-sample-user@example.com",
"avatar": null,
"status": "active",
"status_label": "활성",
"is_guest": false
},
"is_notice": false,
"is_secret": false,
"content_mode": "html",
"is_new": true,
"status": "published",
"status_label": "게시됨",
"view_count": 44,
"comment_count": 0,
"reply_count": 0,
"attachment_count": 0,
"has_attachment": false,
"thumbnail": null,
"parent_id": null,
"depth": 0,
"is_reply": false,
"created_at": "2026-07-08 10:41:34",
"created_at_formatted": "4시간 전",
"is_author": true,
"is_guest_post": false,
"title": "API 문서 샘플 게시글",
"content": "<p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p>",
"user_id": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"trigger_type": "admin",
"updated_at": "2026-07-08 15:01:45",
"deleted_at": null,
"ip_address": "127.0.0.1",
"action_logs": [
{
"action": "restore",
"reason": null,
"admin_name": "API 문서 샘플 사용자",
"created_at": "2026-07-08 06:01:45"
}
],
"board": null,
"navigation": null,
"parent": null,
"comments": null,
"attachments": null,
"replies": null,
"is_already_reported": false,
"is_owner": true,
"abilities": {
"can_read": true,
"can_write": true,
"can_read_secret": true,
"can_read_comments": true,
"can_write_comments": true,
"can_upload": true,
"can_download": true,
"can_manage": true
}
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.manage)이 없는 경우 |
| 404 | Not Found | 슬러그에 해당하는 게시판 또는 ID 에 해당하는 게시글이 없는 경우 (존재하지 않는 게시글입니다.) |
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (reason 이 1000자를 초과하는 등) |
| 500 | Internal Server Error | 복원 처리 실패 (게시글 복원에 실패했습니다.) |
설명 게시판 관리자가 블라인드 처리된 게시글을 복원합니다. auth:sanctum + admin + 게시판별 admin.manage 권한이 필요하며, 선택적 reason(최대 1000자)을 사유로 받아 PostService::restorePost()가 블라인드 상태를 해제해 게시글을 다시 노출합니다.
POST /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.comments.store - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\CommentController@store - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.comments.write
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| postId | path | string | 예 | — | 대상 post의 식별자 |
이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (
sirsoft-board.comment.store_validation_rules).
요청 예시
POST /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
응답 필드 (data 내부)
단건 응답: data 객체의 필드 (CommentResource).
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| id | integer | 1 |
댓글 기본 키 (내부 식별자) |
| post_id | integer | 1 |
댓글이 속한 게시글 식별자 |
| parent_id | null | null |
상위 댓글 식별자 (대댓글일 때만 값 존재) |
| content | string | API 문서 샘플 댓글입니다. |
댓글 본문 내용 |
| author | object | {"uuid":"a234c2b1-…","name":"API 문서 샘플 사용자"} |
작성자 사용자 객체 (author 관계 파생) |
| is_secret | boolean | false |
비밀 댓글 여부 |
| status | string | published |
댓글 상태 코드 (published / blinded / deleted) |
| status_label | string | 게시됨 |
상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
| depth | integer | 0 |
댓글 계층 깊이 (0 = 최상위 댓글, 서비스에서 자동 계산) |
| replies_count | integer | 0 |
이 댓글에 달린 대댓글 수 (집계) |
| created_at | string | 2026-07-08 10:41:34 |
생성 일시 |
| created_at_formatted | string | 방금 전 |
created_at 값의 표시용 포맷 문자열 |
| updated_at | string | 2026-07-08 10:41:34 |
최종 수정 일시 |
| deleted_at | null | null |
소프트 삭제 일시 (미삭제 시 null) |
| is_cascade_deleted | boolean | false |
상위 게시글/댓글 삭제로 연쇄 삭제된 댓글인지 여부 |
| ip_address | string | 127.0.0.1 |
작성 요청이 발생한 IP 주소 (권한자에게만 노출) |
| action_logs | array | [] |
블라인드/복원/삭제 처리 이력 목록. admin.manage 권한 보유자에게만 노출. |
| is_author | boolean | true |
현재 사용자가 작성자인지 여부 |
| is_guest_comment | boolean | false |
비회원 작성 댓글 여부 |
| is_already_reported | boolean | false |
현재 사용자가 이미 신고한 댓글인지 여부 |
| is_owner | boolean | true |
현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
| abilities | object | {"can_read":true,"can_write":true,"can_manage":true} |
현재 사용자가 이 댓글에 수행 가능한 작업 불리언 맵 |
응답 예시
HTTP/1.1 201
{
"success": true,
"message": "댓글이 등록되었습니다.",
"data": {
"id": 1,
"post_id": 1,
"parent_id": null,
"content": "API 문서 샘플 댓글입니다.",
"author": {
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"name": "API 문서 샘플 사용자",
"email": "apidoc-sample-user@example.com",
"avatar": null,
"status": "active",
"status_label": "활성",
"is_guest": false
},
"is_secret": false,
"status": "published",
"status_label": "게시됨",
"depth": 0,
"replies_count": 0,
"created_at": "2026-07-08 10:41:34",
"created_at_formatted": "방금 전",
"updated_at": "2026-07-08 10:41:34",
"deleted_at": null,
"is_cascade_deleted": false,
"ip_address": "127.0.0.1",
"action_logs": [],
"is_author": true,
"is_guest_comment": false,
"is_already_reported": false,
"is_owner": true,
"abilities": {
"can_read": true,
"can_write": true,
"can_manage": true
}
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.comments.write)이 없거나, 게시판의 댓글 기능이 꺼진 경우 (이 게시판은 댓글 기능이 비활성화되어 있습니다.) |
| 404 | Not Found | 슬러그에 해당하는 게시판이 없는 경우 (게시판을 찾을 수 없습니다.) |
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (error.errors 에 필드별 메시지). 댓글 길이, 금지 키워드, 작성 쿨다운, 대상 게시글·상위 댓글 유효성 위반 포함 |
| 500 | Internal Server Error | 댓글 생성 처리 실패 (댓글 등록에 실패했습니다.) |
설명 게시판 관리자가 특정 게시글에 댓글을 작성합니다. auth:sanctum + admin + 게시판별 comments.write 권한이 필요하며, 게시판의 use_comment가 꺼져 있으면 403으로 차단됩니다. 검증된 값에 게시글 ID·작성자(Auth::id())·요청 IP가 자동으로 채워져 CommentService::createComment()로 전달되고, 성공 시 생성된 댓글 리소스를 201로 반환합니다.
DELETE /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments/{id}
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.comments.destroy - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\CommentController@destroy - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.comments.write|sirsoft-board.{slug}.admin.manage
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| postId | path | string | 예 | — | 대상 post의 식별자 |
| id | path | string | 예 | — | 대상 리소스의 식별자 |
요청 예시
DELETE /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments/{id} HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
응답 필드 (data 내부)
이 엔드포인트는 data 를 반환하지 않습니다 (성공 메시지만 — data 는 null).
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "댓글이 삭제되었습니다.",
"data": null
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.comments.write|sirsoft-board.{slug}.admin.manage)이 없거나, 타인/비회원 댓글을 admin.manage 없이 삭제하려는 경우(접근 권한이 없습니다.), 게시판의 댓글 기능이 꺼진 경우(이 게시판은 댓글 기능이 비활성화되어 있습니다.) |
| 404 | Not Found | ID 에 해당하는 댓글 또는 슬러그에 해당하는 게시판이 없는 경우 (댓글을 찾을 수 없습니다.) |
| 500 | Internal Server Error | 삭제 처리 실패 (댓글 삭제에 실패했습니다.) |
설명 게시판 관리자가 댓글 1건을 삭제합니다. auth:sanctum + admin 인증이 필요하며, 라우트 권한은 comments.write 또는 manage입니다. 컨트롤러가 댓글을 조회한 뒤 권한을 적용합니다: admin.manage는 모든 댓글(비회원 댓글 포함), admin.write는 본인 댓글만 삭제할 수 있습니다. 게시판의 use_comment가 꺼져 있으면 403이며, CommentService::deleteComment()가 'admin' 컨텍스트로 삭제를 수행합니다. 경로의 {postId}에 속한 댓글만 대상이 됩니다 — 다른 게시글의 댓글 ID를 지정하면 404를 반환하며 해당 댓글은 변경되지 않습니다.
PUT /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments/{id}
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.comments.update - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\CommentController@update - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.comments.write
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| postId | path | string | 예 | — | 대상 post의 식별자 |
| id | path | string | 예 | — | 대상 리소스의 식별자 |
이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (
sirsoft-board.comment.update_validation_rules).
요청 예시
PUT /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments/{id} HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
응답 필드 (data 내부)
단건 응답: data 객체의 필드 (CommentResource — 댓글 생성/블라인드 응답과 동일한 구조).
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| id | integer | 1 |
댓글 기본 키 (내부 식별자) |
| post_id | integer | 1 |
댓글이 속한 게시글 식별자 |
| parent_id | null | null |
상위 댓글 식별자 (대댓글일 때만 값 존재) |
| content | string | API 문서 샘플 댓글입니다. (수정) |
수정된 댓글 본문 내용 |
| author | object | {"uuid":"a234c2b1-…","name":"API 문서 샘플 사용자"} |
작성자 사용자 객체 (author 관계 파생) |
| is_secret | boolean | false |
비밀 댓글 여부 |
| status | string | published |
댓글 상태 코드 (published / blinded / deleted) |
| status_label | string | 게시됨 |
상태의 사람이 읽는 라벨 |
| depth | integer | 0 |
댓글 계층 깊이 (0 = 최상위 댓글) |
| replies_count | integer | 0 |
이 댓글에 달린 대댓글 수 (집계) |
| created_at | string | 2026-07-08 10:41:34 |
생성 일시 |
| created_at_formatted | string | 4시간 전 |
created_at 값의 표시용 포맷 문자열 |
| updated_at | string | 2026-07-08 15:01:45 |
최종 수정 일시 (수정 시각으로 갱신) |
| deleted_at | null | null |
소프트 삭제 일시 (미삭제 시 null) |
| is_cascade_deleted | boolean | false |
상위 게시글/댓글 삭제로 연쇄 삭제된 댓글인지 여부 |
| ip_address | null | null |
작성 요청이 발생한 IP 주소 (권한자에게만 노출) |
| action_logs | array | [] |
블라인드/복원/삭제 처리 이력 목록. admin.manage 권한 보유자에게만 노출. |
| is_author | boolean | true |
현재 사용자가 작성자인지 여부 |
| is_guest_comment | boolean | false |
비회원 작성 댓글 여부 |
| is_already_reported | boolean | false |
현재 사용자가 이미 신고한 댓글인지 여부 |
| is_owner | boolean | true |
현재 인증 사용자가 이 리소스의 소유자인지 여부 |
| abilities | object | {"can_read":true,"can_write":true,"can_manage":true} |
현재 사용자가 이 댓글에 수행 가능한 작업 불리언 맵 |
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "댓글이 수정되었습니다.",
"data": {
"id": 1,
"post_id": 1,
"parent_id": null,
"content": "API 문서 샘플 댓글입니다. (수정)",
"author": {
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"name": "API 문서 샘플 사용자",
"email": "apidoc-sample-user@example.com",
"avatar": null,
"status": "active",
"status_label": "활성",
"is_guest": false
},
"is_secret": false,
"status": "published",
"status_label": "게시됨",
"depth": 0,
"replies_count": 0,
"created_at": "2026-07-08 10:41:34",
"created_at_formatted": "4시간 전",
"updated_at": "2026-07-08 15:01:45",
"deleted_at": null,
"is_cascade_deleted": false,
"ip_address": null,
"action_logs": [],
"is_author": true,
"is_guest_comment": false,
"is_already_reported": false,
"is_owner": true,
"abilities": {
"can_read": true,
"can_write": true,
"can_manage": true
}
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.comments.write)이 없거나, 타인/비회원 댓글을 admin.manage 없이 수정하려는 경우(접근 권한이 없습니다.), 게시판의 댓글 기능이 꺼진 경우(이 게시판은 댓글 기능이 비활성화되어 있습니다.) |
| 404 | Not Found | ID 에 해당하는 댓글 또는 슬러그에 해당하는 게시판이 없는 경우 (댓글을 찾을 수 없습니다.) |
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (error.errors 에 필드별 메시지) |
| 500 | Internal Server Error | 수정 처리 실패 (댓글 수정에 실패했습니다.) |
설명 게시판 관리자가 댓글 1건을 수정합니다. auth:sanctum + admin + 게시판별 comments.write 권한이 필요하며, 컨트롤러가 댓글을 조회한 뒤 권한을 적용합니다: admin.manage는 모든 댓글, admin.write는 본인 댓글만 수정할 수 있습니다. 게시판의 use_comment가 꺼져 있으면 403이며, UpdateCommentRequest 검증 값으로 CommentService::updateComment()가 갱신을 수행합니다. 경로의 {postId}에 속한 댓글만 대상이 됩니다 — 다른 게시글의 댓글 ID를 지정하면 404를 반환하며 해당 댓글은 변경되지 않습니다.
PATCH /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments/{id}/blind
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.comments.blind - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\CommentController@blind - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.manage
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| postId | path | string | 예 | — | 대상 post의 식별자 |
| id | path | string | 예 | — | 대상 리소스의 식별자 |
| reason | body | string | 아니오 | max 1000 | 댓글 블라인드 처리 사유(최대 1000자). 처리 이력에 기록되며, 미지정 시 빈 문자열로 저장됩니다. |
요청 예시
PATCH /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments/{id}/blind HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
Content-Type: application/json
{
"reason": "예시값"
}
응답 필드 (data 내부)
단건 응답: data 객체의 필드.
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| id | integer | 1 |
기본 키 (내부 식별자) |
| post_id | integer | 1 |
post 식별자 (연관 리소스 참조) |
| parent_id | null | null |
parent 식별자 (연관 리소스 참조) |
| content | string | API 문서 샘플 댓글입니다. |
본문 내용 |
| author | object | {"uuid":"a234c2b1-cde8-437f-b28b-23323be2b98d","name":"AP… |
작성자 사용자 객체 (uuid/name — author 관계 파생) |
| is_secret | boolean | false |
secret 여부 |
| status | string | blinded |
상태 값 (도메인별 상태 집합 — 사람이 읽는 라벨은 status_label, UI 변형은 status_variant 참조) |
| status_label | string | 블라인드 |
상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
| depth | integer | 0 |
계층 트리에서의 깊이 (0 = 최상위, 하위로 갈수록 증가) |
| replies_count | integer | 0 |
replies 개수 (집계) |
| created_at | string | 2026-07-08 10:41:34 |
생성 일시 |
| created_at_formatted | string | 4시간 전 |
created_at 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
| updated_at | string | 2026-07-08 15:01:44 |
최종 수정 일시 |
| deleted_at | null | null |
소프트 삭제 일시 (미삭제 시 null) |
| is_cascade_deleted | boolean | false |
cascade deleted 여부 |
| ip_address | null | null |
요청/행위가 발생한 IP 주소 |
| action_logs | array | [{"action":"blind","reason":"실측 예시값","admin_name":"API 문서… |
블라인드/복원/삭제 등 처리 이력 목록(항목별 action·reason·admin_name·created_at). admin.manage 권한 보유자에게만 노출되며, 민감 필드(admin_id·ip_address)는 제외됩니다. 비권한자에게는 null. |
| is_author | boolean | true |
author 여부 |
| is_guest_comment | boolean | false |
guest comment 여부 |
| is_already_reported | boolean | false |
already reported 여부 |
| is_owner | boolean | true |
현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
| abilities | object | {"can_read":true,"can_write":true,"can_manage":true} |
현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "댓글이 블라인드 처리되었습니다.",
"data": {
"id": 1,
"post_id": 1,
"parent_id": null,
"content": "API 문서 샘플 댓글입니다.",
"author": {
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"name": "API 문서 샘플 사용자",
"email": "apidoc-sample-user@example.com",
"avatar": null,
"status": "active",
"status_label": "활성",
"is_guest": false
},
"is_secret": "{MASKED}",
"status": "blinded",
"status_label": "블라인드",
"depth": 0,
"replies_count": 0,
"created_at": "2026-07-08 10:41:34",
"created_at_formatted": "4시간 전",
"updated_at": "2026-07-08 15:01:44",
"deleted_at": null,
"is_cascade_deleted": false,
"ip_address": null,
"action_logs": [
{
"action": "blind",
"reason": "실측 예시값",
"admin_name": "API 문서 샘플 사용자",
"created_at": "2026-07-08 06:01:44"
}
],
"is_author": true,
"is_guest_comment": false,
"is_already_reported": false,
"is_owner": true,
"abilities": {
"can_read": true,
"can_write": true,
"can_manage": true
}
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.manage)이 없는 경우 |
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (error.errors 에 필드별 메시지) |
설명 게시판 관리자가 댓글을 블라인드 처리합니다. auth:sanctum + admin + 게시판별 admin.manage 권한이 필요하며, 게시판의 use_comment가 꺼져 있으면 403으로 차단됩니다. 선택적 reason(최대 1000자)을 사유로 받아 CommentService::blindComment()가 댓글을 숨김 처리하되 관리 목적으로 보존하며, 복원(restore)으로 되돌릴 수 있습니다. 경로의 {postId}에 속한 댓글만 대상이 됩니다 — 다른 게시글의 댓글 ID를 지정하면 404를 반환하며 해당 댓글은 변경되지 않습니다.
PATCH /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments/{id}/restore
- 라우트명:
api.modules.sirsoft-board.admin.board.posts.comments.restore - 컨트롤러:
Modules\Sirsoft\Board\Http\Controllers\Admin\CommentController@restore - 인증/권한:
auth:sanctum+permission:sirsoft-board.{slug}.admin.manage
요청 파라미터
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|---|---|---|---|---|---|
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
| postId | path | string | 예 | — | 대상 post의 식별자 |
| id | path | string | 예 | — | 대상 리소스의 식별자 |
| reason | body | string | 아니오 | max 1000 | 댓글 블라인드 처리 사유(최대 1000자). 처리 이력에 기록되며, 미지정 시 빈 문자열로 저장됩니다. |
요청 예시
PATCH /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments/{id}/restore HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer {YOUR_TOKEN}
Content-Type: application/json
{
"reason": "예시값"
}
응답 필드 (data 내부)
단건 응답: data 객체의 필드 (CommentResource — 복원된 댓글. 블라인드 응답과 동일한 구조이며, status 가 published 로 되돌아가고 action_logs 에 restore 이력이 1건 추가됩니다).
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|---|---|---|---|
| id | integer | 1 |
댓글 기본 키 (내부 식별자) |
| post_id | integer | 1 |
댓글이 속한 게시글 식별자 |
| parent_id | null | null |
상위 댓글 식별자 (대댓글일 때만 값 존재) |
| content | string | API 문서 샘플 댓글입니다. |
댓글 본문 내용 (복원되어 원문이 다시 노출됨) |
| author | object | {"uuid":"a234c2b1-…","name":"API 문서 샘플 사용자"} |
작성자 사용자 객체 (author 관계 파생) |
| is_secret | boolean | false |
비밀 댓글 여부 |
| status | string | published |
복원 후 댓글 상태 (published 로 되돌아감) |
| status_label | string | 게시됨 |
상태의 사람이 읽는 라벨 |
| depth | integer | 0 |
댓글 계층 깊이 (0 = 최상위 댓글) |
| replies_count | integer | 0 |
이 댓글에 달린 대댓글 수 (집계) |
| created_at | string | 2026-07-08 10:41:34 |
생성 일시 |
| created_at_formatted | string | 4시간 전 |
created_at 값의 표시용 포맷 문자열 |
| updated_at | string | 2026-07-08 15:01:45 |
최종 수정 일시 |
| deleted_at | null | null |
소프트 삭제 일시 (미삭제 시 null) |
| is_cascade_deleted | boolean | false |
상위 게시글/댓글 삭제로 연쇄 삭제된 댓글인지 여부 |
| ip_address | null | null |
작성 요청이 발생한 IP 주소 (권한자에게만 노출) |
| action_logs | array | [{"action":"blind","reason":"실측 예시값",…},{"action":"restore","reason":null,…}] |
블라인드/복원/삭제 처리 이력 목록 (복원 이력이 추가됨). admin.manage 권한 보유자에게만 노출. |
| is_author | boolean | true |
현재 사용자가 작성자인지 여부 |
| is_guest_comment | boolean | false |
비회원 작성 댓글 여부 |
| is_already_reported | boolean | false |
현재 사용자가 이미 신고한 댓글인지 여부 |
| is_owner | boolean | true |
현재 인증 사용자가 이 리소스의 소유자인지 여부 |
| abilities | object | {"can_read":true,"can_write":true,"can_manage":true} |
현재 사용자가 이 댓글에 수행 가능한 작업 불리언 맵 |
응답 예시
HTTP/1.1 200
{
"success": true,
"message": "댓글이 복원되었습니다.",
"data": {
"id": 1,
"post_id": 1,
"parent_id": null,
"content": "API 문서 샘플 댓글입니다.",
"author": {
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
"name": "API 문서 샘플 사용자",
"email": "apidoc-sample-user@example.com",
"avatar": null,
"status": "active",
"status_label": "활성",
"is_guest": false
},
"is_secret": false,
"status": "published",
"status_label": "게시됨",
"depth": 0,
"replies_count": 0,
"created_at": "2026-07-08 10:41:34",
"created_at_formatted": "4시간 전",
"updated_at": "2026-07-08 15:01:45",
"deleted_at": null,
"is_cascade_deleted": false,
"ip_address": null,
"action_logs": [
{
"action": "blind",
"reason": "실측 예시값",
"admin_name": "API 문서 샘플 사용자",
"created_at": "2026-07-08 06:01:44"
},
{
"action": "restore",
"reason": null,
"admin_name": "API 문서 샘플 사용자",
"created_at": "2026-07-08 06:01:45"
}
],
"is_author": true,
"is_guest_comment": false,
"is_already_reported": false,
"is_owner": true,
"abilities": {
"can_read": true,
"can_write": true,
"can_manage": true
}
}
}
에러 응답
| 상태코드 | 의미 | 발생 조건 |
|---|---|---|
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
| 403 | Forbidden | 요구 권한(sirsoft-board.{slug}.admin.manage)이 없거나, 게시판의 댓글 기능이 꺼진 경우 (이 게시판은 댓글 기능이 비활성화되어 있습니다.) |
| 404 | Not Found | ID 에 해당하는 댓글 또는 슬러그에 해당하는 게시판이 없는 경우 (댓글을 찾을 수 없습니다.) |
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (error.errors 에 필드별 메시지) |
| 500 | Internal Server Error | 복원 처리 실패 (댓글 복원에 실패했습니다.) |
설명 게시판 관리자가 블라인드 처리된 댓글을 복원합니다. auth:sanctum + admin + 게시판별 admin.manage 권한이 필요하며, 게시판의 use_comment가 꺼져 있으면 403으로 차단됩니다. 요청 본문의 선택적 reason을 사유로 받아 CommentService::restoreComment()가 블라인드 상태를 해제해 댓글을 다시 노출합니다. 경로의 {postId}에 속한 댓글만 대상이 됩니다 — 다른 게시글의 댓글 ID를 지정하면 404를 반환하며 해당 댓글은 변경되지 않습니다.