fix(core,board,ecommerce,plugins): API 문서 미채움 마커 전수 채움 + 미해석 lang 키 정정 + IDV 조회 시도횟수 비노출
이슈 본연: API 레퍼런스의 미채움 마커 5종(실측 제외/TODO/필드 없음/대표 에러 없음)
1,194건을 코드에서 읽어 전수 채우고(0건), api:docgen 재생성이 사람이 채운 내용을
손실·열화시키던 멱등성 결함 4종(CRLF, 표 파이프 이스케이프, 에러 서술 보존, 중복
라우트명 키)을 근본 수정. --check 를 실측 제외와 드리프트가 구분되도록 재정의.
ParameterDescriber/ResourceFieldDescriber 에 leaf 폴백·SEO 스코프·공통 사전 확장.
파생 결함(문서 실측 중 발견): ResponseHelper 기본 메시지 키 6종이 존재하지 않는
messages.* 를 가리켜 응답 message 가 번역문 대신 키 문자열로 노출되던 문제를 common.*
으로 정정하고, 코어 7 + gdpr/marketing/pay_kginicis/verification/ecommerce 확장의
호출부와 누락 lang 키(게시판 10키 + 이커머스 category_images 4키 포함)를 ko/en/ja
전수 정정. 중복 그룹 키 2건은 기존 키로 호출부 통합.
보안: GET /api/identity/challenges/{id} 는 권한 가드 없는 공개 폴링 엔드포인트인데
Service::getStatus 가 attempts/max_attempts 를 응답에 담아 남은 시도 횟수를 추론할 수
있었다. 두 필드를 제거하고, 챌린지 화면(admin_basic/basic)의 서버 attempts 참조를
제거(남은 횟수 UI 는 query fallback + verify 실패 시 로컬 증가로 유지).
부수 정리(변경셋에 들어온 board 컨트롤러의 audit 사전 결함): FormRequest 4개 신설로
base Request 주입 제거, CommentController 의 Board 직접 호출을 BoardService 위임으로
전환, PHPDoc @return 보강. board 스위트에서 발견한 stale test 3건(seed SSoT 불일치,
admin 계정 user 역할 누락)도 같은 세션에서 정정.
버전 정렬(공개 release 기준): 코어 7.0.3→7.0.4, sirsoft-board 1.0.1→1.0.2,
verification_kginicis 1.0.0→1.0.1, admin_basic 1.0.1→1.0.4.
This commit is contained in:
1 parent
b07d6c8953
commit
6c8381f164
155 files changed
+17192
-1829
No files matched your search
@@ -214,7 +214,7 @@ HTTP/1.1 200
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
| ids | body | array | 예 | min 1 | 삭제할 활동 로그 ID 배열 (원소는 integer 이며 `activity_logs.id` 에 존재해야 함) |
|
||||
|
||||
**요청 예시**
|
||||
|
||||
@@ -234,11 +234,27 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| deleted_count | integer | `3` | 실제로 삭제된 활동 로그 건수 (`ActivityLogService::deleteMany()` 반환값 — 요청한 `ids` 중 삭제에 성공한 개수) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "선택한 활동 로그가 삭제되었습니다.",
|
||||
"data": {
|
||||
"deleted_count": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -276,9 +292,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — 컨트롤러가 `success('activity_log.delete_success')` 를 데이터 인자 없이 호출하여 `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| hash | path | string | 예 | — | 대상 리소스의 해시 식별자 |
|
||||
| hash | path | string | 예 | — | 다운로드할 첨부파일의 해시 식별자 (`attachments.hash`) |
|
||||
|
||||
**요청 예시**
|
||||
|
||||
@@ -39,17 +39,45 @@ Accept: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 JSON 봉투(`data`)를 반환하지 않습니다. 성공 시 파일 바이너리 본문을 그대로 응답합니다 (실패 시에만 JSON 에러 봉투)._
|
||||
|
||||
| 응답 헤더 | 값 | 용도/설명 |
|
||||
| --- | --- | --- |
|
||||
| Content-Type | `image/png` 등 | 첨부파일의 MIME 타입 (`attachments.mime_type`) |
|
||||
| Content-Disposition | `attachment; filename="원본파일명.pdf"` | 이미지가 아닌 파일에만 부여 — 원본 파일명으로 다운로드 |
|
||||
| Cache-Control | `public, max-age=86400, immutable` (프로덕션) / `no-cache` (그 외) | 이미지 응답의 캐싱 정책. max-age 는 환경설정 `cache.layout_ttl` (기본 86400초) |
|
||||
| Expires | `Wed, 15 Jul 2026 00:00:00 GMT` | 이미지 응답의 만료 시각 (현재 시각 + max-age) |
|
||||
| ETag | `9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d` | 이미지 응답의 검증자 (파일 수정시각 + 크기의 MD5). 요청의 `If-None-Match` 와 일치하면 `304 Not Modified` |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: image/png
|
||||
Cache-Control: public, max-age=86400, immutable
|
||||
Expires: Wed, 15 Jul 2026 00:00:00 GMT
|
||||
ETag: 9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d
|
||||
|
||||
<파일 바이너리>
|
||||
```
|
||||
|
||||
이미지가 아닌 파일:
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/pdf
|
||||
Content-Disposition: attachment; filename="manual.pdf"
|
||||
|
||||
<파일 바이너리>
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 304 | Not Modified | 이미지 응답에서 요청 `If-None-Match` 헤더가 현재 ETag 와 일치하는 경우 (본문 없음) |
|
||||
| 403 | Forbidden | 첨부파일 접근 권한 없음 (`core.attachment.download` 훅 권한 미충족) 또는 스토리지에 실제 파일이 없는 경우 — `{"success": false, "message": "이 첨부파일에 대한 접근 권한이 없습니다."}` |
|
||||
| 404 | Not Found | 해당 해시의 첨부파일이 존재하지 않는 경우 — `{"success": false, "message": "첨부파일을 찾을 수 없습니다."}` |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
|
||||
+154
-13
@@ -75,11 +75,59 @@ example-key
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`AttachmentResource`)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 첨부파일 ID (기본 키) |
|
||||
| hash | string | `"aB3xY9kLmQ7z"` | URL용 고유 해시 (12자). 다운로드 URL 식별자로 사용 |
|
||||
| original_filename | string | `"example.pdf"` | 업로드된 원본 파일명 |
|
||||
| mime_type | string | `"application/pdf"` | MIME 타입 (예: `image/jpeg`, `application/pdf`) |
|
||||
| size | integer | `102400` | 파일 크기 (바이트) |
|
||||
| size_formatted | string | `"100 KB"` | 사람이 읽기 쉬운 형식으로 포맷된 파일 크기 (B/KB/MB/GB) |
|
||||
| collection | string | `"default"` | 첨부파일 컬렉션/그룹명 (미지정 시 `default`) |
|
||||
| order | integer | `0` | 컬렉션 내 정렬 순서 |
|
||||
| download_url | string | `"/api/attachment/aB3xY9kLmQ7z"` | 해시 기반 다운로드 경로 |
|
||||
| is_image | boolean | `false` | MIME 타입이 `image/` 로 시작하는지 여부 |
|
||||
| meta | object\|null | `{"width": 800, "height": 600}` | 추가 메타데이터. 이미지 업로드 시 width/height 자동 기록, 그 외에는 빈 객체 |
|
||||
| source_type | string | `"core"` | 첨부 생성 출처 (`core` / `module` / `plugin`) |
|
||||
| source_identifier | string\|null | `"sirsoft-board"` | 모듈/플러그인 식별자 (코어 업로드 시 `null`) |
|
||||
| creator | object\|없음 | `{"uuid": "...", "name": "관리자"}` | 업로더 정보(`uuid`, `name`). `creator` 관계가 eager load 된 경우에만 포함되며, 업로드 응답에는 포함되지 않음 |
|
||||
| created_at | string | `"2026-07-14 10:23:41"` | 생성 일시 (사용자 타임존 기준 `Y-m-d H:i:s`) |
|
||||
| updated_at | string | `"2026-07-14 10:23:41"` | 수정 일시 (사용자 타임존 기준 `Y-m-d H:i:s`) |
|
||||
| is_owner | boolean | `true` | 요청자가 업로더(`created_by`)인지 여부 |
|
||||
| abilities | object | `{"can_update": true, "can_delete": true}` | 요청자의 권한 맵 (`can_update` = `core.attachments.update`, `can_delete` = `core.attachments.delete`) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "파일이 업로드되었습니다.",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"hash": "aB3xY9kLmQ7z",
|
||||
"original_filename": "example.pdf",
|
||||
"mime_type": "application/pdf",
|
||||
"size": 102400,
|
||||
"size_formatted": "100 KB",
|
||||
"collection": "default",
|
||||
"order": 0,
|
||||
"download_url": "/api/attachment/aB3xY9kLmQ7z",
|
||||
"is_image": false,
|
||||
"meta": {},
|
||||
"source_type": "core",
|
||||
"source_identifier": null,
|
||||
"created_at": "2026-07-14 10:23:41",
|
||||
"updated_at": "2026-07-14 10:23:41",
|
||||
"is_owner": true,
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -88,6 +136,7 @@ example-key
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.attachments.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 파일 저장/DB 기록 중 예외 발생 시 (`attachment.upload_failed` — "파일 업로드에 실패했습니다.") |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -136,11 +185,88 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_배열 응답: `data` 는 `AttachmentResource` 객체의 배열입니다 (페이지네이션 없음). 각 항목의 필드는 단일 업로드 응답과 동일합니다._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| data[].id | integer | `1` | 첨부파일 ID (기본 키) |
|
||||
| data[].hash | string | `"aB3xY9kLmQ7z"` | URL용 고유 해시 (12자) |
|
||||
| data[].original_filename | string | `"photo1.jpg"` | 업로드된 원본 파일명 |
|
||||
| data[].mime_type | string | `"image/jpeg"` | MIME 타입 |
|
||||
| data[].size | integer | `204800` | 파일 크기 (바이트) |
|
||||
| data[].size_formatted | string | `"200 KB"` | 포맷된 파일 크기 |
|
||||
| data[].collection | string | `"default"` | 첨부파일 컬렉션/그룹명 |
|
||||
| data[].order | integer | `0` | 컬렉션 내 정렬 순서 (배치 내 파일마다 순차 증가) |
|
||||
| data[].download_url | string | `"/api/attachment/aB3xY9kLmQ7z"` | 해시 기반 다운로드 경로 |
|
||||
| data[].is_image | boolean | `true` | MIME 타입이 `image/` 로 시작하는지 여부 |
|
||||
| data[].meta | object\|null | `{"width": 1920, "height": 1080}` | 이미지 업로드 시 width/height 자동 기록 |
|
||||
| data[].source_type | string | `"core"` | 첨부 생성 출처 (`core` / `module` / `plugin`) |
|
||||
| data[].source_identifier | string\|null | `null` | 모듈/플러그인 식별자 |
|
||||
| data[].created_at | string | `"2026-07-14 10:23:41"` | 생성 일시 (사용자 타임존 기준) |
|
||||
| data[].updated_at | string | `"2026-07-14 10:23:41"` | 수정 일시 (사용자 타임존 기준) |
|
||||
| data[].is_owner | boolean | `true` | 요청자가 업로더인지 여부 |
|
||||
| data[].abilities | object | `{"can_update": true, "can_delete": true}` | 요청자의 권한 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "파일이 일괄 업로드되었습니다.",
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"hash": "aB3xY9kLmQ7z",
|
||||
"original_filename": "photo1.jpg",
|
||||
"mime_type": "image/jpeg",
|
||||
"size": 204800,
|
||||
"size_formatted": "200 KB",
|
||||
"collection": "default",
|
||||
"order": 0,
|
||||
"download_url": "/api/attachment/aB3xY9kLmQ7z",
|
||||
"is_image": true,
|
||||
"meta": {
|
||||
"width": 1920,
|
||||
"height": 1080
|
||||
},
|
||||
"source_type": "core",
|
||||
"source_identifier": null,
|
||||
"created_at": "2026-07-14 10:23:41",
|
||||
"updated_at": "2026-07-14 10:23:41",
|
||||
"is_owner": true,
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"hash": "Zq1WeRt5YuIo",
|
||||
"original_filename": "photo2.jpg",
|
||||
"mime_type": "image/jpeg",
|
||||
"size": 153600,
|
||||
"size_formatted": "150 KB",
|
||||
"collection": "default",
|
||||
"order": 1,
|
||||
"download_url": "/api/attachment/Zq1WeRt5YuIo",
|
||||
"is_image": true,
|
||||
"meta": {
|
||||
"width": 1280,
|
||||
"height": 720
|
||||
},
|
||||
"source_type": "core",
|
||||
"source_identifier": null,
|
||||
"created_at": "2026-07-14 10:23:41",
|
||||
"updated_at": "2026-07-14 10:23:41",
|
||||
"is_owner": true,
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -149,6 +275,7 @@ Content-Type: application/json
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.attachments.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 배치 중 파일 저장/DB 기록 예외 발생 시 (`attachment.upload_failed` — "파일 업로드에 실패했습니다.") |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -187,19 +314,26 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 데이터를 반환하지 않습니다 (`data` 는 `null`, 성공 메시지만 반환)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "파일 순서가 변경되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.attachments.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 403 | Forbidden | 요구 권한(`core.attachments.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지). `order[].id` 가 존재하지 않는 첨부파일이면 "존재하지 않는 첨부파일입니다." |
|
||||
| 500 | Internal Server Error | 순서 갱신 중 예외 발생 시 (`attachment.reorder_failed` — "파일 순서 변경에 실패했습니다.") |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -229,20 +363,27 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 데이터를 반환하지 않습니다 (`data` 는 `null`, 성공 메시지만 반환)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "파일이 삭제되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 400 | Bad Request | 삭제 처리가 실패로 반환된 경우 (`attachment.delete_failed` — "파일 삭제에 실패했습니다.") |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.attachments.create`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 403 | Forbidden | 요구 권한(`core.attachments.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | `{attachment}` 에 해당하는 첨부파일이 없는 경우 (라우트 모델 바인딩 실패) |
|
||||
| 500 | Internal Server Error | 파일/DB 삭제 중 예외 발생 시 (`attachment.delete_failed` — "파일 삭제에 실패했습니다.") |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
|
||||
+297
-36
@@ -38,9 +38,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — `AuthController@logout` 이 `success('auth.logout_success')` 를 인자 없이 호출하므로 `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
@@ -285,18 +283,59 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-500 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`AuthService::login()` 이 반환한 배열 — `user` 만 `UserResource` 로 감싼다)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| user | object | `{"uuid":"a234c2b1-…","name":"관리자","is_admin":true, …}` | 로그인한 관리자 정보 (`UserResource` — 필드 전수는 `GET /api/admin/auth/user` 응답 필드 표와 동일) |
|
||||
| token | string | `75\|WgPUplvLGTv8YIj4507uIR6dEOHTXyNUed…` | 발급된 Sanctum 접근 토큰 평문 (이후 `Authorization: Bearer` 헤더로 사용, 발급 시 1회만 노출) |
|
||||
| token_type | string | `Bearer` | 토큰 타입 (항상 `Bearer` — `AuthService::login()` 이 상수로 반환) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-500 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "관리자 로그인이 성공했습니다.",
|
||||
"data": {
|
||||
"user": {
|
||||
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"name": "API 문서 샘플 사용자",
|
||||
"email": "apidoc-sample-user@example.com",
|
||||
"status": "active",
|
||||
"is_admin": true,
|
||||
"roles": [
|
||||
{ "id": 1, "identifier": "admin", "name": "관리자" }
|
||||
],
|
||||
"is_owner": true,
|
||||
"abilities": {
|
||||
"can_read": true,
|
||||
"can_create": true,
|
||||
"can_update": true,
|
||||
"can_delete": true,
|
||||
"can_assign_roles": true
|
||||
}
|
||||
},
|
||||
"token": "{MASKED}",
|
||||
"token_type": "Bearer"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `user` 객체는 지면 절약을 위해 축약했습니다. 실제로는 `GET /api/admin/auth/user` 의 `data` 와 동일한 `UserResource` 필드 전수가 내려옵니다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 401 | Unauthenticated | 이메일/비밀번호가 일치하지 않는 경우 (`auth.login_failed`) |
|
||||
| 403 | Forbidden | 자격 증명은 맞지만 관리자 역할이 아닌 경우 (`auth.admin_required`) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 423 | Locked | 로그인 실패 누적으로 계정이 잠긴 경우 (`auth.account_locked` — `error.locked_until`, `error.retry_after_seconds` 포함) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -336,18 +375,27 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — `AuthController@forgotPassword` 가 `success('auth.password_reset_email_sent')` 를 인자 없이 호출하므로 `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "비밀번호 재설정 이메일이 발송되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우, 또는 등록되지 않은 이메일인 경우 (`auth.password_reset_failed` — `error.errors.email` 에 `auth.email_not_registered` 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -387,18 +435,56 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-500 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`AuthService::login()` 이 반환한 배열 — `user` 만 `UserResource` 로 감싼다)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| user | object | `{"uuid":"a234c2b1-…","name":"홍길동","is_admin":false, …}` | 로그인한 사용자 정보 (`UserResource` — 필드 전수는 `GET /api/auth/user` 응답 필드 표의 기본(코어) 필드와 동일) |
|
||||
| token | string | `75\|WgPUplvLGTv8YIj4507uIR6dEOHTXyNUed…` | 발급된 Sanctum 접근 토큰 평문 (이후 `Authorization: Bearer` 헤더로 사용, 발급 시 1회만 노출) |
|
||||
| token_type | string | `Bearer` | 토큰 타입 (항상 `Bearer`) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-500 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "로그인이 성공했습니다.",
|
||||
"data": {
|
||||
"user": {
|
||||
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"name": "API 문서 샘플 사용자",
|
||||
"email": "apidoc-sample-user@example.com",
|
||||
"language": "ko",
|
||||
"status": "active",
|
||||
"is_admin": false,
|
||||
"is_owner": true,
|
||||
"abilities": {
|
||||
"can_read": true,
|
||||
"can_create": true,
|
||||
"can_update": true,
|
||||
"can_delete": true,
|
||||
"can_assign_roles": true
|
||||
}
|
||||
},
|
||||
"token": "{MASKED}",
|
||||
"token_type": "Bearer"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `user` 객체는 지면 절약을 위해 축약했습니다. 실제로는 `UserResource` 필드 전수가 내려옵니다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 401 | Unauthenticated | 이메일/비밀번호가 일치하지 않거나 계정 상태가 활성이 아닌 경우 (`auth.login_failed`) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 423 | Locked | 로그인 실패 누적으로 계정이 잠긴 경우 (`auth.account_locked` — `error.locked_until`, `error.retry_after_seconds` 포함) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -491,9 +577,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — `AuthController@logout` 이 `success('auth.logout_success')` 를 인자 없이 호출하므로 `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
@@ -579,18 +663,56 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`AuthService::register()` 이 반환한 배열 — `user` 만 `UserResource` 로 감싼다). 성공 시 HTTP 201._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| user | object | `{"uuid":"a234c2b1-…","name":"홍길동","status":"active", …}` | 생성된 사용자 정보 (`UserResource`. `status` 는 `active`, 가입 후 본인인증 정책이 걸린 경우 `pending_verification`) |
|
||||
| token | string | `75\|WgPUplvLGTv8YIj4507uIR6dEOHTXyNUed…` | 가입 즉시 발급되는 Sanctum 접근 토큰 평문 (가입 직후 로그인 상태로 이어짐) |
|
||||
| token_type | string | `Bearer` | 토큰 타입 (항상 `Bearer`) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 201
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "회원가입이 성공했습니다.",
|
||||
"data": {
|
||||
"user": {
|
||||
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"name": "API 문서 샘플 사용자",
|
||||
"nickname": null,
|
||||
"email": "apidoc-sample-user@example.com",
|
||||
"language": "ko",
|
||||
"status": "active",
|
||||
"is_admin": false,
|
||||
"is_owner": true,
|
||||
"abilities": {
|
||||
"can_read": true,
|
||||
"can_create": true,
|
||||
"can_update": true,
|
||||
"can_delete": true,
|
||||
"can_assign_roles": true
|
||||
}
|
||||
},
|
||||
"token": "{MASKED}",
|
||||
"token_type": "Bearer"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `user` 객체는 지면 절약을 위해 축약했습니다. 실제로는 `UserResource` 필드 전수가 내려옵니다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`auth.register_failed` — `error.errors` 에 필드별 메시지) |
|
||||
| 428 | Precondition Required | 가입 전 본인인증 정책이 매칭되었으나 유효한 `verification_token` 이 없는 경우 (`core.auth.before_register` 훅) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -632,18 +754,27 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — `AuthController@resetPassword` 가 `success('auth.password_reset_success')` 를 인자 없이 호출하므로 `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "비밀번호가 성공적으로 재설정되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반했거나, 토큰이 유효하지 않거나 만료된 경우 (`auth.password_reset_failed` — `error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -813,18 +944,33 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`AuthService::validateResetToken()` 의 반환 배열)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| valid | boolean | `true` | 토큰 유효 여부. 성공 응답에서는 항상 `true` (유효하지 않으면 컨트롤러가 422 로 전환하므로 이 필드가 `false` 인 200 응답은 없음) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": {
|
||||
"valid": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터 검증 위반, 또는 토큰이 유효하지 않거나 만료된 경우 / 미등록 이메일 (`auth.reset_token_invalid` — `error.errors.token` 에 사유 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -854,11 +1000,21 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — `AuthController@logout` 이 `success('auth.logout_success')` 를 인자 없이 호출하므로 `data` 는 `null`). 공용 `POST /api/auth/logout` 과 동일한 컨트롤러 메서드._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "로그아웃이 성공했습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -895,11 +1051,21 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — `AuthController@logoutFromAllDevices` 가 `success('auth.logout_all_devices_success')` 를 인자 없이 호출하므로 `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "모든 디바이스에서 로그아웃되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -936,11 +1102,47 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`AuthService::refreshToken()` 반환 배열 — 공용 `POST /api/admin/auth/refresh` 와 동일 shape)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| user | object | `{"uuid":"a234c2b1-…","name":"홍길동", …}` | 토큰을 갱신한 사용자 정보 (`UserResource`) |
|
||||
| token | string | `75\|WgPUplvLGTv8YIj4507uIR6dEOHTXyNUed…` | 새로 발급된 Sanctum 접근 토큰 평문 (기존 토큰은 폐기됨) |
|
||||
| token_type | string | `Bearer` | 토큰 타입 (항상 `Bearer`) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": {
|
||||
"user": {
|
||||
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"name": "API 문서 샘플 사용자",
|
||||
"email": "apidoc-sample-user@example.com",
|
||||
"status": "active",
|
||||
"is_admin": false,
|
||||
"is_owner": true,
|
||||
"abilities": {
|
||||
"can_read": true,
|
||||
"can_create": true,
|
||||
"can_update": true,
|
||||
"can_delete": true,
|
||||
"can_assign_roles": true
|
||||
}
|
||||
},
|
||||
"token": "{MASKED}",
|
||||
"token_type": "Bearer"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `user` 객체는 지면 절약을 위해 축약했습니다. 실제로는 `UserResource` 필드 전수가 내려옵니다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -977,11 +1179,70 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드. 컨트롤러 메서드가 공용 `GET /api/auth/user` 와 동일한 `AuthController@user` 이므로, 응답은 `UserResource::toAuthArray()` 산물(코어 필드 + `core.user.filter_resource_data` 로 확장이 병합한 필드)로 그 문서의 응답 필드 표와 동일합니다._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a234c2b1-cde8-437f-b28b-23323be2b98d` | 외부 노출용 UUID (URL/API 식별자, 내부 id 비노출) |
|
||||
| name | string | `API 문서 샘플 사용자` | 사용자 이름 |
|
||||
| nickname | string \| null | `song.hyunji` | 닉네임 (미설정 시 null) |
|
||||
| email | string | `apidoc-sample-user@example.com` | 이메일 주소 |
|
||||
| language | string | `ko` | 사용자 언어 설정 |
|
||||
| status | string | `active` | 계정 상태 (active / inactive / blocked / withdrawn / pending_verification) |
|
||||
| is_admin | boolean | `false` | 관리자 역할 보유 여부 |
|
||||
| roles | array | `[{"id":2,"identifier":"user","name":"일반회원"}]` | 부여된 역할 목록 (id/identifier/name) |
|
||||
| permissions | array | `[{"id":81,"identifier":"sirsoft-ecommerce.user-products.read","name":"상품 조회"}]` | 역할 경유 권한 목록 (id/identifier/name) |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":true,"can_update":true, …}` | 이 리소스에 수행 가능한 작업 불리언 맵 |
|
||||
| (확장 병합 필드) | — | `notify_*`, `marketing_consent*`, `ecommerce_*` 등 | marketing 플러그인·ecommerce 모듈이 `core.user.filter_resource_data` 필터로 병합 — 전수는 `GET /api/auth/user` 응답 필드 표 참조 |
|
||||
|
||||
> 필드 전수(코어 + 확장 병합)는 `GET /api/auth/user` 의 응답 필드 표와 동일하므로 그 표를 SSoT 로 참조합니다. 게스트(비인증) 요청은 `optional.sanctum` 을 통과하지만 `request()->user()` 가 없으므로 이 경로는 인증 사용자 컨텍스트에서만 사용자 객체를 반환합니다.
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": {
|
||||
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"name": "API 문서 샘플 사용자",
|
||||
"nickname": "song.hyunji",
|
||||
"email": "apidoc-sample-user@example.com",
|
||||
"language": "ko",
|
||||
"status": "active",
|
||||
"is_admin": false,
|
||||
"roles": [
|
||||
{ "id": 2, "identifier": "user", "name": "일반회원" }
|
||||
],
|
||||
"permissions": [],
|
||||
"is_owner": true,
|
||||
"abilities": {
|
||||
"can_read": true,
|
||||
"can_create": true,
|
||||
"can_update": true,
|
||||
"can_delete": true,
|
||||
"can_assign_roles": true
|
||||
},
|
||||
"notify_post_complete": false,
|
||||
"notify_post_reply": false,
|
||||
"notify_comment": false,
|
||||
"notify_reply_comment": false,
|
||||
"ecommerce_mileage": {
|
||||
"enabled": false
|
||||
},
|
||||
"ecommerce_preferred_currency": null,
|
||||
"ecommerce_preferred_shipping_country": null,
|
||||
"ecommerce_preferred_shipping_country_name": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 지면 절약을 위해 축약했습니다. 실제 응답은 `GET /api/auth/user` 의 응답 예시와 동일한 필드 전수를 포함합니다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
|
||||
@@ -38,17 +38,25 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-404 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-404 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "프로필 이미지가 성공적으로 삭제되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 404 | Not Found | 삭제할 아바타 첨부파일이 없는 경우 (`user.avatar_not_found` — "삭제할 프로필 이미지가 없습니다.") |
|
||||
| 500 | Server Error | 첨부파일/실제 파일 삭제 중 예외 발생 (`user.avatar_delete_failed` — "프로필 이미지 삭제에 실패했습니다.") |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -86,11 +94,25 @@ Content-Type: image/png
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| avatar | string\|null | `/api/attachment/9f1c2b7d8e...` | 업로드된 아바타의 다운로드 URL (`Attachment.download_url` = `/api/attachment/{hash}`). 레거시 `avatar` 컬럼만 있는 경우 `storage/attachments/avatars/{파일명}` 형태의 절대 URL |
|
||||
| attachment_id | integer | `1` | 생성된 첨부파일(Attachment) 레코드의 기본 키 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "프로필 이미지가 성공적으로 업로드되었습니다.",
|
||||
"data": {
|
||||
"avatar": "/api/attachment/9f1c2b7d8e3a4c5b6d7e8f90a1b2c3d4",
|
||||
"attachment_id": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -98,6 +120,7 @@ Content-Type: image/png
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Server Error | 파일 저장/첨부파일 생성 중 예외 발생 (`user.avatar_upload_failed` — "프로필 이미지 업로드에 실패했습니다.") |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
|
||||
@@ -37,17 +37,26 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 G7 공통 응답 봉투(`success`/`message`/`data`)를 사용하지 않습니다. 라우트 클로저가 `Broadcast::auth($request)` 의 반환값을 그대로 응답하므로, 응답 본문은 Laravel 브로드캐스팅 드라이버(Reverb — Pusher 프로토콜 호환)가 생성하는 채널 인증 페이로드입니다. 등록된 채널(`routes/channels.php`, 모듈/플러그인 `getChannels()`)은 모두 boolean 을 반환하는 private 채널이므로 아래 필드만 반환됩니다._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| auth | string | `앱키:서명` 형식 문자열 | 클라이언트가 WebSocket 서버(Reverb)에 프라이빗 채널 구독을 요청할 때 제시하는 인증 서명. `{reverb_app_key}:{HMAC-SHA256(socket_id:channel_name)}` 형태이며, 브로드캐스팅 클라이언트 라이브러리가 자동으로 소비합니다 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"auth": "app-key:5f1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f8"
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 웹소켓 사용 OFF(`broadcasting.default === 'null'`) 로 채널 인증이 거부된 경우, 또는 요청한 채널의 인증 콜백이 `false` 를 반환한 경우(권한 부족·타 사용자 채널 구독 시도 등) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
|
||||
@@ -95,11 +95,31 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| update_available | boolean | `false` | 새 버전 존재 여부 (최신 릴리스 버전이 현재 버전보다 높으면 `true`) |
|
||||
| current_version | string | `7.0.3` | 현재 설치된 코어 버전 (`config('app.version')`) |
|
||||
| latest_version | string | `7.0.3` | GitHub 릴리스에서 조회한 최신 코어 버전 (조회 값이 없으면 현재 버전과 동일) |
|
||||
| github_url | string | `https://github.com/gnuboard/g7` | 업데이트 조회 대상 GitHub 저장소 URL (`config('app.update.github_url')`) |
|
||||
|
||||
> 조회 실패 시(GitHub 접속 불가 등)에는 422 응답이 반환되며, `error` 객체에 `reason`(실패 사유) · `current_version` · `github_url` 이 담깁니다.
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "업데이트 확인이 완료되었습니다.",
|
||||
"data": {
|
||||
"update_available": false,
|
||||
"current_version": "7.0.3",
|
||||
"latest_version": "7.0.3",
|
||||
"github_url": "https://github.com/gnuboard/g7"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
|
||||
@@ -141,9 +141,21 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data` 배열 항목의 필드. `data` 는 `core.dashboard.alerts` 필터 훅의 결과이며, 알릴 항목이 없으면 빈 배열(`[]`)입니다. 코어 기본 리스너(`ExtensionCompatibilityAlertListener`)가 주입하는 항목의 필드는 다음과 같습니다._
|
||||
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | string | `compat_plugins_sirsoft-gdpr` | 알림 식별자 (`compat_{type}_{identifier}` = 자동 비활성화, `recover_{type}_{identifier}` = 재호환. 알림 닫기(dismiss) 상태 판정 키) |
|
||||
| type | string | `warning` | 알림 등급 (`warning`: 코어 비호환 자동 비활성화, `info`: 재호환 복구 가능) |
|
||||
| subtype | string | `incompatible_core` | 알림 세부 분류 (`incompatible_core`: 코어 버전 비호환으로 자동 비활성화됨, `recovery_available`: 코어 업그레이드 후 다시 활성화 가능) |
|
||||
| icon | string | `exclamation-triangle` | 아이콘 식별자 (warning: `exclamation-triangle`, info: `check-circle`) |
|
||||
| title | string | `플러그인 "sirsoft-gdpr" 자동 비활성화됨` | 알림 제목 (다국어 문구 — `extensions.alerts.incompatible_deactivated` / `recovered_title`) |
|
||||
| message | string | `필요 버전: 7.0.0-beta.9, 현재 설치됨: 7.0.0-beta.8` | 알림 본문 (다국어 문구 — `extensions.alerts.incompatible_message` / `recovered_body`) |
|
||||
| extension_type | string | `plugin` | 대상 확장 종류 (`module` / `plugin` / `template`) |
|
||||
| identifier | string | `sirsoft-gdpr` | 대상 확장 식별자 |
|
||||
| recover_endpoint | string | `/api/admin/extensions/plugin/sirsoft-gdpr/recover` | 재활성화 호출 엔드포인트 (재호환 알림 `subtype=recovery_available` 에만 존재) |
|
||||
| time | string\|null | `3시간 전` | 자동 비활성화 시각의 상대 표시 (diffForHumans() 산물, 비활성화 시각이 없으면 `null`) |
|
||||
| read | boolean | `false` | 읽음 여부 (주입 시점에는 항상 `false`) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
@@ -151,6 +163,8 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
알릴 항목이 없는 경우 (기본):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
@@ -159,6 +173,42 @@ HTTP/1.1 200
|
||||
}
|
||||
```
|
||||
|
||||
코어 비호환으로 자동 비활성화된 확장이 있는 경우:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "시스템 알림을 성공적으로 조회했습니다.",
|
||||
"data": [
|
||||
{
|
||||
"id": "compat_plugins_sirsoft-gdpr",
|
||||
"type": "warning",
|
||||
"subtype": "incompatible_core",
|
||||
"icon": "exclamation-triangle",
|
||||
"title": "플러그인 \"sirsoft-gdpr\" 자동 비활성화됨",
|
||||
"message": "필요 버전: 7.0.0-beta.9, 현재 설치됨: 7.0.0-beta.8",
|
||||
"extension_type": "plugin",
|
||||
"identifier": "sirsoft-gdpr",
|
||||
"time": "3시간 전",
|
||||
"read": false
|
||||
},
|
||||
{
|
||||
"id": "recover_modules_sirsoft-board",
|
||||
"type": "info",
|
||||
"subtype": "recovery_available",
|
||||
"icon": "check-circle",
|
||||
"title": "모듈 \"sirsoft-board\" 다시 호환 가능",
|
||||
"message": "코어 업그레이드 후 호환됩니다 (이전 요구: 7.0.0-beta.9). 다시 활성화할 수 있습니다.",
|
||||
"extension_type": "module",
|
||||
"identifier": "sirsoft-board",
|
||||
"recover_endpoint": "/api/admin/extensions/module/sirsoft-board/recover",
|
||||
"time": "2일 전",
|
||||
"read": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
|
||||
@@ -102,11 +102,27 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| alert_id | string | `compat_plugins_sirsoft-tosspayments` | dismiss 처리된 자동 비활성화 알림의 식별자 (`compat_{type}s_{identifier}` 형식). 재호환 알림(`recover_{type}s_{identifier}`)도 함께 dismiss 되지만 응답에는 포함되지 않음 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "알림을 닫았습니다.",
|
||||
"data": {
|
||||
"alert_id": "compat_plugins_sirsoft-tosspayments"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -145,11 +161,29 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| extension_type | string | `plugin` | 복구(재활성화)된 확장의 타입 (`module` \| `plugin` \| `template`) — 요청 path의 `{type}` 을 그대로 반환 |
|
||||
| identifier | string | `sirsoft-tosspayments` | 복구된 확장의 식별자 — 요청 path의 `{identifier}` 를 그대로 반환 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "확장이 다시 활성화되었습니다.",
|
||||
"data": {
|
||||
"extension_type": "plugin",
|
||||
"identifier": "sirsoft-tosspayments"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -157,7 +191,8 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.activate`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 (`extensions.errors.not_found`) |
|
||||
| 422 | Unprocessable Entity | 재검증 결과 여전히 코어 버전이 요구 버전에 미달하는 경우 — 글로벌 핸들러가 `core_version_mismatch` 로 변환 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
|
||||
+628
-68
@@ -93,7 +93,7 @@ HTTP/1.1 200
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "messages.success",
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": {
|
||||
"data": [
|
||||
{
|
||||
@@ -221,7 +221,7 @@ HTTP/1.1 200
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "messages.success",
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": {
|
||||
"purged_count": 200,
|
||||
"older_than_days": 1
|
||||
@@ -414,11 +414,99 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (생성된 정의를 `IdentityMessageDefinitionResource` 로 직렬화, `templates` eager load 포함). 성공 시 HTTP 201._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `13` | 기본 키 (내부 식별자) |
|
||||
| provider_id | string | `g7:core.mail` | 이 정의가 속한 IDV 프로바이더 ID |
|
||||
| scope_type | string | `policy` | 메시지 정의 스코프 (관리자 생성은 항상 `policy`) |
|
||||
| scope_value | string | `admin.custom_action` | 스코프 값 (source_type='admin' 인 IdentityPolicy.key) |
|
||||
| name | object | `{"ko":"...","en":"..."}` | 다국어 표시명 |
|
||||
| description | object | `{"ko":"...","en":"..."}` | 다국어 설명 (미전달 시 null) |
|
||||
| channels | array | `["mail"]` | 이 정의가 지원하는 활성 채널 목록 |
|
||||
| variables | array | `[{"key":"code","description":"인증 코드"}]` | 템플릿 치환 가능 변수 메타데이터 목록 (미전달 시 null) |
|
||||
| extension_type | string | `core` | 이 리소스를 소유한 확장의 타입 (관리자 생성은 core) |
|
||||
| extension_identifier | string | `core` | 이 리소스를 소유한 확장의 식별자 |
|
||||
| is_active | boolean | `true` | 활성 여부 |
|
||||
| is_default | boolean | `false` | 시드 기본 정의 여부 (관리자 생성 정의는 false → 삭제 가능) |
|
||||
| user_overrides | array | `null` | 운영자가 시드 기본값에서 수정한 필드 경로 목록 (신규 생성 직후 null) |
|
||||
| templates | array | `[{"id":13,"definition_id":13,"channel":"mail","subject":{…},"body":{…}}]` | 함께 생성된 채널별 하위 템플릿 목록 |
|
||||
| created_at | string | `2026-07-08 10:43:32` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-08 10:43:32` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 201
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "IDV 메시지 정의가 생성되었습니다.",
|
||||
"data": {
|
||||
"id": 13,
|
||||
"provider_id": "g7:core.mail",
|
||||
"scope_type": "policy",
|
||||
"scope_value": "admin.custom_action",
|
||||
"name": {
|
||||
"ko": "커스텀 민감작업 인증",
|
||||
"en": "Custom Sensitive Action"
|
||||
},
|
||||
"description": {
|
||||
"ko": "운영자가 등록한 정책 전용 인증 메일",
|
||||
"en": "Policy-specific verification mail added by admin"
|
||||
},
|
||||
"channels": [
|
||||
"mail"
|
||||
],
|
||||
"variables": [
|
||||
{
|
||||
"key": "code",
|
||||
"description": "인증 코드 (text_code 흐름)"
|
||||
}
|
||||
],
|
||||
"extension_type": "core",
|
||||
"extension_identifier": "core",
|
||||
"is_active": true,
|
||||
"is_default": false,
|
||||
"user_overrides": null,
|
||||
"templates": [
|
||||
{
|
||||
"id": 13,
|
||||
"definition_id": 13,
|
||||
"channel": "mail",
|
||||
"subject": {
|
||||
"ko": "[{app_name}] 인증 코드",
|
||||
"en": "[{app_name}] Verification Code"
|
||||
},
|
||||
"body": {
|
||||
"ko": "<p>인증 코드: {code}</p>",
|
||||
"en": "<p>Your code: {code}</p>"
|
||||
},
|
||||
"is_active": true,
|
||||
"is_default": false,
|
||||
"user_overrides": null,
|
||||
"updated_by": null,
|
||||
"created_at": "2026-07-08 10:43:32",
|
||||
"updated_at": "2026-07-08 10:43:32",
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"created_at": "2026-07-08 10:43:32",
|
||||
"updated_at": "2026-07-08 10:43:32",
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -427,6 +515,7 @@ Content-Type: application/json
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 정의 생성 중 예외 발생 (`IDV 메시지 정의 생성에 실패했습니다.`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -456,20 +545,26 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — 컨트롤러가 `$this->success(__('identity_message.definition_deleted'))` 를 인자 1개로 호출)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "IDV 메시지 정의가 삭제되었습니다."
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.messages.update`)이 없는 경우, 또는 대상 정의가 시드 기본 정의(`is_default=true`)인 경우 (`시드된 기본 메시지 정의는 삭제할 수 없습니다.`) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 삭제 중 예외 발생 (`IDV 메시지 정의 삭제에 실패했습니다.`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -670,20 +765,111 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (수정된 정의를 `IdentityMessageDefinitionResource` 로 직렬화, `templates` eager load 포함 — GET 상세 응답과 동일 구조)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| provider_id | string | `g7:core.mail` | IDV 프로바이더 ID |
|
||||
| scope_type | string | `purpose` | 메시지 정의 스코프 (provider_default\|purpose\|policy) |
|
||||
| scope_value | string | `checkout_verification` | 범위 값 (provider_default 빈 문자열 / purpose 키 / policy 키) |
|
||||
| name | object | `{"ko":"결제 시 본인 확인","en":"Checkout Verification"}` | 다국어 표시명 (수정 반영) |
|
||||
| description | object | `{"ko":"...","en":"..."}` | 다국어 설명 (수정 반영) |
|
||||
| channels | array | `["mail"]` | 활성 채널 목록 (수정 반영) |
|
||||
| variables | array | `[{"key":"code","description":"인증 코드 (text_code 흐름)"}]` | 템플릿 치환 변수 메타데이터 목록 |
|
||||
| extension_type | string | `module` | 이 리소스를 소유한 확장의 타입 |
|
||||
| extension_identifier | string | `sirsoft-ecommerce` | 이 리소스를 소유한 확장의 식별자 |
|
||||
| is_active | boolean | `true` | 활성 여부 (수정 반영) |
|
||||
| is_default | boolean | `true` | 시드 기본 정의 여부 |
|
||||
| user_overrides | array | `["name","channels"]` | 이번 수정으로 append 된 운영자 재정의 필드 목록 (시더 재실행 시 보존 대상) |
|
||||
| templates | array | `[{"id":1,"definition_id":1,"channel":"mail",…}]` | 채널별 하위 템플릿 목록 |
|
||||
| created_at | string | `2026-07-08 10:43:32` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-08 12:14:36` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_update":true,"can_delete":false}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "IDV 메시지 정의가 수정되었습니다.",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"provider_id": "g7:core.mail",
|
||||
"scope_type": "purpose",
|
||||
"scope_value": "checkout_verification",
|
||||
"name": {
|
||||
"ko": "결제 시 본인 확인",
|
||||
"en": "Checkout Verification"
|
||||
},
|
||||
"description": {
|
||||
"ko": "결제 진행 전 본인/성인 확인 인증 코드 메일",
|
||||
"en": "Identity/adult verification code mail before checkout"
|
||||
},
|
||||
"channels": [
|
||||
"mail"
|
||||
],
|
||||
"variables": [
|
||||
{
|
||||
"key": "code",
|
||||
"description": "인증 코드 (text_code 흐름)"
|
||||
}
|
||||
],
|
||||
"extension_type": "module",
|
||||
"extension_identifier": "sirsoft-ecommerce",
|
||||
"is_active": true,
|
||||
"is_default": true,
|
||||
"user_overrides": [
|
||||
"name"
|
||||
],
|
||||
"templates": [
|
||||
{
|
||||
"id": 1,
|
||||
"definition_id": 1,
|
||||
"channel": "mail",
|
||||
"subject": {
|
||||
"ko": "[{app_name}] 결제 본인 확인 인증 코드",
|
||||
"en": "[{app_name}] Checkout Verification Code"
|
||||
},
|
||||
"body": {
|
||||
"ko": "<h1>결제 본인 확인</h1>…",
|
||||
"en": "<h1>Checkout Verification</h1>…"
|
||||
},
|
||||
"is_active": true,
|
||||
"is_default": true,
|
||||
"user_overrides": null,
|
||||
"updated_by": null,
|
||||
"created_at": "2026-07-08 10:43:32",
|
||||
"updated_at": "2026-07-08 10:43:32",
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"created_at": "2026-07-08 10:43:32",
|
||||
"updated_at": "2026-07-08 12:14:36",
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.messages.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 수정 중 예외 발생 (`IDV 메시지 정의 수정에 실패했습니다.`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -1002,19 +1188,38 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`IdentityMessageTemplate::replaceVariables()` 의 반환값 — 저장 없이 렌더 결과만 반환)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| subject | string | `[G7] 결제 본인 확인 인증 코드` | 지정 로케일 제목에 `{key}` 변수를 `data` 값으로 치환한 결과 문자열 |
|
||||
| body | string | `<h1>결제 본인 확인</h1><p>… 123456 …</p>` | 지정 로케일 본문(HTML)에 `{key}` 변수를 치환한 결과 문자열 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "IDV 메시지 템플릿 미리보기를 생성했습니다.",
|
||||
"data": {
|
||||
"subject": "[G7] 결제 본인 확인 인증 코드",
|
||||
"body": "<h1>결제 본인 확인</h1><p>결제를 진행하기 위해 본인 확인이 필요합니다. 아래 인증 코드를 입력해 주세요.</p><p style=\"font-size:28px; font-weight:bold; letter-spacing:4px; text-align:center; padding:16px; background:#f4f6f8; border-radius:6px;\">123456</p><p>이 코드는 <strong>5분</strong> 후 만료됩니다.</p>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.messages.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | `template_id` 에 해당하는 템플릿이 없거나(`findOrFail`) 렌더 중 예외 발생 (`IDV 메시지 템플릿 미리보기 생성에 실패했습니다.`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -1060,20 +1265,71 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (수정된 템플릿을 `IdentityMessageTemplateResource` 로 직렬화 — templates reset 응답과 동일 구조)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| definition_id | integer | `1` | 이 템플릿이 속한 메시지 정의 ID |
|
||||
| channel | string | `mail` | 메시지 템플릿 채널 (mail 현재 / sms 등 향후) |
|
||||
| subject | object | `{"ko":"[{app_name}] 결제 본인 확인 인증 코드","en":"…"}` | 다국어 제목 (수정 반영, mail 채널에서만 의미) |
|
||||
| body | object | `{"ko":"<h1>결제 본인 확인</h1>…","en":"…"}` | 다국어 본문 (수정 반영) |
|
||||
| is_active | boolean | `true` | 활성 여부 (수정 반영) |
|
||||
| is_default | boolean | `false` | 시더 기본값 유지 여부 (운영자 수정 시 false) |
|
||||
| user_overrides | array | `["subject","body"]` | 이번 수정으로 append 된 운영자 재정의 필드 목록 |
|
||||
| updated_by | null | `null` | 최종 수정한 사용자 정보 (uuid/name — 없으면 null) |
|
||||
| created_at | string | `2026-07-08 10:43:32` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-08 12:14:36` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "IDV 메시지 템플릿이 수정되었습니다.",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"definition_id": 1,
|
||||
"channel": "mail",
|
||||
"subject": {
|
||||
"ko": "[{app_name}] 결제 본인 확인 인증 코드",
|
||||
"en": "[{app_name}] Checkout Verification Code"
|
||||
},
|
||||
"body": {
|
||||
"ko": "<h1>결제 본인 확인</h1><p>아래 인증 코드를 입력해 주세요.</p><p>{code}</p>",
|
||||
"en": "<h1>Checkout Verification</h1><p>Please enter the code below.</p><p>{code}</p>"
|
||||
},
|
||||
"is_active": true,
|
||||
"is_default": false,
|
||||
"user_overrides": [
|
||||
"subject",
|
||||
"body"
|
||||
],
|
||||
"updated_by": null,
|
||||
"created_at": "2026-07-08 10:43:32",
|
||||
"updated_at": "2026-07-08 12:14:36",
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.messages.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 수정 중 예외 발생 (`IDV 메시지 템플릿 수정에 실패했습니다.`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -1325,7 +1581,7 @@ HTTP/1.1 200
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "messages.success",
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": {
|
||||
"data": [
|
||||
{
|
||||
@@ -1458,19 +1714,72 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (생성된 정책을 `PolicyResource` 로 직렬화). 성공 시 HTTP 201._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `25` | 기본 키 (내부 식별자) |
|
||||
| key | string | `admin.custom_action` | 정책 식별자 (고유) |
|
||||
| scope | string | `route` | 정책 적용 범위 (route / hook / custom — IdentityPolicyScope) |
|
||||
| target | string | `api.me.password.update` | 매칭 대상 (라우트명/URI 패턴, 훅 이름, 또는 custom key) |
|
||||
| purpose | string | `sensitive_action` | 이 정책이 요구하는 인증 목적 |
|
||||
| provider_id | null | `null` | 강제할 프로바이더 ID (미지정 시 null → 목적 기본 프로바이더 사용) |
|
||||
| grace_minutes | integer | `30` | 재인증 유예 시간(분) — 0=매번 요구 |
|
||||
| enabled | boolean | `true` | 정책 사용 여부 |
|
||||
| priority | integer | `100` | 정책 우선순위 (작을수록 우선) |
|
||||
| conditions | object | `{"changed_fields":["email"]}` | 추가 매칭 조건 JSON (미지정 시 null) |
|
||||
| source_type | string | `admin` | 정책 출처 — 이 엔드포인트로 생성한 정책은 항상 `admin` |
|
||||
| source_identifier | string | `null` | 출처 식별자 (요청에서 전달한 값, 미전달 시 null) |
|
||||
| applies_to | string | `both` | 적용 대상 사용자 (self / admin / both) |
|
||||
| fail_mode | string | `block` | 실패 시 동작 (block: HTTP 428 차단 / log_only: 감사 로그만) |
|
||||
| user_overrides | array | `[]` | 운영자가 선언 기본값에서 재정의한 필드 목록 (admin 정책은 빈 배열) |
|
||||
| created_at | string | `2026-07-08 10:44:35` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-08 10:44:35` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 201
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "생성되었습니다.",
|
||||
"data": {
|
||||
"id": 25,
|
||||
"key": "admin.custom_action",
|
||||
"scope": "route",
|
||||
"target": "api.me.password.update",
|
||||
"purpose": "sensitive_action",
|
||||
"provider_id": null,
|
||||
"grace_minutes": 30,
|
||||
"enabled": true,
|
||||
"priority": 100,
|
||||
"conditions": null,
|
||||
"source_type": "admin",
|
||||
"source_identifier": null,
|
||||
"applies_to": "both",
|
||||
"fail_mode": "block",
|
||||
"user_overrides": [],
|
||||
"created_at": "2026-07-08 10:44:35",
|
||||
"updated_at": "2026-07-08 10:44:35",
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.policies.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지 — `key` 중복, `scope`/`applies_to`/`fail_mode` 허용값 위반 등) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -1502,20 +1811,30 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — 컨트롤러가 `$this->success('messages.deleted')` 를 인자 1개로 호출)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "삭제되었습니다."
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.policies.update`)이 없는 경우, 또는 대상 정책의 `source_type` 이 `admin` 이 아닌 선언형 정책(core/module/plugin)인 경우 (`messages.cannot_delete_system_resource`) |
|
||||
| 404 | Not Found | 해당 ID 의 정책이 없는 경우 (`messages.not_found`) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 삭제 처리 실패 (`messages.failed`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -1575,20 +1894,77 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (수정 후 `refresh()` 한 정책을 `PolicyResource` 로 직렬화 — 목록 항목과 동일 구조)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `11` | 기본 키 (내부 식별자) |
|
||||
| key | string | `sirsoft-board.report.create` | 정책 식별자 (선언형 정책은 변경 불가) |
|
||||
| scope | string | `hook` | 정책 적용 범위 (선언형 정책은 변경 불가) |
|
||||
| target | string | `sirsoft-board.report.before_create` | 매칭 대상 (선언형 정책은 변경 불가) |
|
||||
| purpose | string | `sensitive_action` | 이 정책이 요구하는 인증 목적 (수정 반영) |
|
||||
| provider_id | null | `null` | 강제할 프로바이더 ID (수정 반영) |
|
||||
| grace_minutes | integer | `30` | 재인증 유예 시간(분) (수정 반영) |
|
||||
| enabled | boolean | `true` | 정책 사용 여부 (수정 반영) |
|
||||
| priority | integer | `100` | 정책 우선순위 (수정 반영) |
|
||||
| conditions | object | `null` | 추가 매칭 조건 JSON (수정 반영) |
|
||||
| source_type | string | `module` | 정책 출처 (core/module/plugin/admin) |
|
||||
| source_identifier | string | `sirsoft-board` | 출처 식별자 |
|
||||
| applies_to | string | `self` | 적용 대상 사용자 (수정 반영) |
|
||||
| fail_mode | string | `block` | 실패 시 동작 (수정 반영) |
|
||||
| user_overrides | array | `["enabled","grace_minutes"]` | 이번 수정으로 append 된 운영자 재정의 필드 목록 (시더 재실행 시 보존) |
|
||||
| created_at | string | `2026-07-08 10:44:35` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-08 12:14:36` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "수정되었습니다.",
|
||||
"data": {
|
||||
"id": 11,
|
||||
"key": "sirsoft-board.report.create",
|
||||
"scope": "hook",
|
||||
"target": "sirsoft-board.report.before_create",
|
||||
"purpose": "sensitive_action",
|
||||
"provider_id": null,
|
||||
"grace_minutes": 30,
|
||||
"enabled": true,
|
||||
"priority": 100,
|
||||
"conditions": null,
|
||||
"source_type": "module",
|
||||
"source_identifier": "sirsoft-board",
|
||||
"applies_to": "self",
|
||||
"fail_mode": "block",
|
||||
"user_overrides": [
|
||||
"enabled",
|
||||
"grace_minutes"
|
||||
],
|
||||
"created_at": "2026-07-08 10:44:35",
|
||||
"updated_at": "2026-07-08 12:14:36",
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.policies.update`)이 없는 경우 |
|
||||
| 404 | Not Found | 해당 ID 의 정책이 없는 경우 (`messages.not_found`) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우, 또는 선언형 정책에 화이트리스트(`enabled`/`grace_minutes`/`provider_id`/`fail_mode`/`conditions`/`purpose`/`applies_to`/`priority`) 밖 필드만 전달되어 적용할 값이 남지 않은 경우 (`validation.nothing_to_update`) |
|
||||
| 500 | Internal Server Error | 수정 처리 실패 (`messages.failed`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -1626,20 +2002,73 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (복원 후 `fresh()` 한 정책을 `PolicyResource` 로 직렬화 — 목록 항목과 동일 구조)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `11` | 기본 키 (내부 식별자) |
|
||||
| key | string | `sirsoft-board.report.create` | 정책 식별자 |
|
||||
| scope | string | `hook` | 정책 적용 범위 (route / hook / custom) |
|
||||
| target | string | `sirsoft-board.report.before_create` | 매칭 대상 |
|
||||
| purpose | string | `sensitive_action` | 이 정책이 요구하는 인증 목적 |
|
||||
| provider_id | null | `null` | 강제할 프로바이더 ID |
|
||||
| grace_minutes | integer | `0` | 재인증 유예 시간(분) — 요청한 `field` 가 이 필드였다면 선언 기본값으로 복원된 값 |
|
||||
| enabled | boolean | `false` | 정책 사용 여부 — 요청한 `field` 가 이 필드였다면 선언 기본값으로 복원된 값 |
|
||||
| priority | integer | `100` | 정책 우선순위 |
|
||||
| conditions | object | `null` | 추가 매칭 조건 JSON |
|
||||
| source_type | string | `module` | 정책 출처 (admin 이면 이 엔드포인트는 403) |
|
||||
| source_identifier | string | `sirsoft-board` | 출처 식별자 |
|
||||
| applies_to | string | `self` | 적용 대상 사용자 |
|
||||
| fail_mode | string | `block` | 실패 시 동작 |
|
||||
| user_overrides | array | `[]` | 남아 있는 운영자 재정의 필드 목록 (요청한 `field` 가 제거된 상태) |
|
||||
| created_at | string | `2026-07-08 10:44:35` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-08 12:20:11` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": {
|
||||
"id": 11,
|
||||
"key": "sirsoft-board.report.create",
|
||||
"scope": "hook",
|
||||
"target": "sirsoft-board.report.before_create",
|
||||
"purpose": "sensitive_action",
|
||||
"provider_id": null,
|
||||
"grace_minutes": 0,
|
||||
"enabled": false,
|
||||
"priority": 100,
|
||||
"conditions": null,
|
||||
"source_type": "module",
|
||||
"source_identifier": "sirsoft-board",
|
||||
"applies_to": "self",
|
||||
"fail_mode": "block",
|
||||
"user_overrides": [],
|
||||
"created_at": "2026-07-08 10:44:35",
|
||||
"updated_at": "2026-07-08 12:20:11",
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.policies.update`)이 없는 경우, 또는 대상 정책의 `source_type` 이 `admin` 이라 선언 기본값이 존재하지 않는 경우 (`관리자가 직접 생성한 정책에는 선언 기본값이 없습니다.`) |
|
||||
| 404 | Not Found | 해당 ID 의 정책이 없는 경우 (`messages.not_found`) |
|
||||
| 422 | Unprocessable Entity | `field` 가 허용값 밖이거나 복원에 실패한 경우 (`선언 기본값 복원에 실패했습니다. 필드가 유효한지 확인하세요.`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -1687,7 +2116,7 @@ HTTP/1.1 200
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "messages.success",
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": [
|
||||
{
|
||||
"id": "g7:core.mail",
|
||||
@@ -1831,20 +2260,49 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (성공 + `return` 쿼리가 없을 때만 JSON 을 반환합니다. `return` 이 있고 same-origin 이면 302 redirect 이므로 본문이 없습니다)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| challenge_id | string | `00484973-8cd3-4a1d-85f2-78361feb6f0d` | 검증이 완료된 challenge 의 식별자 |
|
||||
| provider_id | string | `inicis` | 이 콜백을 처리한 프로바이더 식별자 |
|
||||
| verified_at | string | `2026-05-12T18:14:19+00:00` | 검증 완료 일시 (ISO 8601, 미검증이면 null) |
|
||||
| verification_token | string | `eyJ0eXAiOiJKV1QiLCJhbGciOi…` | 후속 민감 작업 요청에 제출할 본인인증 토큰 (`claims.verification_token`, 없으면 빈 문자열) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "본인 확인이 완료되었습니다.",
|
||||
"data": {
|
||||
"challenge_id": "00484973-8cd3-4a1d-85f2-78361feb6f0d",
|
||||
"provider_id": "inicis",
|
||||
"verified_at": "2026-05-12T18:14:19+00:00",
|
||||
"verification_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`return` 쿼리(same-origin) 가 있으면 JSON 대신 302 redirect 입니다.
|
||||
|
||||
```http
|
||||
HTTP/1.1 302
|
||||
Location: /checkout?verification_token=eyJ0eXAiOiJKV1Qi...&challenge_id=00484973-8cd3-4a1d-85f2-78361feb6f0d
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 302 | Found (실패 redirect) | 검증 실패 + `return` 쿼리(same-origin) 존재 시 `{return}?identity_error={failure_code}` 로 리다이렉트 |
|
||||
| 401 | Unauthenticated | Bearer 토큰을 보냈으나 만료/무효인 경우 (비회원은 헤더 생략 가능) |
|
||||
| 404 | Not Found | `providerId` 에 해당하는 프로바이더가 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터 검증 실패, 또는 검증 실패 + `return` 쿼리 없음 — 본문의 `error.failure_code` 에 실패 사유 코드 (`CHALLENGE_NOT_FOUND`/`EXPIRED`/`INVALID_CODE` 등, `identity.errors.*` 메시지 동반) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -1863,8 +2321,8 @@ Content-Type: application/json
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| purpose | body | string | 예 | max 64 | 인증 목적 (signup/password_reset/self_update/sensitive_action/login 또는 모듈 정의 목적) |
|
||||
| target | body | array | 아니오 | — | 비로그인 게스트의 인증 대상 (target.email 또는 target.phone — 로그인 사용자는 본인으로 자동 설정) |
|
||||
| target.email | body | email | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| target.phone | body | string | 아니오 | max 32 | <!-- TODO: 용도 --> |
|
||||
| target.email | body | email | 아니오 | max 255 | 이메일 주소 |
|
||||
| target.phone | body | string | 아니오 | max 32 | 전화번호 |
|
||||
| provider_id | body | string | 아니오 | max 64 | provider 식별자 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.identity.request_validation_rules`).
|
||||
@@ -1891,19 +2349,51 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-429 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`ChallengeResource` 로 직렬화한 VerificationChallenge DTO — 민감 metadata(code_hash 등) 제외). 성공 시 HTTP 201._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | string | `00484973-8cd3-4a1d-85f2-78361feb6f0d` | 생성된 challenge 의 식별자 (이후 verify/cancel/show 에 사용) |
|
||||
| provider_id | string | `g7:core.mail` | 이 challenge 를 처리하는 프로바이더 식별자 |
|
||||
| purpose | string | `signup` | 인증 목적 |
|
||||
| channel | string | `email` | 실제 발송에 사용된 전송 채널 |
|
||||
| render_hint | string | `text_code` | 프론트 렌더 방식 힌트 (text_code / link / external_redirect) |
|
||||
| redirect_url | string | `null` | external_redirect 흐름에서 사용자를 보낼 외부 인증 페이지 URL (그 외 흐름은 null) |
|
||||
| expires_at | string | `2026-05-12T18:14:19+00:00` | 만료 일시 (ISO 8601) |
|
||||
| public_payload | array | `[]` | 프론트 렌더에 필요한 공개 안전 페이로드 (프로바이더별 UI 힌트, 없으면 빈 배열) |
|
||||
| max_attempts | integer | `5` | 허용되는 최대 검증 시도 횟수 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-429 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 201
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "본인인증 코드를 발송했습니다.",
|
||||
"data": {
|
||||
"id": "00484973-8cd3-4a1d-85f2-78361feb6f0d",
|
||||
"provider_id": "g7:core.mail",
|
||||
"purpose": "signup",
|
||||
"channel": "email",
|
||||
"render_hint": "text_code",
|
||||
"redirect_url": null,
|
||||
"expires_at": "2026-05-12T18:14:19+00:00",
|
||||
"public_payload": [],
|
||||
"max_attempts": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 401 | Unauthenticated | Bearer 토큰을 보냈으나 만료/무효인 경우 (비회원은 헤더 생략 가능) |
|
||||
| 403 | Forbidden | 요구 권한(`core.identity.request`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터 검증 실패, 또는 비로그인 상태에서 `target.email`·`target.phone` 이 모두 비어 있는 경우 (`인증 대상(이메일·전화번호)이 필요합니다.`), 선택한 프로바이더가 해당 목적을 지원하지 않는 경우(`선택된 프로바이더는 이 목적을 지원하지 않습니다.`), 프로바이더 사용 불가(`본인인증 프로바이더를 사용할 수 없습니다.`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -1957,7 +2447,7 @@ HTTP/1.1 200
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "messages.success",
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": {
|
||||
"id": "006209fd-1b6c-40aa-a38f-9b907f1a4bca",
|
||||
"status": "requested",
|
||||
@@ -2008,19 +2498,28 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-429 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — 컨트롤러가 `$this->success('identity.messages.challenge_cancelled')` 를 인자 1개로 호출)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-429 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "본인인증 요청이 취소되었습니다."
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 401 | Unauthenticated | Bearer 토큰을 보냈으나 만료/무효인 경우 (비회원은 헤더 생략 가능) |
|
||||
| 403 | Forbidden | 요구 권한(`core.identity.cancel`)이 없는 경우, 또는 scope=self 가드가 본인 challenge 가 아니라고 판정한 경우 |
|
||||
| 404 | Not Found | path 의 challenge 를 찾을 수 없거나 취소 처리에 실패한 경우 (`유효하지 않은 인증 요청입니다.`) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
@@ -2061,20 +2560,42 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-429 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (컨트롤러가 VerificationResult DTO 에서 직접 조립)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| challenge_id | string | `00484973-8cd3-4a1d-85f2-78361feb6f0d` | 검증이 완료된 challenge 의 식별자 |
|
||||
| provider_id | string | `g7:core.mail` | 이 challenge 를 처리한 프로바이더 식별자 |
|
||||
| verified_at | string | `2026-05-12T18:14:19+00:00` | 검증 완료 일시 (ISO 8601, 없으면 null) |
|
||||
| verification_token | string | `eyJ0eXAiOiJKV1QiLCJhbGciOi…` | 후속 민감 작업 요청에 제출할 본인인증 토큰 (`claims.verification_token`, 없으면 null) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-429 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "본인 확인이 완료되었습니다.",
|
||||
"data": {
|
||||
"challenge_id": "00484973-8cd3-4a1d-85f2-78361feb6f0d",
|
||||
"provider_id": "g7:core.mail",
|
||||
"verified_at": "2026-05-12T18:14:19+00:00",
|
||||
"verification_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 401 | Unauthenticated | Bearer 토큰을 보냈으나 만료/무효인 경우 (비회원은 헤더 생략 가능) |
|
||||
| 403 | Forbidden | 요구 권한(`core.identity.verify`)이 없는 경우, 또는 scope=self 가드가 본인 challenge 가 아니라고 판정한 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 challenge 가 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 검증 실패 — 응답 `error` 에 `failure_code`(예: `INVALID_CODE`/`EXPIRED`/`MAX_ATTEMPTS`) 와 서버 기준 `attempts`/`max_attempts` 를 함께 반환. 메시지는 `identity.errors.*` (`인증 코드가 올바르지 않습니다.` / `인증 시간이 만료되었습니다. 다시 시도해주세요.` / `시도 횟수를 초과했습니다. 다시 요청해주세요.` 등) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -2105,19 +2626,58 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (매칭·활성 정책이 없으면 `data` 는 `null`). 컨트롤러가 UI 힌트용 최소 필드만 직접 조립하며 민감 필드는 노출하지 않습니다._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| policy_key | string | `sirsoft-board.report.create` | 매칭된 정책의 식별자 |
|
||||
| scope | string | `hook` | 정책 적용 범위 (route / hook / custom) |
|
||||
| target | string | `sirsoft-board.report.before_create` | 매칭 대상 |
|
||||
| purpose | string | `sensitive_action` | 이 정책이 요구하는 인증 목적 |
|
||||
| provider_id | null | `null` | 강제할 프로바이더 ID (미지정 시 null) |
|
||||
| grace_minutes | integer | `30` | 재인증 유예 시간(분) — 0=매번 요구 |
|
||||
| applies_to | string | `self` | 적용 대상 사용자 (self / admin / both) |
|
||||
| fail_mode | string | `block` | 실패 시 동작 (block: HTTP 428 차단 / log_only: 감사 로그만) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": {
|
||||
"policy_key": "sirsoft-board.report.create",
|
||||
"scope": "hook",
|
||||
"target": "sirsoft-board.report.before_create",
|
||||
"purpose": "sensitive_action",
|
||||
"provider_id": null,
|
||||
"grace_minutes": 30,
|
||||
"applies_to": "self",
|
||||
"fail_mode": "block"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
매칭 정책이 없거나 `enabled=false` 인 경우:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.admin.identity.logs.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 401 | Unauthenticated | Bearer 토큰을 보냈으나 만료/무효인 경우 (비회원은 헤더 생략 가능) |
|
||||
| 422 | Unprocessable Entity | 필수 쿼리 `scope`/`target` 누락 또는 길이 초과 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -2163,7 +2723,7 @@ HTTP/1.1 200
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "messages.success",
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": [
|
||||
{
|
||||
"id": "g7:core.mail",
|
||||
@@ -2251,7 +2811,7 @@ HTTP/1.1 200
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "messages.success",
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": [
|
||||
{
|
||||
"id": "signup",
|
||||
|
||||
@@ -248,11 +248,41 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`LanguagePackService::bulkActivate()` 반환값)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| succeeded | array | `[3, 5]` | 활성화에 성공한 언어팩 ID 목록 |
|
||||
| failed | array | `[{"id": 7, "reason": "not_found"}]` | 활성화에 실패한 항목 목록 (요소: `id`, `reason`) |
|
||||
| failed[].id | integer\|string | `7` | 실패한 항목의 요청 ID (요청 `ids` 원본 값) |
|
||||
| failed[].reason | string | `not_found` | 실패 사유. 대상 미존재 시 `not_found`, 그 외에는 발생한 예외 메시지 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "language_packs.bulk_activate_success",
|
||||
"data": {
|
||||
"succeeded": [
|
||||
3,
|
||||
5
|
||||
],
|
||||
"failed": [
|
||||
{
|
||||
"id": 7,
|
||||
"reason": "not_found"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `message` 는 `language_packs.bulk_activate_success` 키로 응답하지만, 현재 `lang/ko/language_packs.php` 에 해당 키가 정의되어 있지 않아 번역되지 않은 키 문자열이 그대로 내려갑니다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -288,11 +318,51 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`LanguagePackService::checkUpdates()` 반환값)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| checked | integer | `3` | 실제로 검사한 언어팩 수 (GitHub URL 해석 가능하거나 번들 매니페스트가 있는 팩만 대상) |
|
||||
| updates | integer | `1` | 검사 결과 업데이트가 있는 언어팩 수 |
|
||||
| details | array | `[{"identifier": "g7-core-ja", "current": "1.0.0", "latest": "1.1.0", "has_update": true, "error": null}]` | 팩별 검사 결과 목록 |
|
||||
| details[].identifier | string | `g7-core-ja` | 검사 대상 언어팩 식별자 |
|
||||
| details[].current | string | `1.0.0` | 현재 설치된 버전 |
|
||||
| details[].latest | string\|null | `1.1.0` | 감지된 최신 버전 (GitHub 릴리스 태그 → 실패 시 번들 매니페스트 폴백, 둘 다 없으면 null) |
|
||||
| details[].has_update | boolean | `true` | `latest > current` 여부 |
|
||||
| details[].error | string\|null | `null` | GitHub 조회 중 발생한 오류 메시지 (성공 시 null) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "업데이트 확인을 완료했습니다.",
|
||||
"data": {
|
||||
"checked": 3,
|
||||
"updates": 1,
|
||||
"details": [
|
||||
{
|
||||
"identifier": "g7-core-ja",
|
||||
"current": "1.0.0",
|
||||
"latest": "1.1.0",
|
||||
"has_update": true,
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"identifier": "apidoc-sample-lang",
|
||||
"current": "1.0.0",
|
||||
"latest": "1.0.0",
|
||||
"has_update": false,
|
||||
"error": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -301,6 +371,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 업데이트 확인 중 예외 발생 (`업데이트 확인에 실패했습니다: :error` — `language_packs.check_updates_failed`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -337,11 +408,93 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (설치된 언어팩 = `LanguagePackResource::toArray()`, 상태코드 201)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| identifier | string | `g7-core-ja` | 언어팩 고유 식별자 ({vendor}-{scope}-{target?}-{locale}) |
|
||||
| vendor | string | `g7` | 언어팩 제작자 식별자 |
|
||||
| scope | string | `core` | 적용 대상 분류 (core/module/plugin/template) |
|
||||
| target_identifier | string\|null | `null` | 대상 확장 식별자 (scope=core 일 때 null) |
|
||||
| locale | string | `ja` | IETF BCP-47 locale 태그 |
|
||||
| locale_name | string | `Japanese` | 영문 언어명 |
|
||||
| locale_native_name | string | `日本語` | 원어 언어명 |
|
||||
| text_direction | string | `ltr` | 텍스트 방향 (ltr/rtl) |
|
||||
| version | string | `1.0.0` | 설치된 언어팩 버전 |
|
||||
| latest_version | string\|null | `1.0.0` | 감지된 최신 배포 버전 |
|
||||
| target_version_constraint | string\|null | `null` | 대상 확장 버전 제약 (semver) |
|
||||
| target_version_mismatch | boolean | `false` | 대상 버전 불일치 경고 플래그 |
|
||||
| name | string\|null | `일본어 언어팩` | manifest `name` 의 현재 로케일 해석값 |
|
||||
| license | string\|null | `MIT` | 라이선스 |
|
||||
| description | string\|null | `코어 일본어 번역` | 언어팩 설명 (다국어) |
|
||||
| status | string | `active` | 언어팩 상태 (auto_activate=true 면 active, 아니면 installed) |
|
||||
| is_protected | boolean | `false` | 보호(protected) 팩 여부 |
|
||||
| source_type | string | `bundled` | 설치 소스 유형 (zip/github/url/bundled/bundled_with_extension/built_in) |
|
||||
| origin | string\|null | `bundled` | source_type 에서 파생된 출처 값 (`LanguagePackOrigin`) |
|
||||
| source_url | string\|null | `null` | 설치 소스 URL 또는 경로 |
|
||||
| github_url | string\|null | `null` | GitHub 저장소 URL (manifest 파생) |
|
||||
| github_changelog_url | string\|null | `null` | GitHub 변경 이력(CHANGELOG) URL (manifest 파생) |
|
||||
| bundled_identifier | string\|null | `null` | 대응하는 번들 확장 식별자 (번들 원본 매칭용) |
|
||||
| install_blocked_reason | string\|null | `null` | 설치가 차단된 사유 (차단 없으면 null) |
|
||||
| target_name | string\|null | `null` | 대상 확장의 표시 이름 (scope+target_identifier 로 해석) |
|
||||
| installed_at | string\|null | `2026-07-05 10:41:24` | 설치 일시 (사용자 타임존) |
|
||||
| activated_at | string\|null | `2026-07-05 10:41:24` | 활성화 일시 (사용자 타임존) |
|
||||
| created_at | string\|null | `2026-07-05 10:41:24` | 생성 일시 |
|
||||
| updated_at | string\|null | `2026-07-05 10:41:24` | 최종 수정 일시 |
|
||||
| has_update | boolean | `false` | `latest_version > version` 여부 |
|
||||
| abilities | object | `{"can_activate":true,"can_deactivate":true,"can_uninstall":true}` | 현재 사용자가 이 언어팩에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 201
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "언어팩을 설치했습니다.",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"identifier": "g7-core-ja",
|
||||
"vendor": "g7",
|
||||
"scope": "core",
|
||||
"target_identifier": null,
|
||||
"locale": "ja",
|
||||
"locale_name": "Japanese",
|
||||
"locale_native_name": "日本語",
|
||||
"text_direction": "ltr",
|
||||
"version": "1.0.0",
|
||||
"latest_version": "1.0.0",
|
||||
"target_version_constraint": null,
|
||||
"target_version_mismatch": false,
|
||||
"name": "일본어 언어팩",
|
||||
"license": "MIT",
|
||||
"description": "코어 일본어 번역",
|
||||
"status": "active",
|
||||
"is_protected": false,
|
||||
"source_type": "bundled",
|
||||
"origin": "bundled",
|
||||
"source_url": null,
|
||||
"github_url": null,
|
||||
"github_changelog_url": null,
|
||||
"bundled_identifier": null,
|
||||
"install_blocked_reason": null,
|
||||
"target_name": null,
|
||||
"installed_at": "2026-07-05 10:41:24",
|
||||
"activated_at": "2026-07-05 10:41:24",
|
||||
"created_at": "2026-07-05 10:41:24",
|
||||
"updated_at": "2026-07-05 10:41:24",
|
||||
"has_update": false,
|
||||
"abilities": {
|
||||
"can_activate": true,
|
||||
"can_deactivate": true,
|
||||
"can_uninstall": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -392,11 +545,95 @@ Content-Disposition: form-data; name="auto_activate"
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (설치된 언어팩 = `LanguagePackResource::toArray()`, 상태코드 201). 필드 구성은 [install-from-bundled](#post-apiadminlanguage-packsinstall-from-bundled) 응답과 동일합니다 — `source_type` 은 `zip`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `2` | 기본 키 (내부 식별자) |
|
||||
| identifier | string | `acme-core-de` | 언어팩 고유 식별자 |
|
||||
| vendor | string | `acme` | 언어팩 제작자 식별자 |
|
||||
| scope | string | `core` | 적용 대상 분류 (core/module/plugin/template) |
|
||||
| target_identifier | string\|null | `null` | 대상 확장 식별자 (scope=core 일 때 null) |
|
||||
| locale | string | `de` | IETF BCP-47 locale 태그 |
|
||||
| locale_name | string | `German` | 영문 언어명 |
|
||||
| locale_native_name | string | `Deutsch` | 원어 언어명 |
|
||||
| text_direction | string | `ltr` | 텍스트 방향 (ltr/rtl) |
|
||||
| version | string | `1.0.0` | 설치된 언어팩 버전 |
|
||||
| latest_version | string\|null | `null` | 감지된 최신 배포 버전 |
|
||||
| target_version_constraint | string\|null | `null` | 대상 확장 버전 제약 (semver) |
|
||||
| target_version_mismatch | boolean | `false` | 대상 버전 불일치 경고 플래그 |
|
||||
| name | string\|null | `독일어 언어팩` | manifest `name` 의 현재 로케일 해석값 |
|
||||
| license | string\|null | `MIT` | 라이선스 |
|
||||
| description | string\|null | `—` | 언어팩 설명 (다국어) |
|
||||
| status | string | `installed` | 언어팩 상태 (auto_activate=true 면 active) |
|
||||
| is_protected | boolean | `false` | 보호(protected) 팩 여부 |
|
||||
| source_type | string | `zip` | 설치 소스 유형 (파일 업로드 설치이므로 zip) |
|
||||
| origin | string\|null | `zip` | source_type 에서 파생된 출처 값 |
|
||||
| source_url | string\|null | `null` | 설치 소스 URL 또는 경로 |
|
||||
| github_url | string\|null | `null` | GitHub 저장소 URL (manifest 파생) |
|
||||
| github_changelog_url | string\|null | `null` | GitHub 변경 이력(CHANGELOG) URL (manifest 파생) |
|
||||
| bundled_identifier | string\|null | `null` | 대응하는 번들 확장 식별자 |
|
||||
| install_blocked_reason | string\|null | `null` | 설치가 차단된 사유 (차단 없으면 null) |
|
||||
| target_name | string\|null | `null` | 대상 확장의 표시 이름 |
|
||||
| installed_at | string\|null | `2026-07-05 10:41:24` | 설치 일시 (사용자 타임존) |
|
||||
| activated_at | string\|null | `null` | 활성화 일시 (미활성 시 null) |
|
||||
| created_at | string\|null | `2026-07-05 10:41:24` | 생성 일시 |
|
||||
| updated_at | string\|null | `2026-07-05 10:41:24` | 최종 수정 일시 |
|
||||
| has_update | boolean | `false` | `latest_version > version` 여부 |
|
||||
| abilities | object | `{"can_activate":true,"can_deactivate":true,"can_uninstall":true}` | 현재 사용자가 이 언어팩에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 201
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "언어팩을 설치했습니다.",
|
||||
"data": {
|
||||
"id": 2,
|
||||
"identifier": "acme-core-de",
|
||||
"vendor": "acme",
|
||||
"scope": "core",
|
||||
"target_identifier": null,
|
||||
"locale": "de",
|
||||
"locale_name": "German",
|
||||
"locale_native_name": "Deutsch",
|
||||
"text_direction": "ltr",
|
||||
"version": "1.0.0",
|
||||
"latest_version": null,
|
||||
"target_version_constraint": null,
|
||||
"target_version_mismatch": false,
|
||||
"name": "독일어 언어팩",
|
||||
"license": "MIT",
|
||||
"description": null,
|
||||
"status": "installed",
|
||||
"is_protected": false,
|
||||
"source_type": "zip",
|
||||
"origin": "zip",
|
||||
"source_url": null,
|
||||
"github_url": null,
|
||||
"github_changelog_url": null,
|
||||
"bundled_identifier": null,
|
||||
"install_blocked_reason": null,
|
||||
"target_name": null,
|
||||
"installed_at": "2026-07-05 10:41:24",
|
||||
"activated_at": null,
|
||||
"created_at": "2026-07-05 10:41:24",
|
||||
"updated_at": "2026-07-05 10:41:24",
|
||||
"has_update": false,
|
||||
"abilities": {
|
||||
"can_activate": true,
|
||||
"can_deactivate": true,
|
||||
"can_uninstall": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> manifest 검증 실패 시 422 (`language-pack.json 검증에 실패했습니다.`), 그 외 설치 실패 시 500 (`언어팩 설치에 실패했습니다: :error`) 으로 응답합니다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -441,11 +678,93 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (설치된 언어팩 = `LanguagePackResource::toArray()`, 상태코드 201). 필드 구성은 install-from-bundled 응답과 동일하며 `source_type` 이 `github`, `source_url`/`github_url` 에 저장소 URL 이 들어갑니다._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `3` | 기본 키 (내부 식별자) |
|
||||
| identifier | string | `acme-core-es` | 언어팩 고유 식별자 |
|
||||
| vendor | string | `acme` | 언어팩 제작자 식별자 |
|
||||
| scope | string | `core` | 적용 대상 분류 (core/module/plugin/template) |
|
||||
| target_identifier | string\|null | `null` | 대상 확장 식별자 (scope=core 일 때 null) |
|
||||
| locale | string | `es` | IETF BCP-47 locale 태그 |
|
||||
| locale_name | string | `Spanish` | 영문 언어명 |
|
||||
| locale_native_name | string | `Español` | 원어 언어명 |
|
||||
| text_direction | string | `ltr` | 텍스트 방향 (ltr/rtl) |
|
||||
| version | string | `1.0.0` | 설치된 언어팩 버전 (GitHub 최신 릴리스 태그 기준) |
|
||||
| latest_version | string\|null | `1.0.0` | 감지된 최신 배포 버전 |
|
||||
| target_version_constraint | string\|null | `null` | 대상 확장 버전 제약 (semver) |
|
||||
| target_version_mismatch | boolean | `false` | 대상 버전 불일치 경고 플래그 |
|
||||
| name | string\|null | `스페인어 언어팩` | manifest `name` 의 현재 로케일 해석값 |
|
||||
| license | string\|null | `MIT` | 라이선스 |
|
||||
| description | string\|null | `—` | 언어팩 설명 (다국어) |
|
||||
| status | string | `active` | 언어팩 상태 (auto_activate=true 면 active, 아니면 installed) |
|
||||
| is_protected | boolean | `false` | 보호(protected) 팩 여부 |
|
||||
| source_type | string | `github` | 설치 소스 유형 |
|
||||
| origin | string\|null | `github` | source_type 에서 파생된 출처 값 |
|
||||
| source_url | string\|null | `https://github.com/acme/g7-core-es` | 설치에 사용한 GitHub 저장소 URL |
|
||||
| github_url | string\|null | `https://github.com/acme/g7-core-es` | GitHub 저장소 URL (manifest 파생) |
|
||||
| github_changelog_url | string\|null | `null` | GitHub 변경 이력(CHANGELOG) URL (manifest 파생) |
|
||||
| bundled_identifier | string\|null | `null` | 대응하는 번들 확장 식별자 |
|
||||
| install_blocked_reason | string\|null | `null` | 설치가 차단된 사유 (차단 없으면 null) |
|
||||
| target_name | string\|null | `null` | 대상 확장의 표시 이름 |
|
||||
| installed_at | string\|null | `2026-07-05 10:41:24` | 설치 일시 (사용자 타임존) |
|
||||
| activated_at | string\|null | `2026-07-05 10:41:24` | 활성화 일시 |
|
||||
| created_at | string\|null | `2026-07-05 10:41:24` | 생성 일시 |
|
||||
| updated_at | string\|null | `2026-07-05 10:41:24` | 최종 수정 일시 |
|
||||
| has_update | boolean | `false` | `latest_version > version` 여부 |
|
||||
| abilities | object | `{"can_activate":true,"can_deactivate":true,"can_uninstall":true}` | 현재 사용자가 이 언어팩에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 201
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "언어팩을 설치했습니다.",
|
||||
"data": {
|
||||
"id": 3,
|
||||
"identifier": "acme-core-es",
|
||||
"vendor": "acme",
|
||||
"scope": "core",
|
||||
"target_identifier": null,
|
||||
"locale": "es",
|
||||
"locale_name": "Spanish",
|
||||
"locale_native_name": "Español",
|
||||
"text_direction": "ltr",
|
||||
"version": "1.0.0",
|
||||
"latest_version": "1.0.0",
|
||||
"target_version_constraint": null,
|
||||
"target_version_mismatch": false,
|
||||
"name": "스페인어 언어팩",
|
||||
"license": "MIT",
|
||||
"description": null,
|
||||
"status": "active",
|
||||
"is_protected": false,
|
||||
"source_type": "github",
|
||||
"origin": "github",
|
||||
"source_url": "https://github.com/acme/g7-core-es",
|
||||
"github_url": "https://github.com/acme/g7-core-es",
|
||||
"github_changelog_url": null,
|
||||
"bundled_identifier": null,
|
||||
"install_blocked_reason": null,
|
||||
"target_name": null,
|
||||
"installed_at": "2026-07-05 10:41:24",
|
||||
"activated_at": "2026-07-05 10:41:24",
|
||||
"created_at": "2026-07-05 10:41:24",
|
||||
"updated_at": "2026-07-05 10:41:24",
|
||||
"has_update": false,
|
||||
"abilities": {
|
||||
"can_activate": true,
|
||||
"can_deactivate": true,
|
||||
"can_uninstall": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -494,11 +813,95 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (설치된 언어팩 = `LanguagePackResource::toArray()`, 상태코드 201). 필드 구성은 install-from-bundled 응답과 동일하며 `source_type` 이 `url`, `source_url` 에 다운로드 URL 이 들어갑니다._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `4` | 기본 키 (내부 식별자) |
|
||||
| identifier | string | `acme-core-it` | 언어팩 고유 식별자 |
|
||||
| vendor | string | `acme` | 언어팩 제작자 식별자 |
|
||||
| scope | string | `core` | 적용 대상 분류 (core/module/plugin/template) |
|
||||
| target_identifier | string\|null | `null` | 대상 확장 식별자 (scope=core 일 때 null) |
|
||||
| locale | string | `it` | IETF BCP-47 locale 태그 |
|
||||
| locale_name | string | `Italian` | 영문 언어명 |
|
||||
| locale_native_name | string | `Italiano` | 원어 언어명 |
|
||||
| text_direction | string | `ltr` | 텍스트 방향 (ltr/rtl) |
|
||||
| version | string | `1.0.0` | 설치된 언어팩 버전 |
|
||||
| latest_version | string\|null | `null` | 감지된 최신 배포 버전 |
|
||||
| target_version_constraint | string\|null | `null` | 대상 확장 버전 제약 (semver) |
|
||||
| target_version_mismatch | boolean | `false` | 대상 버전 불일치 경고 플래그 |
|
||||
| name | string\|null | `이탈리아어 언어팩` | manifest `name` 의 현재 로케일 해석값 |
|
||||
| license | string\|null | `MIT` | 라이선스 |
|
||||
| description | string\|null | `—` | 언어팩 설명 (다국어) |
|
||||
| status | string | `active` | 언어팩 상태 (auto_activate=true 면 active, 아니면 installed) |
|
||||
| is_protected | boolean | `false` | 보호(protected) 팩 여부 |
|
||||
| source_type | string | `url` | 설치 소스 유형 |
|
||||
| origin | string\|null | `url` | source_type 에서 파생된 출처 값 |
|
||||
| source_url | string\|null | `https://cdn.example.com/acme-core-it.zip` | 다운로드에 사용한 URL |
|
||||
| github_url | string\|null | `null` | GitHub 저장소 URL (manifest 파생) |
|
||||
| github_changelog_url | string\|null | `null` | GitHub 변경 이력(CHANGELOG) URL (manifest 파생) |
|
||||
| bundled_identifier | string\|null | `null` | 대응하는 번들 확장 식별자 |
|
||||
| install_blocked_reason | string\|null | `null` | 설치가 차단된 사유 (차단 없으면 null) |
|
||||
| target_name | string\|null | `null` | 대상 확장의 표시 이름 |
|
||||
| installed_at | string\|null | `2026-07-05 10:41:24` | 설치 일시 (사용자 타임존) |
|
||||
| activated_at | string\|null | `2026-07-05 10:41:24` | 활성화 일시 |
|
||||
| created_at | string\|null | `2026-07-05 10:41:24` | 생성 일시 |
|
||||
| updated_at | string\|null | `2026-07-05 10:41:24` | 최종 수정 일시 |
|
||||
| has_update | boolean | `false` | `latest_version > version` 여부 |
|
||||
| abilities | object | `{"can_activate":true,"can_deactivate":true,"can_uninstall":true}` | 현재 사용자가 이 언어팩에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 201
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "언어팩을 설치했습니다.",
|
||||
"data": {
|
||||
"id": 4,
|
||||
"identifier": "acme-core-it",
|
||||
"vendor": "acme",
|
||||
"scope": "core",
|
||||
"target_identifier": null,
|
||||
"locale": "it",
|
||||
"locale_name": "Italian",
|
||||
"locale_native_name": "Italiano",
|
||||
"text_direction": "ltr",
|
||||
"version": "1.0.0",
|
||||
"latest_version": null,
|
||||
"target_version_constraint": null,
|
||||
"target_version_mismatch": false,
|
||||
"name": "이탈리아어 언어팩",
|
||||
"license": "MIT",
|
||||
"description": null,
|
||||
"status": "active",
|
||||
"is_protected": false,
|
||||
"source_type": "url",
|
||||
"origin": "url",
|
||||
"source_url": "https://cdn.example.com/acme-core-it.zip",
|
||||
"github_url": null,
|
||||
"github_changelog_url": null,
|
||||
"bundled_identifier": null,
|
||||
"install_blocked_reason": null,
|
||||
"target_name": null,
|
||||
"installed_at": "2026-07-05 10:41:24",
|
||||
"activated_at": "2026-07-05 10:41:24",
|
||||
"created_at": "2026-07-05 10:41:24",
|
||||
"updated_at": "2026-07-05 10:41:24",
|
||||
"has_update": false,
|
||||
"abilities": {
|
||||
"can_activate": true,
|
||||
"can_deactivate": true,
|
||||
"can_uninstall": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `checksum` 불일치 시 500 (`체크섬이 일치하지 않습니다.`), manifest 검증 실패 시 422 로 응답합니다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -544,11 +947,51 @@ Content-Type: application/octet-stream
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`LanguagePackService::previewManifest()` 반환값)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| manifest | object | `{"identifier":"acme-core-de","locale":"de","version":"1.0.0"}` | ZIP 안 `language-pack.json` 원본 전체 (파싱된 객체) |
|
||||
| validation | object | `{"errors":[],"is_valid":true,...}` | manifest 검증 결과 요약 |
|
||||
| validation.errors | array | `[]` | 검증 실패 메시지 목록 (통과 시 빈 배열) |
|
||||
| validation.is_valid | boolean | `true` | 검증 통과 여부 (`errors` 가 비어 있으면 true) |
|
||||
| validation.already_installed | boolean | `false` | 동일 `identifier` 언어팩이 이미 설치되어 있는지 여부 |
|
||||
| validation.existing_version | string\|null | `null` | 이미 설치되어 있다면 그 버전 (없으면 null) |
|
||||
| validation.target_version_mismatch | boolean | `false` | 대상 확장 버전이 manifest 요구 조건과 어긋나는지 여부 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "manifest 미리보기를 완료했습니다.",
|
||||
"data": {
|
||||
"manifest": {
|
||||
"identifier": "acme-core-de",
|
||||
"vendor": "acme",
|
||||
"scope": "core",
|
||||
"locale": "de",
|
||||
"version": "1.0.0",
|
||||
"name": {
|
||||
"ko": "독일어 언어팩",
|
||||
"en": "German Language Pack"
|
||||
},
|
||||
"license": "MIT"
|
||||
},
|
||||
"validation": {
|
||||
"errors": [],
|
||||
"is_valid": true,
|
||||
"already_installed": false,
|
||||
"existing_version": null,
|
||||
"target_version_mismatch": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -584,11 +1027,33 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`LanguagePackService::refreshCache()` 반환값 — 각 캐시 계층의 무효화 성공 여부)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| registry | boolean | `true` | 언어팩 레지스트리 캐시 무효화 성공 여부 |
|
||||
| translator | boolean | `true` | Laravel 번역기(loaded 번역 배열) 초기화 성공 여부 |
|
||||
| template | boolean | `true` | 템플릿 언어(`template-lang`) 캐시 플러시 성공 여부 |
|
||||
| version | boolean | `true` | 프론트엔드 cache busting 용 확장 캐시 버전 증가 성공 여부 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "언어팩 캐시를 갱신했습니다.",
|
||||
"data": {
|
||||
"registry": true,
|
||||
"translator": true,
|
||||
"template": true,
|
||||
"version": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -627,11 +1092,23 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — 컨트롤러가 `success('language_packs.uninstall_success')` 만 호출하므로 `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "언어팩을 제거했습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
> 보호된 언어팩(`is_protected`)은 제거할 수 없으며, 이 경우 500 (`언어팩 제거에 실패했습니다: 보호된 언어팩은 비활성화/제거할 수 없습니다.`) 으로 응답합니다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -713,11 +1190,108 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (활성화된 언어팩 = `LanguagePackResource::toArray()`). 필드 구성은 [GET /api/admin/language-packs/{id}](#get-apiadminlanguage-packsid) 의 `manifest`/`validation_summary`/`source_meta`/`changelog_entries` 4개를 제외한 나머지와 동일합니다._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| identifier | string | `apidoc-sample-lang` | 언어팩 고유 식별자 |
|
||||
| vendor | string | `apidoc` | 언어팩 제작자 식별자 |
|
||||
| scope | string | `core` | 적용 대상 분류 (core/module/plugin/template) |
|
||||
| target_identifier | string\|null | `null` | 대상 확장 식별자 (scope=core 일 때 null) |
|
||||
| locale | string | `fr` | IETF BCP-47 locale 태그 |
|
||||
| locale_name | string | `French` | 영문 언어명 |
|
||||
| locale_native_name | string | `Français` | 원어 언어명 |
|
||||
| text_direction | string | `ltr` | 텍스트 방향 (ltr/rtl) |
|
||||
| version | string | `1.0.0` | 언어팩 버전 |
|
||||
| latest_version | string\|null | `1.0.0` | 감지된 최신 배포 버전 |
|
||||
| target_version_constraint | string\|null | `null` | 대상 확장 버전 제약 (semver) |
|
||||
| target_version_mismatch | boolean | `false` | 대상 버전 불일치 경고 플래그 |
|
||||
| name | string\|null | `API 문서 샘플 언어팩` | manifest `name` 의 현재 로케일 해석값 |
|
||||
| license | string\|null | `MIT` | 라이선스 |
|
||||
| description | string\|null | `문서 실측용 언어팩` | 언어팩 설명 (다국어) |
|
||||
| status | string | `active` | 활성화 후 상태 (`active`) |
|
||||
| is_protected | boolean | `false` | 보호(protected) 팩 여부 |
|
||||
| source_type | string | `bundled` | 설치 소스 유형 |
|
||||
| origin | string\|null | `bundled` | source_type 에서 파생된 출처 값 |
|
||||
| source_url | string\|null | `null` | 설치 소스 URL 또는 경로 |
|
||||
| github_url | string\|null | `null` | GitHub 저장소 URL (manifest 파생) |
|
||||
| github_changelog_url | string\|null | `null` | GitHub 변경 이력(CHANGELOG) URL (manifest 파생) |
|
||||
| bundled_identifier | string\|null | `null` | 대응하는 번들 확장 식별자 |
|
||||
| install_blocked_reason | string\|null | `null` | 설치가 차단된 사유 (차단 없으면 null) |
|
||||
| target_name | string\|null | `null` | 대상 확장의 표시 이름 |
|
||||
| installed_at | string\|null | `2026-07-05 10:41:24` | 설치 일시 (사용자 타임존) |
|
||||
| activated_at | string\|null | `2026-07-05 10:41:24` | 활성화 일시 (사용자 타임존) |
|
||||
| created_at | string\|null | `2026-07-08 10:41:24` | 생성 일시 |
|
||||
| updated_at | string\|null | `2026-07-08 10:41:24` | 최종 수정 일시 |
|
||||
| has_update | boolean | `false` | `latest_version > version` 여부 |
|
||||
| abilities | object | `{"can_activate":true,"can_deactivate":true,"can_uninstall":true}` | 현재 사용자가 이 언어팩에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "언어팩을 활성화했습니다.",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"identifier": "apidoc-sample-lang",
|
||||
"vendor": "apidoc",
|
||||
"scope": "core",
|
||||
"target_identifier": null,
|
||||
"locale": "fr",
|
||||
"locale_name": "French",
|
||||
"locale_native_name": "Français",
|
||||
"text_direction": "ltr",
|
||||
"version": "1.0.0",
|
||||
"latest_version": "1.0.0",
|
||||
"target_version_constraint": null,
|
||||
"target_version_mismatch": false,
|
||||
"name": "API 문서 샘플 언어팩",
|
||||
"license": "MIT",
|
||||
"description": "문서 실측용 언어팩",
|
||||
"status": "active",
|
||||
"is_protected": false,
|
||||
"source_type": "bundled",
|
||||
"origin": "bundled",
|
||||
"source_url": null,
|
||||
"github_url": null,
|
||||
"github_changelog_url": null,
|
||||
"bundled_identifier": null,
|
||||
"install_blocked_reason": null,
|
||||
"target_name": null,
|
||||
"installed_at": "2026-07-05 10:41:24",
|
||||
"activated_at": "2026-07-05 10:41:24",
|
||||
"created_at": "2026-07-08 10:41:24",
|
||||
"updated_at": "2026-07-08 10:41:24",
|
||||
"has_update": false,
|
||||
"abilities": {
|
||||
"can_activate": true,
|
||||
"can_deactivate": true,
|
||||
"can_uninstall": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**슬롯 충돌(409) 응답**
|
||||
|
||||
동일 슬롯(scope·target·locale)에 다른 활성 팩이 있고 `force=true` 가 아니면 409 로 응답하며, `errors` 에 현재 팩(`current`)과 대상 팩(`target`)이 위 필드 구성 그대로 담깁니다.
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "같은 슬롯에 이미 활성 언어팩(:current)이 있습니다. (:target)으로 교체하려면 확인이 필요합니다.",
|
||||
"errors": {
|
||||
"current": { "id": 1, "identifier": "apidoc-sample-lang", "status": "active" },
|
||||
"target": { "id": 2, "identifier": "acme-core-fr", "status": "installed" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -799,11 +1373,95 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (비활성화된 언어팩 = `LanguagePackResource::toArray()`). 필드 구성은 activate 응답과 동일하며 `status` 만 `inactive` 로 바뀝니다 (`activated_at` 은 마지막 활성화 시각 그대로 유지)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| identifier | string | `apidoc-sample-lang` | 언어팩 고유 식별자 |
|
||||
| vendor | string | `apidoc` | 언어팩 제작자 식별자 |
|
||||
| scope | string | `core` | 적용 대상 분류 (core/module/plugin/template) |
|
||||
| target_identifier | string\|null | `null` | 대상 확장 식별자 (scope=core 일 때 null) |
|
||||
| locale | string | `fr` | IETF BCP-47 locale 태그 |
|
||||
| locale_name | string | `French` | 영문 언어명 |
|
||||
| locale_native_name | string | `Français` | 원어 언어명 |
|
||||
| text_direction | string | `ltr` | 텍스트 방향 (ltr/rtl) |
|
||||
| version | string | `1.0.0` | 언어팩 버전 |
|
||||
| latest_version | string\|null | `1.0.0` | 감지된 최신 배포 버전 |
|
||||
| target_version_constraint | string\|null | `null` | 대상 확장 버전 제약 (semver) |
|
||||
| target_version_mismatch | boolean | `false` | 대상 버전 불일치 경고 플래그 |
|
||||
| name | string\|null | `API 문서 샘플 언어팩` | manifest `name` 의 현재 로케일 해석값 |
|
||||
| license | string\|null | `MIT` | 라이선스 |
|
||||
| description | string\|null | `문서 실측용 언어팩` | 언어팩 설명 (다국어) |
|
||||
| status | string | `inactive` | 비활성화 후 상태 |
|
||||
| is_protected | boolean | `false` | 보호(protected) 팩 여부 (보호 팩은 비활성화 불가) |
|
||||
| source_type | string | `bundled` | 설치 소스 유형 |
|
||||
| origin | string\|null | `bundled` | source_type 에서 파생된 출처 값 |
|
||||
| source_url | string\|null | `null` | 설치 소스 URL 또는 경로 |
|
||||
| github_url | string\|null | `null` | GitHub 저장소 URL (manifest 파생) |
|
||||
| github_changelog_url | string\|null | `null` | GitHub 변경 이력(CHANGELOG) URL (manifest 파생) |
|
||||
| bundled_identifier | string\|null | `null` | 대응하는 번들 확장 식별자 |
|
||||
| install_blocked_reason | string\|null | `null` | 설치가 차단된 사유 (차단 없으면 null) |
|
||||
| target_name | string\|null | `null` | 대상 확장의 표시 이름 |
|
||||
| installed_at | string\|null | `2026-07-05 10:41:24` | 설치 일시 (사용자 타임존) |
|
||||
| activated_at | string\|null | `2026-07-05 10:41:24` | 마지막 활성화 일시 (비활성화 시에도 초기화되지 않음) |
|
||||
| created_at | string\|null | `2026-07-08 10:41:24` | 생성 일시 |
|
||||
| updated_at | string\|null | `2026-07-08 10:41:24` | 최종 수정 일시 |
|
||||
| has_update | boolean | `false` | `latest_version > version` 여부 |
|
||||
| abilities | object | `{"can_activate":true,"can_deactivate":true,"can_uninstall":true}` | 현재 사용자가 이 언어팩에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "언어팩을 비활성화했습니다.",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"identifier": "apidoc-sample-lang",
|
||||
"vendor": "apidoc",
|
||||
"scope": "core",
|
||||
"target_identifier": null,
|
||||
"locale": "fr",
|
||||
"locale_name": "French",
|
||||
"locale_native_name": "Français",
|
||||
"text_direction": "ltr",
|
||||
"version": "1.0.0",
|
||||
"latest_version": "1.0.0",
|
||||
"target_version_constraint": null,
|
||||
"target_version_mismatch": false,
|
||||
"name": "API 문서 샘플 언어팩",
|
||||
"license": "MIT",
|
||||
"description": "문서 실측용 언어팩",
|
||||
"status": "inactive",
|
||||
"is_protected": false,
|
||||
"source_type": "bundled",
|
||||
"origin": "bundled",
|
||||
"source_url": null,
|
||||
"github_url": null,
|
||||
"github_changelog_url": null,
|
||||
"bundled_identifier": null,
|
||||
"install_blocked_reason": null,
|
||||
"target_name": null,
|
||||
"installed_at": "2026-07-05 10:41:24",
|
||||
"activated_at": "2026-07-05 10:41:24",
|
||||
"created_at": "2026-07-08 10:41:24",
|
||||
"updated_at": "2026-07-08 10:41:24",
|
||||
"has_update": false,
|
||||
"abilities": {
|
||||
"can_activate": true,
|
||||
"can_deactivate": true,
|
||||
"can_uninstall": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 보호된 언어팩은 비활성화할 수 없으며, 이 경우 500 (`언어팩 비활성화에 실패했습니다: 보호된 언어팩은 비활성화/제거할 수 없습니다.`) 으로 응답합니다. 같은 슬롯에 다른 후보 팩이 있으면 가장 최근 inactive/installed 팩이 자동으로 활성 승격됩니다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -842,11 +1500,95 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (업데이트된 언어팩 = `LanguagePackResource::toArray()`). 필드 구성은 activate/deactivate 응답과 동일하며 `version` 이 새 버전으로 갱신되고 `has_update` 가 `false` 가 됩니다._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `3` | 기본 키 (내부 식별자) |
|
||||
| identifier | string | `acme-core-es` | 언어팩 고유 식별자 |
|
||||
| vendor | string | `acme` | 언어팩 제작자 식별자 |
|
||||
| scope | string | `core` | 적용 대상 분류 (core/module/plugin/template) |
|
||||
| target_identifier | string\|null | `null` | 대상 확장 식별자 (scope=core 일 때 null) |
|
||||
| locale | string | `es` | IETF BCP-47 locale 태그 |
|
||||
| locale_name | string | `Spanish` | 영문 언어명 |
|
||||
| locale_native_name | string | `Español` | 원어 언어명 |
|
||||
| text_direction | string | `ltr` | 텍스트 방향 (ltr/rtl) |
|
||||
| version | string | `1.1.0` | 업데이트 후 적용된 버전 |
|
||||
| latest_version | string\|null | `1.1.0` | 감지된 최신 배포 버전 |
|
||||
| target_version_constraint | string\|null | `null` | 대상 확장 버전 제약 (semver) |
|
||||
| target_version_mismatch | boolean | `false` | 대상 버전 불일치 경고 플래그 |
|
||||
| name | string\|null | `스페인어 언어팩` | manifest `name` 의 현재 로케일 해석값 |
|
||||
| license | string\|null | `MIT` | 라이선스 |
|
||||
| description | string\|null | `—` | 언어팩 설명 (다국어) |
|
||||
| status | string | `active` | 언어팩 상태 (업데이트 전 상태 유지) |
|
||||
| is_protected | boolean | `false` | 보호(protected) 팩 여부 |
|
||||
| source_type | string | `github` | 설치 소스 유형 (업데이트는 GitHub/번들 소스만 가능) |
|
||||
| origin | string\|null | `github` | source_type 에서 파생된 출처 값 |
|
||||
| source_url | string\|null | `https://github.com/acme/g7-core-es` | 설치 소스 URL 또는 경로 |
|
||||
| github_url | string\|null | `https://github.com/acme/g7-core-es` | GitHub 저장소 URL (manifest 파생) |
|
||||
| github_changelog_url | string\|null | `null` | GitHub 변경 이력(CHANGELOG) URL (manifest 파생) |
|
||||
| bundled_identifier | string\|null | `null` | 대응하는 번들 확장 식별자 |
|
||||
| install_blocked_reason | string\|null | `null` | 설치가 차단된 사유 (차단 없으면 null) |
|
||||
| target_name | string\|null | `null` | 대상 확장의 표시 이름 |
|
||||
| installed_at | string\|null | `2026-07-05 10:41:24` | 설치 일시 (사용자 타임존) |
|
||||
| activated_at | string\|null | `2026-07-05 10:41:24` | 활성화 일시 (사용자 타임존) |
|
||||
| created_at | string\|null | `2026-07-05 10:41:24` | 생성 일시 |
|
||||
| updated_at | string\|null | `2026-07-09 09:12:00` | 최종 수정 일시 (업데이트 시각으로 갱신) |
|
||||
| has_update | boolean | `false` | `latest_version > version` 여부 (업데이트 직후 false) |
|
||||
| abilities | object | `{"can_activate":true,"can_deactivate":true,"can_uninstall":true}` | 현재 사용자가 이 언어팩에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "언어팩을 업데이트했습니다.",
|
||||
"data": {
|
||||
"id": 3,
|
||||
"identifier": "acme-core-es",
|
||||
"vendor": "acme",
|
||||
"scope": "core",
|
||||
"target_identifier": null,
|
||||
"locale": "es",
|
||||
"locale_name": "Spanish",
|
||||
"locale_native_name": "Español",
|
||||
"text_direction": "ltr",
|
||||
"version": "1.1.0",
|
||||
"latest_version": "1.1.0",
|
||||
"target_version_constraint": null,
|
||||
"target_version_mismatch": false,
|
||||
"name": "스페인어 언어팩",
|
||||
"license": "MIT",
|
||||
"description": null,
|
||||
"status": "active",
|
||||
"is_protected": false,
|
||||
"source_type": "github",
|
||||
"origin": "github",
|
||||
"source_url": "https://github.com/acme/g7-core-es",
|
||||
"github_url": "https://github.com/acme/g7-core-es",
|
||||
"github_changelog_url": null,
|
||||
"bundled_identifier": null,
|
||||
"install_blocked_reason": null,
|
||||
"target_name": null,
|
||||
"installed_at": "2026-07-05 10:41:24",
|
||||
"activated_at": "2026-07-05 10:41:24",
|
||||
"created_at": "2026-07-05 10:41:24",
|
||||
"updated_at": "2026-07-09 09:12:00",
|
||||
"has_update": false,
|
||||
"abilities": {
|
||||
"can_activate": true,
|
||||
"can_deactivate": true,
|
||||
"can_uninstall": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 업데이트 소스 정보가 없거나(`업데이트 소스 정보가 없습니다 (GitHub 소스 언어팩만 업데이트 가능).`) 이미 최신 버전이면(`이미 최신 버전입니다.`) 500 (`언어팩 업데이트에 실패했습니다: :error`) 으로 응답합니다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
|
||||
+129
-9
@@ -67,7 +67,7 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| token | path | string | 예 | — | 인증/검증 토큰 |
|
||||
| token | path | string | 예 | — | 미리보기 토큰(UUID). `LayoutPreviewService::createPreview` 가 발급하며 기본 30분 후 만료 |
|
||||
|
||||
**요청 예시**
|
||||
|
||||
@@ -80,17 +80,76 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `success`/`message`/`data` 봉투를 사용하지 않습니다. `LayoutPreviewController@serve` 가 `response()->json($layout)` 로 **병합된 레이아웃 JSON 객체를 최상위(root)에 그대로** 반환합니다 (상속 병합 + 모듈/플러그인 확장 적용 완료 상태). 아래는 레이아웃 JSON의 최상위 키이며, 실제 포함 여부는 저장된 레이아웃 content 에 따라 달라집니다._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| version | string | `"1.0"` | 레이아웃 스키마 버전 (저장 시 필수) |
|
||||
| layout_name | string | `"product_list"` | 레이아웃 이름 (식별자) |
|
||||
| extends | string\|null | `"_user_base"` | 상속할 베이스 레이아웃 이름 (미리보기 서빙 시 이미 병합됨) |
|
||||
| slots | object | `{"content": [ ... ]}` | 베이스 레이아웃 슬롯에 삽입할 컴포넌트 배열 (extends 레이아웃) |
|
||||
| components | array | `[{"type":"basic","name":"Div", ...}]` | 렌더링할 컴포넌트 트리 (병합·확장 적용 결과) |
|
||||
| endpoint | string\|null | `"/api/products"` | 화면이 주로 fetch 하는 데이터 API 경로 (레거시·선택) |
|
||||
| data_sources | array | `[{"id":"products","endpoint":"/api/products","method":"GET"}]` | 화면이 로드하는 API 데이터 소스 정의 |
|
||||
| meta | object | `{"title":"상품 목록","auth_required":false}` | 메타 정보 (title, description, keywords, auth_required, is_base, guest_only, is_error_layout, error_code, seo) |
|
||||
| permissions | array\|object | `["core.templates.layouts.edit"]` | 레이아웃 접근에 필요한 권한 (flat 배열=AND, 구조화 객체=OR/AND 중첩) |
|
||||
| modals | object | `{}` | 모달 컴포넌트 정의 |
|
||||
| state / init_state / initLocal / initGlobal / initIsolated / global_state | object | `{}` | 레이아웃 레벨 초기 상태 정의 |
|
||||
| init_actions | array | `[{"handler":"apiCall", ...}]` | 레이아웃 로드 시 실행할 초기화 액션 |
|
||||
| actions / named_actions | array\|object | `{}` | 재사용 가능한 액션 정의 |
|
||||
| computed | object | `{}` | 계산된 값 정의 |
|
||||
| defines | object | `{}` | 재사용 가능한 컴포넌트 조각 정의 |
|
||||
| errorHandling | object | `{"404":{"handler":"navigate"}}` | 상태 코드별 에러 처리 정책 |
|
||||
| globalHeaders | array | `[{"pattern":"*","headers":{"X-Foo":"bar"}}]` | API 호출 시 자동 적용되는 HTTP 헤더 규칙 |
|
||||
| transition_overlay | object | `{"enabled":true,"style":"blur"}` | 페이지 전환 오버레이 설정 |
|
||||
| routes | array | `[]` | 라우트 정의 |
|
||||
| pageConfig / schema | object | `{}` | 플러그인 설정 레이아웃 전용 (설정 UI 안내/스키마) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"layout_name": "product_list",
|
||||
"meta": {
|
||||
"title": "상품 목록",
|
||||
"auth_required": false
|
||||
},
|
||||
"data_sources": [
|
||||
{
|
||||
"id": "products",
|
||||
"endpoint": "/api/products",
|
||||
"method": "GET"
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"type": "basic",
|
||||
"name": "Div",
|
||||
"props": {
|
||||
"className": "p-4"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
404 응답은 봉투 형식입니다 (`BaseApiController::notFound` → `templates.layout_not_found`).
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "레이아웃을 찾을 수 없습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 404 | Not Found | 토큰에 해당하는 미리보기가 없거나 만료된 경우 (`templates.layout_not_found`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -148,8 +207,8 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| templateIdentifier | path | string | 예 | — | 대상 template의 식별자 |
|
||||
| layoutName | path | string | 예 | — | 대상 layout의 이름 (식별자) |
|
||||
| templateIdentifier | path | string | 예 | — | 레이아웃을 서빙할 활성 템플릿의 식별자 (예: `sirsoft-basic`) — 미존재/비활성 시 404 |
|
||||
| layoutName | path | string | 예 | — | 서빙할 레이아웃 이름 (예: `product_list`) |
|
||||
|
||||
**요청 예시**
|
||||
|
||||
@@ -162,17 +221,78 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 는 병합된 레이아웃 JSON 객체입니다 (상속 병합 + 모듈/플러그인 확장 적용 + 사용자별 컴포넌트 권한 필터링 완료). 실제 포함 키는 저장된 레이아웃 content 에 따라 달라집니다._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| version | string | `"1.0"` | 레이아웃 스키마 버전 |
|
||||
| layout_name | string | `"product_list"` | 레이아웃 이름 (식별자) |
|
||||
| extends | string\|null | `"_user_base"` | 상속한 베이스 레이아웃 이름 (서빙 시 이미 병합 반영됨) |
|
||||
| slots | object | `{"content": [ ... ]}` | 베이스 슬롯에 삽입되는 컴포넌트 배열 (extends 레이아웃) |
|
||||
| components | array | `[{"type":"basic","name":"Div", ...}]` | 렌더링할 컴포넌트 트리 (병합·확장·권한 필터 적용 결과) |
|
||||
| endpoint | string\|null | `"/api/products"` | 화면이 주로 fetch 하는 데이터 API 경로 (레거시·선택) |
|
||||
| data_sources | array | `[{"id":"products","endpoint":"/api/products","method":"GET"}]` | 화면이 로드하는 API 데이터 소스 정의 |
|
||||
| meta | object | `{"title":"상품 목록","auth_required":false}` | 메타 정보 (title, description, keywords, auth_required, is_base, guest_only, is_error_layout, error_code, seo) |
|
||||
| permissions | array\|object | `["core.templates.layouts.edit"]` | 레이아웃 접근에 필요한 권한 (flat 배열=AND, 구조화 객체=OR/AND 중첩) |
|
||||
| modals | object | `{}` | 모달 컴포넌트 정의 |
|
||||
| state / init_state / initLocal / initGlobal / initIsolated / global_state | object | `{}` | 레이아웃 레벨 초기 상태 정의 |
|
||||
| init_actions | array | `[{"handler":"apiCall", ...}]` | 레이아웃 로드 시 실행할 초기화 액션 |
|
||||
| actions / named_actions | array\|object | `{}` | 재사용 가능한 액션 정의 |
|
||||
| computed | object | `{}` | 계산된 값 정의 |
|
||||
| defines | object | `{}` | 재사용 가능한 컴포넌트 조각 정의 |
|
||||
| errorHandling | object | `{"404":{"handler":"navigate"}}` | 상태 코드별 에러 처리 정책 |
|
||||
| globalHeaders | array | `[{"pattern":"*","headers":{"X-Foo":"bar"}}]` | API 호출 시 자동 적용되는 HTTP 헤더 규칙 |
|
||||
| transition_overlay | object | `{"enabled":true,"style":"blur"}` | 페이지 전환 오버레이 설정 |
|
||||
| routes | array | `[]` | 라우트 정의 |
|
||||
| pageConfig / schema | object | `{}` | 플러그인 설정 레이아웃 전용 (설정 UI 안내/스키마) |
|
||||
| lock_version | integer | `3` | 낙관적 잠금 버전. `with_source_meta=1` 일 때만 부착 (편집기 저장 시 `expected_lock_version` 으로 되돌려 보냄) |
|
||||
| __editor | object | `{"original": { ... }}` | 자식 레이아웃의 저장 원본 content. `with_source_meta=1` 일 때만 부착 (편집기 전용) |
|
||||
| __source (각 노드 내부) | object | `{"kind":"base","layout":"_user_base"}` | 각 컴포넌트/데이터소스 노드의 출처 메타 (`base` / `extension` / `partial` / `route`). `with_source_meta=1` 일 때만 부착 |
|
||||
|
||||
응답 헤더: `ETag`(본문 md5), `Cache-Control: public, max-age=3600`, `Vary: Accept-Encoding, Accept-Language`. 클라이언트 `If-None-Match` 가 일치하면 본문 없이 `304 Not Modified` 를 반환합니다.
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "레이아웃이 제공되었습니다.",
|
||||
"data": {
|
||||
"version": "1.0",
|
||||
"layout_name": "product_list",
|
||||
"meta": {
|
||||
"title": "상품 목록",
|
||||
"auth_required": false
|
||||
},
|
||||
"data_sources": [
|
||||
{
|
||||
"id": "products",
|
||||
"endpoint": "/api/products",
|
||||
"method": "GET"
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"type": "basic",
|
||||
"name": "Div",
|
||||
"props": {
|
||||
"className": "p-4"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 304 | Not Modified | 요청의 `If-None-Match` 가 현재 ETag 와 일치 (본문 없음) |
|
||||
| 401 | Unauthorized | 비회원이 `permissions` 요구 레이아웃에 접근 (`auth.layout_guest_permission_denied`), 또는 비회원이 `with_source_meta=1` 요청 |
|
||||
| 403 | Forbidden | 회원이지만 레이아웃 `permissions` 미충족 (`auth.layout_permission_denied`), 또는 `with_source_meta=1` 요청 시 `core.templates.layouts.edit` 권한 없음 |
|
||||
| 404 | Not Found | 템플릿이 없거나 비활성 상태, 또는 레이아웃/부모 레이아웃 미존재 (`templates.layout_not_found`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ HTTP/1.1 200
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). <!-- TODO: 도메인 특이 에러가 있으면 보강 -->_
|
||||
_이 엔드포인트는 도메인 에러를 반환하지 않습니다. 공개 조회이므로 인증 실패(401)가 없고, 요청 파라미터가 없어 검증 실패(422)도 발생하지 않으며, 컨트롤러(`LocaleController@active`)와 `LanguagePackService::getActiveLocales()` 경로에서 던지는 예외도 없습니다._
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
|
||||
+82
-4
@@ -38,11 +38,17 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-500 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-500 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "회원 탈퇴가 완료되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -309,11 +315,83 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`UserResource::toArray()` 산물 — GET /api/me 의 `toProfileArray()` 와 필드 구성이 다르다)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a234c2b1-cde8-437f-b28b-23323be2b98d` | 외부 노출용 UUID (URL/API 식별자, 내부 id 비노출) |
|
||||
| name | string | `홍길동` | 사용자 이름 |
|
||||
| nickname | string\|null | `gildong` | 닉네임 |
|
||||
| email | string | `user@example.com` | 이메일 주소 |
|
||||
| avatar | string\|null | `null` | 아바타 이미지 URL (`User::getAvatarUrl()` 산물, 미등록 시 null) |
|
||||
| language | string | `ko` | 사용자 언어 설정 (ko: 한국어, en: 영어) |
|
||||
| language_label | string\|null | `한국어` | 언어 코드의 다국어 라벨 (`user.language.{code}` 번역문) |
|
||||
| country | string\|null | `KR` | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| status | string | `active` | 계정 상태 (active, inactive, blocked, withdrawn, pending_verification) |
|
||||
| status_label | string\|null | `활성` | 상태의 사람이 읽는 라벨 (UserStatus::label() 산물) |
|
||||
| status_variant | string\|null | `success` | 상태 표시 색상/스타일 변형 키 (UserStatus::variant() 산물 — UI 배지용) |
|
||||
| is_admin | boolean | `false` | 관리자 역할 보유 여부 (`User::isAdmin()` — 역할 관계 기반 파생) |
|
||||
| homepage | string\|null | `https://example.com` | 홈페이지 URL |
|
||||
| mobile | string\|null | `010-1234-5678` | 휴대폰 번호 |
|
||||
| phone | string\|null | `02-123-4567` | 전화번호 |
|
||||
| zipcode | string\|null | `06234` | 우편번호 |
|
||||
| address | string\|null | `서울특별시 강남구 테헤란로 1` | 기본 주소 |
|
||||
| address_detail | string\|null | `101동 202호` | 상세 주소 |
|
||||
| signature | string\|null | `null` | 서명 |
|
||||
| bio | string\|null | `null` | 자기소개 |
|
||||
| last_login_at | string\|null | `2026-07-07 10:41:24` | 마지막 로그인 일시 (사용자 시간대 기준 문자열) |
|
||||
| email_verified_at | string\|null | `null` | 이메일 인증 일시 (미인증 시 null) |
|
||||
| timezone | string\|null | `Asia/Seoul` | 사용자 시간대 (예: Asia/Seoul, UTC) |
|
||||
| created_at | string | `2026-07-08 10:41:24` | 생성 일시 (사용자 시간대 기준 문자열) |
|
||||
| updated_at | string | `2026-07-08 11:02:10` | 수정 일시 (사용자 시간대 기준 문자열) |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":false,"can_create":false,"can_update":false,"can_delete":false,"can_assign_roles":false}` | 현재 사용자의 이 리소스에 대한 권한 맵 (core.users.read/create/update/delete, core.permissions.update 기준. 슈퍼관리자 계정은 `can_delete` 가 항상 false) |
|
||||
|
||||
관계형 필드(`modules`, `plugins`, `menus`, `roles`, `permissions`, `consents`, `terms_consent`, `privacy_consent`)와 카운트 필드(`modules_count`, `plugins_count`, `menus_count`)는 해당 관계가 로드된 경우에만 응답에 포함된다 (프로필 수정 응답에서는 로드하지 않으므로 나타나지 않는다).
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "사용자 정보가 성공적으로 업데이트되었습니다.",
|
||||
"data": {
|
||||
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"name": "예시 이름",
|
||||
"nickname": "예시 이름",
|
||||
"email": "user@example.com",
|
||||
"avatar": null,
|
||||
"language": "ko",
|
||||
"language_label": "한국어",
|
||||
"country": "KR",
|
||||
"status": "active",
|
||||
"status_label": "활성",
|
||||
"status_variant": "success",
|
||||
"is_admin": false,
|
||||
"homepage": "https://example.com",
|
||||
"mobile": "010-1234-5678",
|
||||
"phone": "010-1234-5678",
|
||||
"zipcode": "06234",
|
||||
"address": "서울특별시 강남구 테헤란로 1",
|
||||
"address_detail": "서울특별시 강남구 테헤란로 1",
|
||||
"signature": "예시값",
|
||||
"bio": "예시 내용입니다.",
|
||||
"last_login_at": "2026-07-07 10:41:24",
|
||||
"email_verified_at": null,
|
||||
"timezone": "Asia/Seoul",
|
||||
"created_at": "2026-07-08 10:41:24",
|
||||
"updated_at": "2026-07-08 11:02:10",
|
||||
"is_owner": true,
|
||||
"abilities": {
|
||||
"can_read": false,
|
||||
"can_create": false,
|
||||
"can_update": false,
|
||||
"can_delete": false,
|
||||
"can_assign_roles": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
|
||||
+171
-8
@@ -481,11 +481,94 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + 컬렉션 레벨 `data.abilities`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `15` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"게시판 관리","en":"Board Management"}` | 메뉴 이름 (다국어 JSON) |
|
||||
| slug | string | `sirsoft-board` | 메뉴 슬러그 |
|
||||
| url | string \| null | `null` | 메뉴 URL (그룹 메뉴는 null) |
|
||||
| icon | string \| null | `fas fa-clipboard-list` | 메뉴 아이콘 (Font Awesome 클래스) |
|
||||
| order | integer | `30` | 메뉴 순서 (작을수록 우선 — `order` 오름차순 정렬) |
|
||||
| is_active | boolean | `true` | 활성 여부 |
|
||||
| parent_id | integer \| null | `null` | 상위 메뉴 ID (최상위는 null) |
|
||||
| extension_type | string | `module` | 확장 소유 타입 (`module` / `plugin`) |
|
||||
| extension_identifier | string | `sirsoft-board` | 확장 식별자 (요청 path 의 `identifier` 와 동일) |
|
||||
| parent | object \| null | `null` | 상위 항목 객체 (id/name/url/icon — parent 관계 파생) |
|
||||
| children | array | `[{"id":16,"name":{"ko":"환경설정"},"slug":"sirsoft-board-settings", ...}]` | 하위 메뉴 배열 (order 오름차순 — children 관계 파생) |
|
||||
| creator | object \| null | `null` | 생성자 정보 객체 (uuid/name/email — creator 관계 파생) |
|
||||
| created_at | string | `2026-07-08 10:44:35` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-08 10:44:35` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `false` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
> `roles` 관계는 이 엔드포인트에서 eager-load 되지 않으므로(`MenuRepository::getMenusByExtension` 은 `creator`/`parent`/`children` 만 로드) 항목에 `roles` 키가 포함되지 않습니다.
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "메뉴를 성공적으로 가져왔습니다.",
|
||||
"data": {
|
||||
"data": [
|
||||
{
|
||||
"id": 15,
|
||||
"name": {
|
||||
"ko": "게시판 관리",
|
||||
"en": "Board Management"
|
||||
},
|
||||
"slug": "sirsoft-board",
|
||||
"url": null,
|
||||
"icon": "fas fa-clipboard-list",
|
||||
"order": 30,
|
||||
"is_active": true,
|
||||
"parent_id": null,
|
||||
"extension_type": "module",
|
||||
"extension_identifier": "sirsoft-board",
|
||||
"parent": null,
|
||||
"children": [
|
||||
{
|
||||
"id": 16,
|
||||
"name": {
|
||||
"ko": "환경설정",
|
||||
"en": "Settings"
|
||||
},
|
||||
"slug": "sirsoft-board-settings",
|
||||
"url": "/admin/boards/settings",
|
||||
"icon": "fas fa-cog",
|
||||
"order": 1,
|
||||
"is_active": true,
|
||||
"parent_id": 15,
|
||||
"extension_type": "module",
|
||||
"extension_identifier": "sirsoft-board",
|
||||
"roles": []
|
||||
}
|
||||
],
|
||||
"creator": null,
|
||||
"created_at": "2026-07-08 10:44:35",
|
||||
"updated_at": "2026-07-08 10:44:35",
|
||||
"is_owner": false,
|
||||
"abilities": {
|
||||
"can_create": true,
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"abilities": {
|
||||
"can_create": true,
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -638,11 +721,21 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — 컨트롤러가 `success('menu.order_update_success')` 를 데이터 없이 호출)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "메뉴 순서가 성공적으로 업데이트되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -650,7 +743,7 @@ Content-Type: application/json
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.menus.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지). `moved_items[].new_parent_id` 가 자기 자신·자손을 가리키는 순환 참조인 경우 포함 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -682,7 +775,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — 컨트롤러가 `success('menu.delete_success')` 를 데이터 없이 호출)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
@@ -928,11 +1021,81 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (갱신된 메뉴를 `MenuResource` 로 반환 — `creator`/`parent`/`children`/`roles` eager-load)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"API 문서 샘플 메뉴","en":"API Doc Sample Menu"}` | 메뉴 이름 (다국어 JSON) |
|
||||
| slug | string | `apidoc-sample-menu` | 메뉴 슬러그 |
|
||||
| url | string \| null | `/admin/apidoc-sample` | 메뉴 URL |
|
||||
| icon | string \| null | `fas fa-book` | 메뉴 아이콘 |
|
||||
| order | integer | `35` | 메뉴 순서 |
|
||||
| is_active | boolean | `true` | 활성 여부 |
|
||||
| parent_id | integer \| null | `null` | 상위 메뉴 ID |
|
||||
| extension_type | string \| null | `core` | 확장 소유 타입: core / module / plugin / null(사용자 정의) |
|
||||
| extension_identifier | string \| null | `core` | 확장 식별자 |
|
||||
| parent | object \| null | `null` | 상위 항목 객체 (id/name/url/icon — parent 관계 파생) |
|
||||
| children | array | `[]` | 하위 항목 배열 (order 오름차순 — children 관계 파생) |
|
||||
| creator | object \| null | `{"uuid":"a234c2b1-…","name":"API 문서 샘플 사용자","email":"apidoc-sample-user@example.com"}` | 생성자 정보 객체 (creator 관계 파생) |
|
||||
| roles | array | `[{"id":1,"name":{"ko":"관리자","en":"Administrator"},"permission_type":"read"}]` | 이 메뉴 노출이 허용된 역할 목록 (요청 `roles` 로 교체된 결과) |
|
||||
| created_at | string | `2026-07-08 10:41:24` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-08 12:20:11` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "메뉴가 성공적으로 업데이트되었습니다.",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": {
|
||||
"ko": "API 문서 샘플 메뉴",
|
||||
"en": "API Doc Sample Menu"
|
||||
},
|
||||
"slug": "apidoc-sample-menu",
|
||||
"url": "/admin/apidoc-sample",
|
||||
"icon": "fas fa-book",
|
||||
"order": 35,
|
||||
"is_active": true,
|
||||
"parent_id": null,
|
||||
"extension_type": null,
|
||||
"extension_identifier": null,
|
||||
"parent": null,
|
||||
"children": [],
|
||||
"creator": {
|
||||
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"name": "API 문서 샘플 사용자",
|
||||
"email": "apidoc-sample-user@example.com"
|
||||
},
|
||||
"roles": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": {
|
||||
"ko": "관리자",
|
||||
"en": "Administrator"
|
||||
},
|
||||
"permission_type": "read"
|
||||
}
|
||||
],
|
||||
"created_at": "2026-07-08 10:41:24",
|
||||
"updated_at": "2026-07-08 12:20:11",
|
||||
"is_owner": true,
|
||||
"abilities": {
|
||||
"can_create": true,
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
|
||||
+781
-93
File diff suppressed because it is too large.
Load diff
@@ -369,11 +369,95 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드. 수정된 알림 정의를 `templates` 관계와 함께 반환합니다 (`NotificationDefinitionResource`)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| type | string | `apidoc-sample.event` | 알림 타입 (welcome, order_confirmed 등) |
|
||||
| hook_prefix | string | `core` | 훅 접두사 (core.auth, sirsoft-ecommerce 등) |
|
||||
| extension_type | string | `core` | 이 정의를 소유한 확장의 타입 (core/module/plugin) |
|
||||
| extension_identifier | string | `` | 이 정의를 소유한 확장의 식별자 (코어는 빈 문자열) |
|
||||
| name | object | `{"ko":"API 문서 샘플 알림","en":"API Doc Sample Notification"}` | 다국어 이름 (로케일별 값 객체) |
|
||||
| description | object | `{"ko":"문서 실측용 알림 정의","en":"Sample notification"}` | 다국어 설명 (로케일별 값 객체) |
|
||||
| variables | array | `[]` | 사용 가능 변수 메타데이터 ([{key, description}]) |
|
||||
| channels | array | `["database","mail"]` | 수정 후의 활성 채널 (["mail", "database"]) |
|
||||
| hooks | array | `[]` | 수정 후의 트리거 훅 목록 (["core.auth.after_register"]) |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| is_default | boolean | `false` | default 여부 (사용자 수정 시 false) |
|
||||
| templates | array | `[{"id":1,"definition_id":1,"channel":"mail", ...}]` | 채널별 알림 템플릿 목록 (`templates` 관계를 로드해 반환 — NotificationTemplateResource 배열) |
|
||||
| created_at | string | `2026-07-08 10:41:24` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-08 12:14:43` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update/can_delete — 모두 `core.settings.update` 기준) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "알림 정의가 수정되었습니다.",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"type": "apidoc-sample.event",
|
||||
"hook_prefix": "core",
|
||||
"extension_type": "core",
|
||||
"extension_identifier": "",
|
||||
"name": {
|
||||
"ko": "API 문서 샘플 알림",
|
||||
"en": "API Doc Sample Notification"
|
||||
},
|
||||
"description": {
|
||||
"ko": "문서 실측용 알림 정의",
|
||||
"en": "Sample notification"
|
||||
},
|
||||
"variables": [],
|
||||
"channels": [
|
||||
"database",
|
||||
"mail"
|
||||
],
|
||||
"hooks": [],
|
||||
"is_active": true,
|
||||
"is_default": false,
|
||||
"templates": [
|
||||
{
|
||||
"id": 1,
|
||||
"definition_id": 1,
|
||||
"channel": "mail",
|
||||
"subject": "API 문서 샘플 템플릿 제목",
|
||||
"body": "안녕하세요 {{name}} 님, 문서 실측용 본문입니다.",
|
||||
"click_url": "/admin/apidoc-sample",
|
||||
"recipients": [
|
||||
{
|
||||
"type": "role",
|
||||
"value": "admin",
|
||||
"display_name": "관리자"
|
||||
}
|
||||
],
|
||||
"is_active": true,
|
||||
"is_default": false,
|
||||
"user_overrides": null,
|
||||
"updated_by": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"created_at": "2026-07-08 10:41:24",
|
||||
"updated_at": "2026-07-08 10:41:24",
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"created_at": "2026-07-08 10:41:24",
|
||||
"updated_at": "2026-07-08 12:14:43",
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
|
||||
@@ -208,11 +208,27 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| deleted_count | integer | `3` | 실제로 삭제된 알림 발송 이력 건수 (요청한 `ids` 중 존재하는 행만 카운트) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "선택한 알림 발송 이력이 삭제되었습니다.",
|
||||
"data": {
|
||||
"deleted_count": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -250,9 +266,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — 컨트롤러가 `success(__('notification_log.delete_success'))` 만 호출하므로 `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
|
||||
@@ -55,11 +55,25 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| subject | string | `[사이트명] 회원가입을 환영합니다` | 요청 `locale`(미지정 시 현재 앱 로케일) 의 제목에서 `{변수}` 를 정의(`definition_id`)의 변수 설명(`[설명]`)으로 치환한 결과 |
|
||||
| body | string | `<h1>[회원 이름]님, 환영합니다!</h1>...` | 동일 로케일 본문에서 `{변수}` 를 정의의 변수 설명으로 치환한 결과. 해당 로케일 값이 없으면 빈 문자열 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "미리보기를 생성했습니다.",
|
||||
"data": {
|
||||
"subject": "[사이트명] 회원가입을 환영합니다",
|
||||
"body": "<h1>[회원 이름]님, 환영합니다!</h1><p>[사이트명]에 가입해 주셔서 감사합니다.</p>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -119,11 +133,67 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`NotificationTemplateResource`)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| definition_id | integer | `1` | 소속 알림 정의 식별자 |
|
||||
| channel | string | `mail` | 발송 채널 (`mail`, `database`, `fcm`) |
|
||||
| subject | object | `{"ko":"[{app_name}] 회원가입을 환영합니다","en":"..."}` | 다국어 제목 (로케일 키 → 문자열, 로케일당 최대 500자) |
|
||||
| body | object | `{"ko":"<h1>{name}님, 환영합니다!</h1>...","en":"..."}` | 다국어 본문 (로케일 키 → 문자열, 로케일당 최대 65535자) |
|
||||
| click_url | string \| null | `null` | 알림 클릭 시 이동할 대상 URL (미설정 시 `null`) |
|
||||
| recipients | array | `[{"type":"role","value":"admin","display_name":"관리자"}]` | 수신자 규칙 목록. `type` 은 `trigger_user`/`related_user`/`role`/`specific_users`. `role` 이면 `display_name`, `specific_users` 면 `display_names` 가 표시용으로 부가됨 |
|
||||
| is_active | boolean | `true` | 활성 여부 (false 면 해당 채널 발송 중단) |
|
||||
| is_default | boolean | `false` | 기본값 상태 여부 (수정 시 항상 `false` 로 전환됨) |
|
||||
| user_overrides | array \| null | `["subject","body"]` | 사용자가 직접 수정한 필드명 목록 (`HasUserOverrides`) |
|
||||
| updated_by | string \| null | `a234c2b1-cde8-437f-b28b-23323be2b98d` | 최종 수정한 사용자 UUID (없으면 `null`) |
|
||||
| created_at | string | `2026-07-08 10:41:24` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-08 12:14:43` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (모두 `core.settings.update` 권한 기반) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "알림 템플릿이 수정되었습니다.",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"definition_id": 1,
|
||||
"channel": "mail",
|
||||
"subject": {
|
||||
"ko": "[{app_name}] 회원가입을 환영합니다",
|
||||
"en": "[{app_name}] Welcome to Our Service"
|
||||
},
|
||||
"body": {
|
||||
"ko": "<h1>{name}님, 환영합니다!</h1>",
|
||||
"en": "<h1>Welcome, {name}!</h1>"
|
||||
},
|
||||
"click_url": "/admin/notifications",
|
||||
"recipients": [
|
||||
{
|
||||
"type": "role",
|
||||
"value": "admin",
|
||||
"display_name": "관리자"
|
||||
}
|
||||
],
|
||||
"is_active": true,
|
||||
"is_default": false,
|
||||
"user_overrides": [
|
||||
"subject",
|
||||
"body"
|
||||
],
|
||||
"updated_by": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"created_at": "2026-07-08 10:41:24",
|
||||
"updated_at": "2026-07-08 12:14:43",
|
||||
"abilities": {
|
||||
"can_update": true,
|
||||
"can_delete": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
|
||||
@@ -49,16 +49,16 @@ _목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `23` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | string | `518b9c94-5853-4b68-8193-83af1851bbc6` | 기본 키 (내부 식별자) |
|
||||
| type | string | `inquiry_received` | <!-- TODO: 설명 --> |
|
||||
| type_label | string | `상품 문의 접수` | `type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| subject | string | `새로운 상품 문의가 접수되었습니다` | <!-- TODO: 설명 --> |
|
||||
| body | string | `옥혜진님이 "면 손수건 3매입 #1" 상품에 문의를 남겼습니다.` | <!-- TODO: 설명 --> |
|
||||
| url | string | `https://g7_2.dev/admin/ecommerce/prod…` | <!-- TODO: 설명 --> |
|
||||
| data | object | `{"type":"inquiry_received","subject":"새로운 상품 문의가 접수되었습니다"…` | <!-- TODO: 설명 --> |
|
||||
| read_at | string | `2026-07-31 22:06:53` | read 일시 |
|
||||
| created_at | string | `2026-07-31 21:41:58` | 생성 일시 |
|
||||
| number | integer | `92` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | string | `02ee1121-ec63-4812-b77a-a0ffb4040acb` | 기본 키 (내부 식별자) |
|
||||
| type | string | `new_order_admin` | 알림 유형 식별자 (알림 정의의 type — 발송 트리거를 구분) |
|
||||
| type_label | string | `신규 주문 관리자 알림` | `type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| subject | string | `새로운 주문이 접수되었습니다` | 알림 제목 (알림 템플릿의 subject 를 변수 치환해 렌더한 문자열) |
|
||||
| body | string | `소경은님이 주문번호 20260713-0038038875 (결제금액:…` | 알림 본문 (알림 템플릿의 body 를 변수 치환해 렌더한 문자열) |
|
||||
| url | string | `https://g7.dev/admin/ecommerce/orders…` | 알림 클릭 시 이동할 URL (템플릿의 click_url 우선, 없으면 메일 CTA action_url) |
|
||||
| data | object | `{"type":"new_order_admin","subject":"새로운 주문이 접수되었습니다","bo…` | 알림 원본 페이로드 객체 (type/subject/body/click_url 과 발송 시 전달된 변수 data 를 포함) |
|
||||
| read_at | null | `null` | read 일시 |
|
||||
| created_at | string | `2026-07-13 09:38:04` | 생성 일시 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
@@ -302,11 +302,27 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| marked_count | integer | `2` | 실제로 읽음 처리된 알림 건수 (요청한 `ids` 중 본인 소유이면서 미읽음 상태였던 항목만 집계) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "알림을 읽음 처리했습니다.",
|
||||
"data": {
|
||||
"marked_count": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -404,11 +420,21 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "알림이 삭제되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -449,11 +475,51 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (읽음 처리 후 갱신된 알림 1건 — `UserNotificationResource`)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | string | `02ee1121-ec63-4812-b77a-a0ffb4040acb` | 알림 기본 키 (UUID) |
|
||||
| type | string | `new_order_admin` | 알림 유형 식별자 (알림 정의의 type — 발송 트리거를 구분) |
|
||||
| type_label | string | `신규 주문 관리자 알림` | `type` 값의 사람이 읽는 라벨 (알림 정의의 현지화 이름, 정의 미존재 시 빈 문자열) |
|
||||
| subject | string | `새로운 주문이 접수되었습니다` | 알림 제목 (알림 템플릿의 subject 를 변수 치환해 렌더한 문자열) |
|
||||
| body | string | `소경은님이 주문번호 20260713-0038038875 (결제금액:…` | 알림 본문 (알림 템플릿의 body 를 변수 치환해 렌더한 문자열) |
|
||||
| url | string \| null | `https://g7.dev/admin/ecommerce/orders/1` | 알림 클릭 시 이동할 URL (템플릿의 `click_url` 우선, 없으면 메일 CTA `action_url`, 둘 다 없으면 `null`) |
|
||||
| data | object | `{"type":"new_order_admin","subject":"...","body":"...","click_url":"..."}` | 알림 원본 페이로드 객체 (type/subject/body/click_url 과 발송 시 전달된 변수 data 를 포함) |
|
||||
| read_at | string \| null | `2026-07-13 09:40:11` | 읽음 처리 일시 (사용자 타임존 기준 `Y-m-d H:i:s`) — 이 엔드포인트 성공 시 항상 값이 채워짐 |
|
||||
| created_at | string \| null | `2026-07-13 09:38:04` | 알림 생성 일시 (사용자 타임존 기준 `Y-m-d H:i:s`) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "알림을 읽음 처리했습니다.",
|
||||
"data": {
|
||||
"id": "02ee1121-ec63-4812-b77a-a0ffb4040acb",
|
||||
"type": "new_order_admin",
|
||||
"type_label": "신규 주문 관리자 알림",
|
||||
"subject": "새로운 주문이 접수되었습니다",
|
||||
"body": "소경은님이 주문번호 20260713-0038038875 주문을 접수했습니다.",
|
||||
"url": "https://g7.dev/admin/ecommerce/orders/1",
|
||||
"data": {
|
||||
"type": "new_order_admin",
|
||||
"subject": "새로운 주문이 접수되었습니다",
|
||||
"body": "소경은님이 주문번호 20260713-0038038875 주문을 접수했습니다.",
|
||||
"click_url": "https://g7.dev/admin/ecommerce/orders/1",
|
||||
"data": {
|
||||
"action_url": "https://g7.dev/admin/ecommerce/orders/1"
|
||||
}
|
||||
},
|
||||
"read_at": "2026-07-13 09:40:11",
|
||||
"created_at": "2026-07-13 09:38:04"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -503,16 +569,16 @@ _목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `23` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | string | `518b9c94-5853-4b68-8193-83af1851bbc6` | 기본 키 (내부 식별자) |
|
||||
| type | string | `inquiry_received` | <!-- TODO: 설명 --> |
|
||||
| type_label | string | `상품 문의 접수` | `type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| subject | string | `새로운 상품 문의가 접수되었습니다` | <!-- TODO: 설명 --> |
|
||||
| body | string | `옥혜진님이 "면 손수건 3매입 #1" 상품에 문의를 남겼습니다.` | <!-- TODO: 설명 --> |
|
||||
| url | string | `https://g7_2.dev/admin/ecommerce/prod…` | <!-- TODO: 설명 --> |
|
||||
| data | object | `{"type":"inquiry_received","subject":"새로운 상품 문의가 접수되었습니다"…` | <!-- TODO: 설명 --> |
|
||||
| read_at | string | `2026-07-31 22:06:53` | read 일시 |
|
||||
| created_at | string | `2026-07-31 21:41:58` | 생성 일시 |
|
||||
| number | integer | `92` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | string | `02ee1121-ec63-4812-b77a-a0ffb4040acb` | 기본 키 (내부 식별자) |
|
||||
| type | string | `new_order_admin` | 알림 유형 식별자 (알림 정의의 type — 발송 트리거를 구분) |
|
||||
| type_label | string | `신규 주문 관리자 알림` | `type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| subject | string | `새로운 주문이 접수되었습니다` | 알림 제목 (알림 템플릿의 subject 를 변수 치환해 렌더한 문자열) |
|
||||
| body | string | `소경은님이 주문번호 20260713-0038038875 (결제금액:…` | 알림 본문 (알림 템플릿의 body 를 변수 치환해 렌더한 문자열) |
|
||||
| url | string | `https://g7.dev/admin/ecommerce/orders…` | 알림 클릭 시 이동할 URL (템플릿의 click_url 우선, 없으면 메일 CTA action_url) |
|
||||
| data | object | `{"type":"new_order_admin","subject":"새로운 주문이 접수되었습니다","bo…` | 알림 원본 페이로드 객체 (type/subject/body/click_url 과 발송 시 전달된 변수 data 를 포함) |
|
||||
| read_at | null | `null` | read 일시 |
|
||||
| created_at | string | `2026-07-13 09:38:04` | 생성 일시 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
@@ -756,11 +822,27 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| marked_count | integer | `2` | 실제로 읽음 처리된 알림 건수 (요청한 `ids` 중 본인 소유이면서 미읽음 상태였던 항목만 집계) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "알림을 읽음 처리했습니다.",
|
||||
"data": {
|
||||
"marked_count": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -858,11 +940,21 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "알림이 삭제되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -903,11 +995,51 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (읽음 처리 후 갱신된 알림 1건 — `UserNotificationResource`)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | string | `9f2c1a44-1b6e-4a55-8b0e-4c8a3f1d90ab` | 알림 기본 키 (UUID) |
|
||||
| type | string | `order_shipped` | 알림 유형 식별자 (알림 정의의 type — 발송 트리거를 구분) |
|
||||
| type_label | string | `배송 시작 알림` | `type` 값의 사람이 읽는 라벨 (알림 정의의 현지화 이름, 정의 미존재 시 빈 문자열) |
|
||||
| subject | string | `주문하신 상품이 발송되었습니다` | 알림 제목 (알림 템플릿의 subject 를 변수 치환해 렌더한 문자열) |
|
||||
| body | string | `주문번호 20260713-0038038875 상품이 발송되었습니다.` | 알림 본문 (알림 템플릿의 body 를 변수 치환해 렌더한 문자열) |
|
||||
| url | string \| null | `https://g7.dev/mypage/orders/1` | 알림 클릭 시 이동할 URL (템플릿의 `click_url` 우선, 없으면 메일 CTA `action_url`, 둘 다 없으면 `null`) |
|
||||
| data | object | `{"type":"order_shipped","subject":"...","body":"...","click_url":"..."}` | 알림 원본 페이로드 객체 (type/subject/body/click_url 과 발송 시 전달된 변수 data 를 포함) |
|
||||
| read_at | string \| null | `2026-07-13 10:02:33` | 읽음 처리 일시 (사용자 타임존 기준 `Y-m-d H:i:s`) — 이 엔드포인트 성공 시 항상 값이 채워짐 |
|
||||
| created_at | string \| null | `2026-07-13 09:58:12` | 알림 생성 일시 (사용자 타임존 기준 `Y-m-d H:i:s`) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "알림을 읽음 처리했습니다.",
|
||||
"data": {
|
||||
"id": "9f2c1a44-1b6e-4a55-8b0e-4c8a3f1d90ab",
|
||||
"type": "order_shipped",
|
||||
"type_label": "배송 시작 알림",
|
||||
"subject": "주문하신 상품이 발송되었습니다",
|
||||
"body": "주문번호 20260713-0038038875 상품이 발송되었습니다.",
|
||||
"url": "https://g7.dev/mypage/orders/1",
|
||||
"data": {
|
||||
"type": "order_shipped",
|
||||
"subject": "주문하신 상품이 발송되었습니다",
|
||||
"body": "주문번호 20260713-0038038875 상품이 발송되었습니다.",
|
||||
"click_url": "https://g7.dev/mypage/orders/1",
|
||||
"data": {
|
||||
"action_url": "https://g7.dev/mypage/orders/1"
|
||||
}
|
||||
},
|
||||
"read_at": "2026-07-13 10:02:33",
|
||||
"created_at": "2026-07-13 09:58:12"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
|
||||
@@ -51,11 +51,17 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "비밀번호가 성공적으로 변경되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
|
||||
+787
-90
File diff suppressed because it is too large.
Load diff
+241
-8
@@ -38,11 +38,75 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`UserResource::toProfileArray()` 산물)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a231747f-e82e-4cf2-9ae1-a261849dce40` | 외부 노출용 UUID (URL/API 식별자, 내부 id 비노출) |
|
||||
| name | string | `홍길동` | 사용자 이름 |
|
||||
| nickname | string\|null | `gildong` | 닉네임 (미설정 시 null) |
|
||||
| email | string | `user@example.com` | 이메일 주소 |
|
||||
| avatar | string\|null | `null` | 아바타 이미지 URL (`User::getAvatarUrl()` 산물, 미등록 시 null) |
|
||||
| language | string | `ko` | 사용자 언어 설정 (`config('app.supported_locales')` 값 — 기본 `ko`, `en`) |
|
||||
| timezone | string\|null | `Asia/Seoul` | 사용자 시간대 식별자 |
|
||||
| country | string\|null | `KR` | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| status | string | `active` | 계정 상태 (`active`, `inactive`, `blocked`, `withdrawn`, `pending_verification`) |
|
||||
| status_label | string\|null | `활성` | 상태의 다국어 라벨 (`UserStatus::label()` 산물) |
|
||||
| status_variant | string\|null | `success` | 상태 배지 색상 키 (`success`/`secondary`/`danger`/`warning`/`info`) |
|
||||
| homepage | string\|null | `https://example.com` | 홈페이지 URL |
|
||||
| mobile | string\|null | `010-1234-5678` | 휴대전화 번호 |
|
||||
| phone | string\|null | `02-123-4567` | 전화번호 |
|
||||
| zipcode | string\|null | `06234` | 우편번호 |
|
||||
| address | string\|null | `서울특별시 강남구 테헤란로 1` | 기본 주소 |
|
||||
| address_detail | string\|null | `101동 202호` | 상세 주소 |
|
||||
| signature | string\|null | `null` | 게시글 서명 |
|
||||
| bio | string\|null | `null` | 자기소개 |
|
||||
| is_super | boolean | `false` | 슈퍼관리자 여부 (`User::isSuperAdmin()` 파생) |
|
||||
| is_admin | boolean | `false` | 관리자 역할 보유 여부 (`User::isAdmin()` 파생) |
|
||||
| withdrawn_at | string\|null | `null` | 탈퇴 처리 일시 (사용자 시간대 기준) |
|
||||
| last_login_at | string\|null | `2026-07-05 19:15:16` | 마지막 로그인 일시 (사용자 시간대 기준) |
|
||||
| last_login_human | string\|null | `1일 전` | 마지막 로그인 시각의 상대 표현 (`diffForHumans()` 산물) |
|
||||
| created_at | string\|null | `2026-07-06 19:15:16` | 가입 일시 (사용자 시간대 기준) |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 |
|
||||
|
||||
> 위 필드에 더해 `core.user.filter_resource_data` 훅으로 확장 소유 필드가 병합된다 (게시판 모듈 `notify_*`, 마케팅 플러그인 `marketing_consent*`/`email_subscription*`/`third_party_consent*`/`info_disclosure*`/`channels`/`consent_histories`, 이커머스 모듈 `ecommerce_*`). 전체 목록은 `GET /api/me` 문서 참조.
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "프로필 정보를 성공적으로 가져왔습니다.",
|
||||
"data": {
|
||||
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"name": "홍길동",
|
||||
"nickname": "gildong",
|
||||
"email": "user@example.com",
|
||||
"avatar": null,
|
||||
"language": "ko",
|
||||
"timezone": "Asia/Seoul",
|
||||
"country": "KR",
|
||||
"status": "active",
|
||||
"status_label": "활성",
|
||||
"status_variant": "success",
|
||||
"homepage": null,
|
||||
"mobile": "010-1234-5678",
|
||||
"phone": null,
|
||||
"zipcode": "06234",
|
||||
"address": "서울특별시 강남구 테헤란로 1",
|
||||
"address_detail": "101동 202호",
|
||||
"signature": null,
|
||||
"bio": null,
|
||||
"is_super": false,
|
||||
"is_admin": false,
|
||||
"withdrawn_at": null,
|
||||
"last_login_at": "2026-07-05 19:15:16",
|
||||
"last_login_human": "1일 전",
|
||||
"created_at": "2026-07-06 19:15:16",
|
||||
"is_owner": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -133,11 +197,83 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`UserResource::toArray()` 산물 — `show` 의 `toProfileArray()` 와 필드 구성이 다르다)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a234c2b1-cde8-437f-b28b-23323be2b98d` | 외부 노출용 UUID |
|
||||
| name | string | `홍길동` | 사용자 이름 |
|
||||
| nickname | string\|null | `gildong` | 닉네임 |
|
||||
| email | string | `user@example.com` | 이메일 주소 |
|
||||
| avatar | string\|null | `null` | 아바타 이미지 URL (미등록 시 null) |
|
||||
| language | string | `ko` | 사용자 언어 설정 |
|
||||
| language_label | string\|null | `한국어` | 언어의 다국어 라벨 (`user.language.{code}` 번역) |
|
||||
| country | string\|null | `KR` | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| status | string | `active` | 계정 상태 (`active`, `inactive`, `blocked`, `withdrawn`, `pending_verification`) |
|
||||
| status_label | string\|null | `활성` | 상태의 다국어 라벨 |
|
||||
| status_variant | string\|null | `success` | 상태 배지 색상 키 (`success`/`secondary`/`danger`/`warning`/`info`) |
|
||||
| is_admin | boolean | `false` | 관리자 역할 보유 여부 |
|
||||
| homepage | string\|null | `https://example.com` | 홈페이지 URL |
|
||||
| mobile | string\|null | `010-1234-5678` | 휴대전화 번호 |
|
||||
| phone | string\|null | `02-123-4567` | 전화번호 |
|
||||
| zipcode | string\|null | `06234` | 우편번호 |
|
||||
| address | string\|null | `서울특별시 강남구 테헤란로 1` | 기본 주소 |
|
||||
| address_detail | string\|null | `101동 202호` | 상세 주소 |
|
||||
| signature | string\|null | `null` | 게시글 서명 |
|
||||
| bio | string\|null | `null` | 자기소개 |
|
||||
| last_login_at | string\|null | `2026-07-05 19:15:16` | 마지막 로그인 일시 (사용자 시간대 기준) |
|
||||
| email_verified_at | string\|null | `null` | 이메일 인증 완료 일시 (미인증 시 null) |
|
||||
| timezone | string\|null | `Asia/Seoul` | 사용자 시간대 식별자 |
|
||||
| created_at | string\|null | `2026-07-06 19:15:16` | 가입 일시 |
|
||||
| updated_at | string\|null | `2026-07-08 10:41:24` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 |
|
||||
| abilities | object | `{"can_read":true,"can_update":true,...}` | 현재 사용자의 리소스 권한 맵 (`can_read`/`can_create`/`can_update`/`can_delete`/`can_assign_roles`) |
|
||||
|
||||
> `modules_count`/`plugins_count`/`menus_count`·`modules`/`plugins`/`menus`/`roles`/`permissions`/`consents`/`terms_consent`/`privacy_consent` 는 해당 관계가 로드된 경우에만 포함된다 (프로필 수정 응답에서는 로드되지 않아 생략). 확장 소유 필드는 `core.user.filter_resource_data` 훅으로 병합된다.
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "사용자 정보가 성공적으로 업데이트되었습니다.",
|
||||
"data": {
|
||||
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"name": "홍길동",
|
||||
"nickname": "gildong",
|
||||
"email": "user@example.com",
|
||||
"avatar": null,
|
||||
"language": "ko",
|
||||
"language_label": "한국어",
|
||||
"country": "KR",
|
||||
"status": "active",
|
||||
"status_label": "활성",
|
||||
"status_variant": "success",
|
||||
"is_admin": false,
|
||||
"homepage": null,
|
||||
"mobile": "010-1234-5678",
|
||||
"phone": null,
|
||||
"zipcode": "06234",
|
||||
"address": "서울특별시 강남구 테헤란로 1",
|
||||
"address_detail": "101동 202호",
|
||||
"signature": null,
|
||||
"bio": null,
|
||||
"last_login_at": "2026-07-05 19:15:16",
|
||||
"email_verified_at": null,
|
||||
"timezone": "Asia/Seoul",
|
||||
"created_at": "2026-07-06 19:15:16",
|
||||
"updated_at": "2026-07-08 10:41:24",
|
||||
"is_owner": true,
|
||||
"abilities": {
|
||||
"can_read": false,
|
||||
"can_create": false,
|
||||
"can_update": false,
|
||||
"can_delete": false,
|
||||
"can_assign_roles": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -174,11 +310,38 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체에 `activities` 배열이 담긴다 (페이지네이션 없음, 최신순 최대 50건)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| activities | array | `[{...}]` | 최근 활동 로그 목록 (최신순, 최대 50건) |
|
||||
| activities[].id | integer | `1` | 활동 로그 기본 키 |
|
||||
| activities[].action | string | `profile.update` | 활동 액션 키 (점 표기, 예: `profile.show`, `profile.update`, `auth.login`) |
|
||||
| activities[].action_label | string | `프로필 수정` | 액션의 다국어 라벨 (`activity_log.action.*` 번역, 확장 액션은 확장 lang 우선) |
|
||||
| activities[].description | string | `프로필 정보를 수정했습니다.` | 활동 설명 (현재 로케일 기준 렌더 결과, `description_key` 미설정 시 빈 문자열) |
|
||||
| activities[].ip_address | string\|null | `127.0.0.1` | 활동을 수행한 클라이언트 IP |
|
||||
| activities[].created_at | string\|null | `2026-07-06T19:15:16+09:00` | 활동 발생 일시 (ISO 8601) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "활동 기록을 성공적으로 가져왔습니다.",
|
||||
"data": {
|
||||
"activities": [
|
||||
{
|
||||
"id": 1024,
|
||||
"action": "profile.update",
|
||||
"action_label": "프로필 수정",
|
||||
"description": "프로필 정보를 수정했습니다.",
|
||||
"ip_address": "127.0.0.1",
|
||||
"created_at": "2026-07-06T19:15:16+09:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -214,11 +377,81 @@ Authorization: Bearer {YOUR_TOKEN} (optional.sanctum: 비회원은 헤더 생
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (`UserResource::toArray()` 산물 — `PUT /api/user/profile` 응답과 동일 구조)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a234c2b1-cde8-437f-b28b-23323be2b98d` | 외부 노출용 UUID |
|
||||
| name | string | `홍길동` | 사용자 이름 |
|
||||
| nickname | string\|null | `gildong` | 닉네임 |
|
||||
| email | string | `user@example.com` | 이메일 주소 |
|
||||
| avatar | string\|null | `null` | 아바타 이미지 URL |
|
||||
| language | string | `en` | 변경된 사용자 언어 설정 |
|
||||
| language_label | string\|null | `English` | 언어의 다국어 라벨 (`user.language.{code}` 번역) |
|
||||
| country | string\|null | `KR` | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| status | string | `active` | 계정 상태 |
|
||||
| status_label | string\|null | `활성` | 상태의 다국어 라벨 |
|
||||
| status_variant | string\|null | `success` | 상태 배지 색상 키 |
|
||||
| is_admin | boolean | `false` | 관리자 역할 보유 여부 |
|
||||
| homepage | string\|null | `null` | 홈페이지 URL |
|
||||
| mobile | string\|null | `010-1234-5678` | 휴대전화 번호 |
|
||||
| phone | string\|null | `null` | 전화번호 |
|
||||
| zipcode | string\|null | `06234` | 우편번호 |
|
||||
| address | string\|null | `서울특별시 강남구 테헤란로 1` | 기본 주소 |
|
||||
| address_detail | string\|null | `101동 202호` | 상세 주소 |
|
||||
| signature | string\|null | `null` | 게시글 서명 |
|
||||
| bio | string\|null | `null` | 자기소개 |
|
||||
| last_login_at | string\|null | `2026-07-05 19:15:16` | 마지막 로그인 일시 |
|
||||
| email_verified_at | string\|null | `null` | 이메일 인증 완료 일시 |
|
||||
| timezone | string\|null | `Asia/Seoul` | 사용자 시간대 식별자 |
|
||||
| created_at | string\|null | `2026-07-06 19:15:16` | 가입 일시 |
|
||||
| updated_at | string\|null | `2026-07-08 10:41:24` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 |
|
||||
| abilities | object | `{"can_read":false,...}` | 현재 사용자의 리소스 권한 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "언어 설정이 성공적으로 변경되었습니다.",
|
||||
"data": {
|
||||
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"name": "홍길동",
|
||||
"nickname": "gildong",
|
||||
"email": "user@example.com",
|
||||
"avatar": null,
|
||||
"language": "en",
|
||||
"language_label": "English",
|
||||
"country": "KR",
|
||||
"status": "active",
|
||||
"status_label": "활성",
|
||||
"status_variant": "success",
|
||||
"is_admin": false,
|
||||
"homepage": null,
|
||||
"mobile": "010-1234-5678",
|
||||
"phone": null,
|
||||
"zipcode": "06234",
|
||||
"address": "서울특별시 강남구 테헤란로 1",
|
||||
"address_detail": "101동 202호",
|
||||
"signature": null,
|
||||
"bio": null,
|
||||
"last_login_at": "2026-07-05 19:15:16",
|
||||
"email_verified_at": null,
|
||||
"timezone": "Asia/Seoul",
|
||||
"created_at": "2026-07-06 19:15:16",
|
||||
"updated_at": "2026-07-08 10:41:24",
|
||||
"is_owner": true,
|
||||
"abilities": {
|
||||
"can_read": false,
|
||||
"can_create": false,
|
||||
"can_update": false,
|
||||
"can_delete": false,
|
||||
"can_assign_roles": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
|
||||
@@ -440,7 +440,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — 컨트롤러가 `role.delete_success` 키로 `success()` 만 호출)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
|
||||
@@ -319,11 +319,27 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| deleted_count | integer | `3` | 실제로 삭제된 스케줄 건수 (`ScheduleService::bulkDelete` 반환값) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "선택한 스케줄이 삭제되었습니다.",
|
||||
"data": {
|
||||
"deleted_count": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -372,11 +388,27 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| updated_count | integer | `3` | 상태가 실제로 변경된 스케줄 건수 (`ScheduleService::bulkUpdateStatus` 반환값) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "선택한 스케줄의 상태가 변경되었습니다.",
|
||||
"data": {
|
||||
"updated_count": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -414,11 +446,21 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — 컨트롤러가 `success('schedule.history_delete_success')` 를 데이터 없이 호출)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "실행 이력이 삭제되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -426,7 +468,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.schedules.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 404 | Not Found | 지정한 `historyId` 의 실행 이력이 존재하지 않는 경우 (`schedule.history_not_found`) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
@@ -525,9 +567,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — 컨트롤러가 `success('schedule.delete_success')` 를 데이터 없이 호출)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
@@ -950,7 +990,25 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
목록 항목은 `ScheduleHistoryResource::toListArray()` 산물입니다 (단건 실행 응답과 달리 `output`/`error_output`/`memory_usage`(raw)/`created_at`/`updated_at` 은 포함되지 않습니다).
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `7` | 실행 이력의 기본 키 (내부 식별자) |
|
||||
| schedule_id | integer | `1` | 이 이력이 속한 스케줄의 식별자 |
|
||||
| started_at | string\|null | `2026-07-08T12:14:49+09:00` | 실행 시작 일시 (사용자 타임존 포맷) |
|
||||
| ended_at | string\|null | `2026-07-08T12:14:49+09:00` | 실행 종료 일시 (사용자 타임존 포맷, 실행 중이면 null) |
|
||||
| duration | integer\|null | `0` | 실행 소요 시간 |
|
||||
| duration_formatted | string\|null | `45초` | `duration` 값의 표시용 포맷 문자열 (모델 접근자 파생, 없으면 null) |
|
||||
| status | string | `success` | 실행 결과 상태: success(성공), failed(실패), running(실행중) |
|
||||
| status_label | string\|null | `성공` | `status` 값의 사람이 읽는 라벨 (`schedule.result.*` 현지화) |
|
||||
| exit_code | integer\|null | `0` | 실행 종료 코드 (0=성공, 그 외=실패) |
|
||||
| memory_usage_formatted | string\|null | `417.34 KB` | 실행 중 메모리 사용량의 표시용 포맷 문자열 |
|
||||
| trigger_type | string | `manual` | 실행 방식: scheduled(예약 자동 실행), manual(수동 즉시 실행) |
|
||||
| trigger_type_label | string\|null | `수동 실행` | `trigger_type` 값의 사람이 읽는 라벨 (`schedule.trigger_type.*` 현지화) |
|
||||
| triggered_by | object\|null | `{"uuid":"a234c2b1-cde8-437f-b28b-23323be2b98d","name":"관리자"}` | 수동 실행을 트리거한 사용자 정보 (uuid/name — triggeredBy 관계가 로드되지 않았거나 자동 실행이면 null) |
|
||||
|
||||
`data.pagination` 은 `current_page`/`last_page`/`per_page`/`total`/`from`/`to`/`has_more_pages` 로 구성됩니다.
|
||||
|
||||
**응답 예시**
|
||||
|
||||
@@ -963,14 +1021,30 @@ HTTP/1.1 200
|
||||
"success": true,
|
||||
"message": "실행 이력을 조회했습니다.",
|
||||
"data": {
|
||||
"data": [],
|
||||
"data": [
|
||||
{
|
||||
"id": 7,
|
||||
"schedule_id": 1,
|
||||
"started_at": "2026-07-08T12:14:49+09:00",
|
||||
"ended_at": "2026-07-08T12:14:49+09:00",
|
||||
"duration": 0,
|
||||
"duration_formatted": null,
|
||||
"status": "success",
|
||||
"status_label": "성공",
|
||||
"exit_code": 0,
|
||||
"memory_usage_formatted": "417.34 KB",
|
||||
"trigger_type": "manual",
|
||||
"trigger_type_label": "수동 실행",
|
||||
"triggered_by": null
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"current_page": 1,
|
||||
"last_page": 1,
|
||||
"per_page": 25,
|
||||
"total": 0,
|
||||
"from": null,
|
||||
"to": null,
|
||||
"total": 1,
|
||||
"from": 1,
|
||||
"to": 1,
|
||||
"has_more_pages": false
|
||||
}
|
||||
}
|
||||
|
||||
+42
-6
@@ -54,7 +54,7 @@ HTTP/1.1 200
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "messages.success",
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": {
|
||||
"urls": [],
|
||||
"count": 0
|
||||
@@ -106,11 +106,27 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| cleared | integer \| string | `12` / `"all"` | 삭제 결과. `layout` 을 지정한 경우 해당 레이아웃에서 무효화된 캐시 항목 수(정수), 미지정 시 전체 캐시를 삭제했음을 뜻하는 문자열 `"all"`. |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": {
|
||||
"cleared": "all"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -119,6 +135,7 @@ Content-Type: application/json
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 캐시 무효화(`invalidateByLayout` / `clearAll`) 중 예외가 발생한 경우 (`messages.error_occurred`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -315,7 +332,7 @@ HTTP/1.1 200
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "messages.success",
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": {
|
||||
"overall": {
|
||||
"total_entries": 0,
|
||||
@@ -365,11 +382,29 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| status | string | `dispatched` | 워밍업 요청 접수 상태. 현재 구현에서는 항상 `dispatched` 고정값이며, 실제 사전 렌더가 완료되었음을 뜻하지는 않는다. |
|
||||
| message | string | `SEO 캐시 워밍업이 시작되었습니다.` | 관리자에게 노출할 안내 문구 (`seo.warmup_dispatched` 다국어 키). |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "성공적으로 처리되었습니다.",
|
||||
"data": {
|
||||
"status": "dispatched",
|
||||
"message": "SEO 캐시 워밍업이 시작되었습니다."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -377,6 +412,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 500 | Internal Server Error | 워밍업 처리 중 예외가 발생한 경우 (`messages.error_occurred`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
|
||||
+303
-128
@@ -171,111 +171,111 @@ HTTP/1.1 200
|
||||
| advanced | body | array | 아니오 | — | 고급 탭 설정 묶음 (캐시·디버그·코어 업데이트·GeoIP 설정) |
|
||||
| notifications | body | array | 아니오 | — | 알림 탭 설정 묶음. channels 배열로 각 알림 채널의 id·is_active(활성 여부)·sort_order(표시 순서)를 저장 |
|
||||
| identity | body | array | 아니오 | — | 본인인증(IDV) 탭 설정 묶음 (기본 provider·목적별 provider 매핑·챌린지 유효시간·최대 시도 횟수) |
|
||||
| notifications.channels | body | array | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| notifications.channels | body | array | 아니오 | — | 알림 채널 목록. 각 원소는 `id`(채널 식별자, 필수·최대 50자)·`is_active`(활성 여부, 필수 boolean)·`sort_order`(표시 순서, 0 이상 정수) 로 구성 |
|
||||
| general.site_name | body | string | 예 | max 100 | general.site 이름 (식별자) |
|
||||
| general.site_url | body | string | 예 | max 255 | <!-- TODO: 용도 --> |
|
||||
| general.site_description | body | string | 아니오 | max 500 | <!-- TODO: 용도 --> |
|
||||
| general.admin_email | body | email | 예 | max 255 | <!-- TODO: 용도 --> |
|
||||
| general.timezone | body | string | 예 | — | <!-- TODO: 용도 --> |
|
||||
| general.language | body | string | 예 | — | <!-- TODO: 용도 --> |
|
||||
| general.currency | body | string | 아니오 | max 10 | <!-- TODO: 용도 --> |
|
||||
| general.maintenance_mode | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| general.site_logo | body | array | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| mail.mailer | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| mail.host | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| mail.port | body | integer | 아니오 | min 1, max 65535 | <!-- TODO: 용도 --> |
|
||||
| mail.username | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| mail.password | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| mail.encryption | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| mail.mailgun_domain | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| mail.mailgun_secret | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| mail.mailgun_endpoint | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| mail.ses_key | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| mail.ses_secret | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| mail.ses_region | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| mail.from_address | body | email | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| general.site_url | body | string | 예 | max 255 | 사이트 기본 URL |
|
||||
| general.site_description | body | string | 아니오 | max 500 | 사이트 설명 |
|
||||
| general.admin_email | body | email | 예 | max 255 | 관리자 이메일 주소 |
|
||||
| general.timezone | body | string | 예 | — | 타임존 식별자 |
|
||||
| general.language | body | string | 예 | — | 언어 코드 |
|
||||
| general.currency | body | string | 아니오 | max 10 | 통화 코드 (ISO 4217 — 예: KRW) |
|
||||
| general.maintenance_mode | body | boolean | 아니오 | — | 점검 모드 사용 여부 (사이트 접근 차단) |
|
||||
| general.site_logo | body | array | 아니오 | — | 사이트 로고 이미지 |
|
||||
| mail.mailer | body | string | 아니오 | — | 메일 발송 드라이버 (smtp/mailgun/ses) |
|
||||
| mail.host | body | string | 아니오 | max 255 | 호스트 주소 |
|
||||
| mail.port | body | integer | 아니오 | min 1, max 65535 | 포트 번호 |
|
||||
| mail.username | body | string | 아니오 | max 255 | 사용자명 (로그인/인증 아이디) |
|
||||
| mail.password | body | string | 아니오 | max 255 | 비밀번호 |
|
||||
| mail.encryption | body | string | 아니오 | — | 전송 암호화 방식 (tls/ssl) |
|
||||
| mail.mailgun_domain | body | string | 아니오 | max 255 | Mailgun 도메인 |
|
||||
| mail.mailgun_secret | body | string | 아니오 | max 255 | Mailgun 시크릿 키 |
|
||||
| mail.mailgun_endpoint | body | string | 아니오 | max 255 | Mailgun 엔드포인트 |
|
||||
| mail.ses_key | body | string | 아니오 | max 255 | SES 액세스 키 |
|
||||
| mail.ses_secret | body | string | 아니오 | max 255 | SES 시크릿 키 |
|
||||
| mail.ses_region | body | string | 아니오 | max 255 | SES 리전 |
|
||||
| mail.from_address | body | email | 아니오 | max 255 | 발신자 주소 |
|
||||
| mail.from_name | body | string | 아니오 | max 255 | mail.from 이름 (식별자) |
|
||||
| upload.max_file_size | body | integer | 아니오 | min 1, max 1024 | <!-- TODO: 용도 --> |
|
||||
| upload.allowed_extensions | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| upload.image_max_width | body | integer | 아니오 | min 100, max 10000 | <!-- TODO: 용도 --> |
|
||||
| upload.image_max_height | body | integer | 아니오 | min 100, max 10000 | <!-- TODO: 용도 --> |
|
||||
| upload.image_quality | body | integer | 아니오 | min 1, max 100 | <!-- TODO: 용도 --> |
|
||||
| seo.meta_title_suffix | body | string | 아니오 | max 100 | <!-- TODO: 용도 --> |
|
||||
| seo.meta_description | body | string | 아니오 | max 160 | <!-- TODO: 용도 --> |
|
||||
| seo.meta_keywords | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| upload.max_file_size | body | integer | 아니오 | min 1, max 1024 | 업로드 허용 최대 파일 크기 |
|
||||
| upload.allowed_extensions | body | string | 아니오 | — | 업로드 허용 확장자 목록 |
|
||||
| upload.image_max_width | body | integer | 아니오 | min 100, max 10000 | 이미지 리사이즈 최대 너비 (px) |
|
||||
| upload.image_max_height | body | integer | 아니오 | min 100, max 10000 | 이미지 리사이즈 최대 높이 (px) |
|
||||
| upload.image_quality | body | integer | 아니오 | min 1, max 100 | 이미지 리사이즈 시 압축 품질 (1~100) |
|
||||
| seo.meta_title_suffix | body | string | 아니오 | max 100 | 모든 페이지 SEO 제목 뒤에 붙는 접미 문구 |
|
||||
| seo.meta_description | body | string | 아니오 | max 160 | SEO 메타 설명 (검색엔진/소셜 공유 표시 요약) |
|
||||
| seo.meta_keywords | body | string | 아니오 | max 255 | SEO 메타 키워드 (검색엔진 노출 키워드, 쉼표 구분) |
|
||||
| seo.google_analytics_id | body | string | 아니오 | max 50 | seo.google analytics 식별자 |
|
||||
| seo.google_site_verification | body | string | 아니오 | max 100 | <!-- TODO: 용도 --> |
|
||||
| seo.naver_site_verification | body | string | 아니오 | max 100 | <!-- TODO: 용도 --> |
|
||||
| seo.bot_user_agents | body | array | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| seo.bot_detection_enabled | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| seo.bot_detection_library_enabled | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| seo.google_site_verification | body | string | 아니오 | max 100 | Google Search Console 사이트 소유 확인 코드 |
|
||||
| seo.naver_site_verification | body | string | 아니오 | max 100 | 네이버 서치어드바이저 사이트 소유 확인 코드 |
|
||||
| seo.bot_user_agents | body | array | 아니오 | — | 봇으로 판정할 User-Agent 목록 |
|
||||
| seo.bot_detection_enabled | body | boolean | 아니오 | — | 검색엔진 봇 감지 사용 여부 (봇 요청에 SEO 렌더링 적용) |
|
||||
| seo.bot_detection_library_enabled | body | boolean | 아니오 | — | 봇 감지 라이브러리 사용 여부 (User-Agent 목록 대신 라이브러리 판정) |
|
||||
| seo.og_default_site_name | body | string | 아니오 | max 200 | seo.og default site 이름 (식별자) |
|
||||
| seo.og_image_default_width | body | integer | 아니오 | min 0, max 8000 | <!-- TODO: 용도 --> |
|
||||
| seo.og_image_default_height | body | integer | 아니오 | min 0, max 8000 | <!-- TODO: 용도 --> |
|
||||
| seo.twitter_default_card | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| seo.twitter_default_site | body | string | 아니오 | max 50 | <!-- TODO: 용도 --> |
|
||||
| seo.cache_enabled | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| seo.cache_ttl | body | integer | 아니오 | min 60, max 86400 | <!-- TODO: 용도 --> |
|
||||
| seo.sitemap_enabled | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| seo.sitemap_cache_ttl | body | integer | 아니오 | min 3600, max 604800 | <!-- TODO: 용도 --> |
|
||||
| seo.sitemap_schedule | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| seo.sitemap_schedule_time | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| seo.generator_enabled | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| seo.generator_content | body | string | 아니오 | max 200 | <!-- TODO: 용도 --> |
|
||||
| security.force_https | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| security.login_attempt_enabled | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| security.auth_token_lifetime | body | integer | 아니오 | min 0, max 3600 | <!-- TODO: 용도 --> |
|
||||
| security.max_login_attempts | body | integer | 아니오 | min 0, max 100 | <!-- TODO: 용도 --> |
|
||||
| security.login_lockout_time | body | integer | 아니오 | min 0, max 1440 | <!-- TODO: 용도 --> |
|
||||
| advanced.cache_enabled | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| advanced.layout_cache_enabled | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| advanced.layout_cache_ttl | body | integer | 아니오 | min 0, max 14400 | <!-- TODO: 용도 --> |
|
||||
| advanced.stats_cache_enabled | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| advanced.stats_cache_ttl | body | integer | 아니오 | min 0, max 14400 | <!-- TODO: 용도 --> |
|
||||
| advanced.seo_cache_enabled | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| advanced.seo_cache_ttl | body | integer | 아니오 | min 0, max 14400 | <!-- TODO: 용도 --> |
|
||||
| advanced.debug_mode | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| advanced.sql_query_log | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| advanced.core_update_github_url | body | string | 아니오 | max 500 | <!-- TODO: 용도 --> |
|
||||
| advanced.core_update_github_token | body | string | 아니오 | max 500 | <!-- TODO: 용도 --> |
|
||||
| advanced.geoip_enabled | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| advanced.geoip_license_key | body | string | 아니오 | max 200 | <!-- TODO: 용도 --> |
|
||||
| advanced.geoip_auto_update_enabled | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| drivers.storage_driver | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| drivers.s3_bucket | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| drivers.s3_region | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| drivers.s3_access_key | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| drivers.s3_secret_key | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| drivers.s3_url | body | string | 아니오 | max 500 | <!-- TODO: 용도 --> |
|
||||
| drivers.cache_driver | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| drivers.redis_host | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| drivers.redis_port | body | integer | 아니오 | min 1, max 65535 | <!-- TODO: 용도 --> |
|
||||
| drivers.redis_password | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| drivers.redis_database | body | integer | 아니오 | min 0, max 15 | <!-- TODO: 용도 --> |
|
||||
| drivers.memcached_host | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| drivers.memcached_port | body | integer | 아니오 | min 1, max 65535 | <!-- TODO: 용도 --> |
|
||||
| drivers.session_driver | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| drivers.session_lifetime | body | integer | 아니오 | min 1, max 43200 | <!-- TODO: 용도 --> |
|
||||
| drivers.queue_driver | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| drivers.websocket_enabled | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| seo.og_image_default_width | body | integer | 아니오 | min 0, max 8000 | 기본 Open Graph 이미지 너비 (px) |
|
||||
| seo.og_image_default_height | body | integer | 아니오 | min 0, max 8000 | 기본 Open Graph 이미지 높이 (px) |
|
||||
| seo.twitter_default_card | body | string | 아니오 | — | 기본 트위터 카드 유형 (summary 등) |
|
||||
| seo.twitter_default_site | body | string | 아니오 | max 50 | 기본 트위터 사이트 계정 (@handle) |
|
||||
| seo.cache_enabled | body | boolean | 아니오 | — | 캐시 사용 여부 |
|
||||
| seo.cache_ttl | body | integer | 아니오 | min 60, max 86400 | 캐시 유효 시간 (초) |
|
||||
| seo.sitemap_enabled | body | boolean | 아니오 | — | sitemap.xml 생성 사용 여부 |
|
||||
| seo.sitemap_cache_ttl | body | integer | 아니오 | min 3600, max 604800 | sitemap 캐시 유효 시간 (초) |
|
||||
| seo.sitemap_schedule | body | string | 아니오 | — | sitemap 자동 생성 주기 |
|
||||
| seo.sitemap_schedule_time | body | string | 아니오 | — | sitemap 자동 생성 시각 |
|
||||
| seo.generator_enabled | body | boolean | 아니오 | — | SEO 페이지 생성기 사용 여부 |
|
||||
| seo.generator_content | body | string | 아니오 | max 200 | SEO 렌더링 본문 생성 방식 |
|
||||
| security.force_https | body | boolean | 아니오 | — | HTTPS 강제 리다이렉트 여부 |
|
||||
| security.login_attempt_enabled | body | boolean | 아니오 | — | 로그인 시도 제한 사용 여부 |
|
||||
| security.auth_token_lifetime | body | integer | 아니오 | min 0, max 3600 | 인증 토큰 유효 시간 (분) |
|
||||
| security.max_login_attempts | body | integer | 아니오 | min 0, max 100 | 로그인 실패 허용 횟수 (초과 시 잠금) |
|
||||
| security.login_lockout_time | body | integer | 아니오 | min 0, max 1440 | 로그인 잠금 지속 시간 (분) |
|
||||
| advanced.cache_enabled | body | boolean | 아니오 | — | 캐시 사용 여부 |
|
||||
| advanced.layout_cache_enabled | body | boolean | 아니오 | — | 레이아웃 캐시 사용 여부 (레이아웃 데이터를 캐시) |
|
||||
| advanced.layout_cache_ttl | body | integer | 아니오 | min 0, max 14400 | 레이아웃 캐시 만료 시간 (초, 0 = 만료 없음) |
|
||||
| advanced.stats_cache_enabled | body | boolean | 아니오 | — | 통계 캐시 사용 여부 (대시보드 통계를 캐시) |
|
||||
| advanced.stats_cache_ttl | body | integer | 아니오 | min 0, max 14400 | 통계 캐시 만료 시간 (초, 0 = 만료 없음) |
|
||||
| advanced.seo_cache_enabled | body | boolean | 아니오 | — | SEO 캐시 사용 여부 (SEO 메타데이터를 캐시) |
|
||||
| advanced.seo_cache_ttl | body | integer | 아니오 | min 0, max 14400 | SEO 캐시 만료 시간 (초, 0 = 만료 없음) |
|
||||
| advanced.debug_mode | body | boolean | 아니오 | — | 디버그 모드 사용 여부 (상세 오류 노출) |
|
||||
| advanced.sql_query_log | body | boolean | 아니오 | — | SQL 쿼리 로그 기록 여부 |
|
||||
| advanced.core_update_github_url | body | string | 아니오 | max 500 | 코어 업데이트를 확인할 GitHub 저장소 URL |
|
||||
| advanced.core_update_github_token | body | string | 아니오 | max 500 | 프라이빗 저장소의 코어/확장 업데이트에 사용할 GitHub 액세스 토큰 (공개 저장소는 비워둘 수 있음) |
|
||||
| advanced.geoip_enabled | body | boolean | 아니오 | — | IP 기반 타임존 감지(GeoIP) 사용 여부 |
|
||||
| advanced.geoip_license_key | body | string | 아니오 | max 200 | MaxMind GeoLite2 라이선스 키 |
|
||||
| advanced.geoip_auto_update_enabled | body | boolean | 아니오 | — | GeoIP DB 자동 업데이트 사용 여부 (주 1회 자동 재다운로드) |
|
||||
| drivers.storage_driver | body | string | 아니오 | — | 스토리지 드라이버 (local/s3) |
|
||||
| drivers.s3_bucket | body | string | 아니오 | max 255 | S3 버킷명 |
|
||||
| drivers.s3_region | body | string | 아니오 | — | S3 리전 |
|
||||
| drivers.s3_access_key | body | string | 아니오 | max 255 | S3 액세스 키 |
|
||||
| drivers.s3_secret_key | body | string | 아니오 | max 255 | S3 시크릿 키 |
|
||||
| drivers.s3_url | body | string | 아니오 | max 500 | S3 엔드포인트 URL |
|
||||
| drivers.cache_driver | body | string | 아니오 | — | 캐시 드라이버 (file/redis/memcached) |
|
||||
| drivers.redis_host | body | string | 아니오 | max 255 | Redis 호스트 주소 |
|
||||
| drivers.redis_port | body | integer | 아니오 | min 1, max 65535 | Redis 포트 번호 |
|
||||
| drivers.redis_password | body | string | 아니오 | max 255 | Redis 비밀번호 |
|
||||
| drivers.redis_database | body | integer | 아니오 | min 0, max 15 | Redis 데이터베이스 번호 |
|
||||
| drivers.memcached_host | body | string | 아니오 | max 255 | Memcached 호스트 주소 |
|
||||
| drivers.memcached_port | body | integer | 아니오 | min 1, max 65535 | Memcached 포트 번호 |
|
||||
| drivers.session_driver | body | string | 아니오 | — | 세션 드라이버 (file/database/redis) |
|
||||
| drivers.session_lifetime | body | integer | 아니오 | min 1, max 43200 | 세션 유효 시간 (분) |
|
||||
| drivers.queue_driver | body | string | 아니오 | — | 큐 드라이버 (sync/database/redis) |
|
||||
| drivers.websocket_enabled | body | boolean | 아니오 | — | WebSocket 사용 여부 |
|
||||
| drivers.websocket_app_id | body | string | 아니오 | max 255 | drivers.websocket app 식별자 |
|
||||
| drivers.websocket_app_key | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| drivers.websocket_app_secret | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| drivers.websocket_host | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| drivers.websocket_port | body | integer | 아니오 | min 1, max 65535 | <!-- TODO: 용도 --> |
|
||||
| drivers.websocket_scheme | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| drivers.websocket_verify_ssl | body | boolean | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| drivers.websocket_server_host | body | string | 아니오 | max 255 | <!-- TODO: 용도 --> |
|
||||
| drivers.websocket_server_port | body | integer | 아니오 | min 1, max 65535 | <!-- TODO: 용도 --> |
|
||||
| drivers.websocket_server_scheme | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| drivers.search_engine_driver | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| drivers.log_driver | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| drivers.log_level | body | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| drivers.log_days | body | integer | 아니오 | min 1, max 365 | <!-- TODO: 용도 --> |
|
||||
| identity.default_provider | body | string | 아니오 | max 100 | <!-- TODO: 용도 --> |
|
||||
| identity.purpose_providers | body | array | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| identity.challenge_ttl_minutes | body | integer | 아니오 | min 1, max 1440 | <!-- TODO: 용도 --> |
|
||||
| identity.max_attempts | body | integer | 아니오 | min 1, max 20 | <!-- TODO: 용도 --> |
|
||||
| drivers.websocket_app_key | body | string | 아니오 | max 255 | WebSocket 앱 키 |
|
||||
| drivers.websocket_app_secret | body | string | 아니오 | max 255 | WebSocket 앱 시크릿 |
|
||||
| drivers.websocket_host | body | string | 아니오 | max 255 | WebSocket 호스트 주소 |
|
||||
| drivers.websocket_port | body | integer | 아니오 | min 1, max 65535 | WebSocket 포트 번호 |
|
||||
| drivers.websocket_scheme | body | string | 아니오 | — | WebSocket 스킴 (http/https) |
|
||||
| drivers.websocket_verify_ssl | body | boolean | 아니오 | — | WebSocket 서버 SSL 인증서 검증 여부 |
|
||||
| drivers.websocket_server_host | body | string | 아니오 | max 255 | WebSocket 서버 호스트 주소 (서버측 발행 대상) |
|
||||
| drivers.websocket_server_port | body | integer | 아니오 | min 1, max 65535 | WebSocket 서버 포트 번호 (서버측 발행 대상) |
|
||||
| drivers.websocket_server_scheme | body | string | 아니오 | — | WebSocket 서버 스킴 (http/https — 서버측 발행 대상) |
|
||||
| drivers.search_engine_driver | body | string | 아니오 | — | 검색 엔진 드라이버 (Scout 엔진 선택) |
|
||||
| drivers.log_driver | body | string | 아니오 | — | 로그 드라이버 (single/daily/stack) |
|
||||
| drivers.log_level | body | string | 아니오 | — | 로그 레벨 (debug/info/warning/error 등) |
|
||||
| drivers.log_days | body | integer | 아니오 | min 1, max 365 | 로그 파일 보관 일수 |
|
||||
| identity.default_provider | body | string | 아니오 | max 100 | 본인인증 기본 프로바이더 (목적별로 지정되지 않은 경우 사용). 예: `g7:core.mail` |
|
||||
| identity.purpose_providers | body | array | 아니오 | — | 본인인증 목적(Purpose)별 프로바이더 매핑. 미지정 목적은 기본 프로바이더를 사용 |
|
||||
| identity.challenge_ttl_minutes | body | integer | 아니오 | min 1, max 1440 | 발급된 인증 코드/링크(challenge)의 유효시간 (분) |
|
||||
| identity.max_attempts | body | integer | 아니오 | min 1, max 20 | challenge 최대 시도 횟수 (연속 실패 시 잠금 — 재전송 필요) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.settings.save_validation_rules`, `core.search.engine_drivers`).
|
||||
|
||||
@@ -435,11 +435,55 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| settings | object | `{"general":{...},"security":{...},"available_drivers":{...}}` | 저장 직후 다시 조회한 전체 설정 집계. 구조는 `GET /api/admin/settings` 의 `data` 와 동일 (general/security/mail/upload/seo/advanced/cache/debug/drivers/core_update/geoip/notifications/identity + `available_drivers`) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "설정이 성공적으로 저장되었습니다.",
|
||||
"data": {
|
||||
"settings": {
|
||||
"general": {
|
||||
"site_name": "Test Site",
|
||||
"site_url": "https://test.example.com",
|
||||
"site_description": "",
|
||||
"admin_email": "admin@example.com",
|
||||
"timezone": "Asia/Seoul",
|
||||
"language": "ko",
|
||||
"currency": "KRW",
|
||||
"maintenance_mode": false,
|
||||
"site_logo": []
|
||||
},
|
||||
"security": {
|
||||
"force_https": true,
|
||||
"login_attempt_enabled": true,
|
||||
"auth_token_lifetime": 0,
|
||||
"max_login_attempts": 5,
|
||||
"login_lockout_time": 30
|
||||
},
|
||||
"available_drivers": {
|
||||
"storage": [
|
||||
{
|
||||
"id": "local",
|
||||
"label": {
|
||||
"ko": "로컬",
|
||||
"en": "Local"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 위 예시는 지면상 일부 그룹만 표기한 것으로, 실제 응답의 `data.settings` 에는 `GET /api/admin/settings` 와 동일한 전체 그룹이 포함됩니다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -534,11 +578,23 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| backup_path | string | `backups/backup_2026-07-14_030000.zip` | 생성된 설정 백업 ZIP 의 저장소 상대 경로 (카테고리별 설정 JSON 을 묶은 아카이브). `POST /api/admin/settings/restore` 의 `backup_path` 로 그대로 전달해 복원에 사용 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "데이터베이스 백업이 성공적으로 시작되었습니다.",
|
||||
"data": {
|
||||
"backup_path": "backups/backup_2026-07-14_030000.zip"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -546,6 +602,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 500 | Internal Server Error | 백업 파일 생성에 실패한 경우 (`settings.backup_failed`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -575,18 +632,26 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만). 컨트롤러가 `ResponseHelper::success('settings.backup_success')` 를 데이터 없이 호출하므로 `data` 는 `null` 입니다._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "데이터베이스 백업이 성공적으로 시작되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 400 | Bad Request | 백업이 수행되지 않은 경우 (`settings.backup_failed`) |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 500 | Internal Server Error | 백업 처리 중 예외가 발생한 경우 (`settings.backup_error`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -616,18 +681,26 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만). 컨트롤러가 `ResponseHelper::success('settings.cache_clear_success')` 를 데이터 없이 호출하므로 `data` 는 `null` 입니다._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "캐시가 성공적으로 정리되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 400 | Bad Request | 캐시 정리가 수행되지 않은 경우 (`settings.cache_clear_failed`) |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 500 | Internal Server Error | 캐시 정리 중 예외가 발생한 경우 (`settings.cache_clear_error`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -657,18 +730,38 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (GeoIpDatabaseService::updateDatabase() 의 `data`)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| database_path | string | `storage/app/geoip/GeoLite2-City.mmdb` | 갱신된 GeoLite2 DB 파일의 절대 경로 (`config('geoip.database_path')`) |
|
||||
| file_size_bytes | integer | `60000000` | 다운로드·전개 후 최종 DB 파일 크기 (바이트) |
|
||||
| elapsed_seconds | number | `12.34` | 다운로드부터 교체 완료까지 소요 시간 (초) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "settings.geoip.update_success",
|
||||
"data": {
|
||||
"database_path": "storage/app/geoip/GeoLite2-City.mmdb",
|
||||
"file_size_bytes": 60000000,
|
||||
"elapsed_seconds": 12.34
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `message` 는 컨트롤러가 넘기는 `settings.geoip.update_success` 키를 번역한 값입니다. 현재 코어 `lang/{ko,en}/settings.php` 에 `geoip.*` 항목이 정의되어 있지 않아 번역이 없으면 키 문자열이 그대로 내려갑니다 (관리자 화면은 프론트엔드 다국어 키로 별도 문구를 표시).
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 400 | Bad Request | MaxMind 라이선스 키가 설정되지 않은 경우 (`missing_license_key`) |
|
||||
| 401 | Unauthorized | MaxMind 라이선스 키가 유효하지 않은 경우 (`unauthorized`) |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 500 | Internal Server Error | MaxMind 연결 실패(`connection_failed`) 또는 다운로드·압축 해제 실패 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -698,9 +791,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만). 컨트롤러가 `ResponseHelper::success('settings.optimize_success')` 를 데이터 없이 호출하므로 `data` 는 `null` 입니다._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
@@ -760,19 +851,32 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| app_key | string | `base64:97gZH********************************` | 재생성된 애플리케이션 키를 마스킹한 문자열 (앞 12자 + 별표 32개). 전체 원문 키는 반환하지 않으며 `.env` 의 `APP_KEY` 에만 기록됨 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "어플리케이션 키가 성공적으로 재생성되었습니다.",
|
||||
"data": {
|
||||
"app_key": "base64:97gZH********************************"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 401 | Unauthorized | 본문 `password` 가 요청자 본인의 비밀번호와 일치하지 않는 경우 (`settings.invalid_password`) |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없거나, FormRequest 가 `super_admin` 역할이 아닌 사용자를 거부한 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | `.env` 기록/config 캐시 재생성 실패 (`settings.app_key_regenerate_failed`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -811,19 +915,27 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만). 컨트롤러가 `ResponseHelper::success('settings.restore_success')` 를 데이터 없이 호출하므로 `data` 는 `null` 입니다._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: side-effectful-write — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "설정이 성공적으로 복원되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 400 | Bad Request | 복원이 수행되지 않은 경우 (`settings.restore_failed`) |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 백업 파일을 읽을 수 없는 등 복원 중 예외 발생 (`settings.restore_error`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -1047,11 +1159,35 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (DriverConnectionTester::testAll() 산물)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| results | object | `{"redis":{"success":true,"message":"Redis 서버에 성공적으로 연결되었습니다.","latency":"3ms"}}` | 드라이버별 테스트 결과 맵. 키는 실제 테스트가 수행된 드라이버(`s3`/`redis`/`memcached`/`websocket`)만 포함 — 요청 설정에서 해당 드라이버를 쓰지 않으면 키 자체가 없음 |
|
||||
| results.{driver}.success | boolean | `true` | 해당 드라이버 연결 성공 여부 |
|
||||
| results.{driver}.message | string | `Redis 서버에 성공적으로 연결되었습니다.` | 결과 메시지 (성공/실패 사유 — 설정 누락·확장 미설치·인증 실패 등) |
|
||||
| results.{driver}.latency | string | `3ms` | 성공 시에만 포함. 연결 왕복 소요 시간 |
|
||||
| results.{driver}.error | string | `Connection refused` | 실패 시에만 포함. 원본 예외 메시지 |
|
||||
| all_passed | boolean | `true` | 수행된 모든 드라이버 테스트가 성공했는지 여부. `false` 여도 HTTP 200 으로 응답하며 message 가 `일부 드라이버 연결 테스트가 실패했습니다.` 로 바뀜 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "모든 드라이버 연결 테스트가 성공했습니다.",
|
||||
"data": {
|
||||
"results": {
|
||||
"redis": {
|
||||
"success": true,
|
||||
"message": "Redis 서버에 성공적으로 연결되었습니다.",
|
||||
"latency": "3ms"
|
||||
}
|
||||
},
|
||||
"all_passed": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -1060,6 +1196,7 @@ Content-Type: application/json
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 테스트 실행 중 예외가 발생한 경우 (`settings.driver_test_error`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -1126,11 +1263,25 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-500 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (발송 성공 시에만 반환)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| subject | string | `그누보드7 테스트 메일` | 실제로 발송한 테스트 메일의 제목 (`settings.test_mail_subject` — 앱 이름이 치환됨) |
|
||||
| body | string | `이것은 그누보드7에서 발송한 테스트 메일입니다. 이 메일을 받으셨다면 메일 설정이 올바르게 구성되어 있습니다.` | 실제로 발송한 테스트 메일의 본문 (`settings.test_mail_body`, 평문) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-500 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "테스트 메일이 성공적으로 발송되었습니다.",
|
||||
"data": {
|
||||
"subject": "그누보드7 테스트 메일",
|
||||
"body": "이것은 그누보드7에서 발송한 테스트 메일입니다. 이 메일을 받으셨다면 메일 설정이 올바르게 구성되어 있습니다."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -1139,6 +1290,7 @@ Content-Type: application/json
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 발송 실패 시 — `message` 는 `테스트 메일 발송에 실패했습니다.`, `error` 에 원본 예외 메시지(SMTP 인증 실패·연결 거부 등)가 담김 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -1170,11 +1322,25 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| key | string | `general.site_name` | 요청한 설정 키를 그대로 되돌려 준 값 (`{category}.{field}` 형태) |
|
||||
| value | mixed | `Test Site` | 해당 설정 키의 현재 값. 설정 항목의 자료형에 따라 문자열/정수/불리언/배열이 될 수 있으며, 키가 없으면 `null` |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "설정을 성공적으로 가져왔습니다.",
|
||||
"data": {
|
||||
"key": "general.site_name",
|
||||
"value": "Test Site"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -1183,6 +1349,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 500 | Internal Server Error | 설정 조회 중 예외가 발생한 경우 (`settings.fetch_failed`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -1222,20 +1389,28 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만). 컨트롤러가 `ResponseHelper::success('settings.update_success')` 를 데이터 없이 호출하므로 `data` 는 `null` 입니다._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "설정이 성공적으로 업데이트되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 400 | Bad Request | 저장이 수행되지 않은 경우 (`settings.update_failed`) |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 저장 중 예외가 발생한 경우 (`settings.update_error`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
|
||||
+1725
-224
File diff suppressed because it is too large.
Load diff
+280
-15
@@ -293,11 +293,85 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (생성된 사용자 — `UserResource::toArray()`, 관계 미로드이므로 modules/plugins/menus/roles/permissions/consents 키는 응답에 포함되지 않음)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a234c2b1-cde8-437f-b28b-23323be2b98d` | 외부 노출용 UUID (URL/API 식별자, 내부 id 비노출) |
|
||||
| name | string | `API 문서 샘플 사용자` | 사용자 이름 |
|
||||
| nickname | string\|null | `null` | 닉네임 |
|
||||
| email | string | `apidoc-sample-user@example.com` | 이메일 주소 |
|
||||
| avatar | string\|null | `null` | 프로필 아바타 이미지 URL (미설정 시 null) |
|
||||
| language | string | `ko` | 사용자 언어 설정 (ko: 한국어, en: English) |
|
||||
| language_label | string | `한국어` | 언어 코드의 현지화 라벨 (`user.language.{code}` 번역) |
|
||||
| country | string\|null | `KR` | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| status | string | `active` | 계정 상태 (UserStatus Enum: active/inactive/blocked/withdrawn) |
|
||||
| status_label | string | `활성` | 상태의 사람이 읽는 라벨 (UserStatus::label()) |
|
||||
| status_variant | string | `success` | 상태 표시 색상/스타일 변형 키 (UserStatus::variant() — UI 배지용) |
|
||||
| is_admin | boolean | `false` | 관리자 역할 보유 여부 (User::isAdmin()) |
|
||||
| homepage | string\|null | `null` | 홈페이지 URL |
|
||||
| mobile | string\|null | `null` | 휴대폰 번호 |
|
||||
| phone | string\|null | `null` | 전화번호 |
|
||||
| zipcode | string\|null | `null` | 우편번호 |
|
||||
| address | string\|null | `null` | 기본 주소 |
|
||||
| address_detail | string\|null | `null` | 상세 주소 |
|
||||
| signature | string\|null | `null` | 서명 |
|
||||
| bio | string\|null | `null` | 자기소개 |
|
||||
| last_login_at | string\|null | `null` | 마지막 로그인 일시 (신규 생성 시 null) |
|
||||
| email_verified_at | string\|null | `null` | 이메일 인증 일시 (미인증 시 null) |
|
||||
| timezone | string\|null | `Asia/Seoul` | 사용자 시간대 |
|
||||
| created_at | string | `2026-07-08 10:41:24` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-08 10:41:24` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `false` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":true,"can_create":true,"can_update":true,"can_delete":true,"can_assign_roles":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (슈퍼관리자 대상은 can_delete=false 강제) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 201
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "사용자가 성공적으로 생성되었습니다.",
|
||||
"data": {
|
||||
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"name": "예시 이름",
|
||||
"nickname": null,
|
||||
"email": "user@example.com",
|
||||
"avatar": null,
|
||||
"language": "ko",
|
||||
"language_label": "한국어",
|
||||
"country": "KR",
|
||||
"status": "active",
|
||||
"status_label": "활성",
|
||||
"status_variant": "success",
|
||||
"is_admin": false,
|
||||
"homepage": null,
|
||||
"mobile": "010-1234-5678",
|
||||
"phone": null,
|
||||
"zipcode": null,
|
||||
"address": null,
|
||||
"address_detail": null,
|
||||
"signature": null,
|
||||
"bio": null,
|
||||
"last_login_at": null,
|
||||
"email_verified_at": null,
|
||||
"timezone": "Asia/Seoul",
|
||||
"created_at": "2026-07-08 10:41:24",
|
||||
"updated_at": "2026-07-08 10:41:24",
|
||||
"is_owner": false,
|
||||
"abilities": {
|
||||
"can_read": true,
|
||||
"can_create": true,
|
||||
"can_update": true,
|
||||
"can_delete": true,
|
||||
"can_assign_roles": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -306,6 +380,7 @@ Content-Type: application/json
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | Internal Server Error | 사용자 생성 중 예외 발생 (`user.create_failed`, `errors.error` 에 예외 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -348,11 +423,29 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (UserService::bulkUpdateStatus() 반환값)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| updated_count | integer | `3` | 실제로 상태가 변경된 사용자 수 (요청자 본인 제외 규칙 적용 후 갱신된 행 수) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": ":count명의 사용자 상태가 변경되었습니다.",
|
||||
"data": {
|
||||
"updated_count": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `user.bulk_status_updated` 메시지는 `:count` 치환자를 갖지만 컨트롤러가 messageParams 를 넘기지 않으므로 응답 message 에는 치환되지 않은 원문이 그대로 담긴다. 실제 변경 건수는 `data.updated_count` 로 판단한다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -360,7 +453,8 @@ Content-Type: application/json
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지 — 예: 요청자 본인 UUID 포함 시 `ExcludeCurrentUser` 위반) |
|
||||
| 500 | Internal Server Error | 일괄 변경 중 예외 발생 (`user.bulk_update_status_failed`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -401,11 +495,29 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| available | boolean | `true` | 해당 이메일의 사용 가능 여부 (true: 사용 가능, false: 이미 사용 중). `exclude_user_id` 로 지정한 사용자가 소유한 이메일이면 true 로 판정 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "사용 가능한 이메일입니다.",
|
||||
"data": {
|
||||
"available": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 이미 사용 중인 이메일이면 동일한 200 응답에 `message` 가 `이미 사용 중인 이메일입니다.` (`user.email_unavailable`), `data.available` 이 `false` 로 반환된다.
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -413,7 +525,8 @@ Content-Type: application/json
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지 — 이메일 형식/필수, exclude_user_id UUID 형식·존재 여부) |
|
||||
| 500 | Internal Server Error | 중복 확인 중 예외 발생 (`user.email_check_failed`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -695,11 +808,87 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_목록 응답: `data[]` 배열 항목의 필드 (페이지네이션 없는 단순 컬렉션 — `UserResource::collection()`, 관계 미로드이므로 modules/plugins/menus/roles/permissions/consents 키는 포함되지 않음). 일치하는 사용자가 없으면 `data` 는 빈 배열._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a234c2b1-cde8-437f-b28b-23323be2b98d` | 외부 노출용 UUID (URL/API 식별자, 내부 id 비노출) |
|
||||
| name | string | `API 문서 샘플 사용자` | 사용자 이름 |
|
||||
| nickname | string\|null | `null` | 닉네임 |
|
||||
| email | string | `apidoc-sample-user@example.com` | 이메일 주소 |
|
||||
| avatar | string\|null | `null` | 프로필 아바타 이미지 URL (미설정 시 null) |
|
||||
| language | string | `ko` | 사용자 언어 설정 (ko: 한국어, en: English) |
|
||||
| language_label | string | `한국어` | 언어 코드의 현지화 라벨 (`user.language.{code}` 번역) |
|
||||
| country | string\|null | `KR` | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| status | string | `active` | 계정 상태 (UserStatus Enum: active/inactive/blocked/withdrawn) |
|
||||
| status_label | string | `활성` | 상태의 사람이 읽는 라벨 (UserStatus::label()) |
|
||||
| status_variant | string | `success` | 상태 표시 색상/스타일 변형 키 (UserStatus::variant() — UI 배지용) |
|
||||
| is_admin | boolean | `true` | 관리자 역할 보유 여부 (User::isAdmin()) |
|
||||
| homepage | string\|null | `null` | 홈페이지 URL |
|
||||
| mobile | string\|null | `null` | 휴대폰 번호 |
|
||||
| phone | string\|null | `null` | 전화번호 |
|
||||
| zipcode | string\|null | `null` | 우편번호 |
|
||||
| address | string\|null | `null` | 기본 주소 |
|
||||
| address_detail | string\|null | `null` | 상세 주소 |
|
||||
| signature | string\|null | `null` | 서명 |
|
||||
| bio | string\|null | `null` | 자기소개 |
|
||||
| last_login_at | string\|null | `2026-07-07 10:41:24` | 마지막 로그인 일시 (미로그인 시 null) |
|
||||
| email_verified_at | string\|null | `2026-07-08 10:41:24` | 이메일 인증 일시 (미인증 시 null) |
|
||||
| timezone | string\|null | `Asia/Seoul` | 사용자 시간대 |
|
||||
| created_at | string | `2026-07-08 10:41:24` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-08 10:41:24` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `false` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":true,"can_create":true,"can_update":true,"can_delete":true,"can_assign_roles":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "사용자 검색을 성공적으로 완료했습니다.",
|
||||
"data": [
|
||||
{
|
||||
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"name": "API 문서 샘플 사용자",
|
||||
"nickname": null,
|
||||
"email": "apidoc-sample-user@example.com",
|
||||
"avatar": null,
|
||||
"language": "ko",
|
||||
"language_label": "한국어",
|
||||
"country": "KR",
|
||||
"status": "active",
|
||||
"status_label": "활성",
|
||||
"status_variant": "success",
|
||||
"is_admin": true,
|
||||
"homepage": null,
|
||||
"mobile": null,
|
||||
"phone": null,
|
||||
"zipcode": null,
|
||||
"address": null,
|
||||
"address_detail": null,
|
||||
"signature": null,
|
||||
"bio": null,
|
||||
"last_login_at": "2026-07-07 10:41:24",
|
||||
"email_verified_at": "2026-07-08 10:41:24",
|
||||
"timezone": "Asia/Seoul",
|
||||
"created_at": "2026-07-08 10:41:24",
|
||||
"updated_at": "2026-07-08 10:41:24",
|
||||
"is_owner": true,
|
||||
"abilities": {
|
||||
"can_read": true,
|
||||
"can_create": true,
|
||||
"can_update": true,
|
||||
"can_delete": true,
|
||||
"can_assign_roles": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -707,7 +896,8 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지 — `keyword`/`uuid` 를 모두 생략한 경우 포함) |
|
||||
| 500 | Internal Server Error | 검색 중 예외 발생 (`user.search_failed`) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
@@ -809,7 +999,7 @@ Authorization: Bearer {YOUR_TOKEN}
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — `data` 는 `null`)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
@@ -1151,11 +1341,85 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
_단건 응답: `data` 객체의 필드 (수정된 사용자 — `UserResource::toArray()`, 관계 미로드이므로 modules/plugins/menus/roles/permissions/consents 키는 응답에 포함되지 않음)._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a234c2b1-cde8-437f-b28b-23323be2b98d` | 외부 노출용 UUID (URL/API 식별자, 내부 id 비노출) |
|
||||
| name | string | `API 문서 샘플 사용자` | 사용자 이름 |
|
||||
| nickname | string\|null | `null` | 닉네임 |
|
||||
| email | string | `apidoc-sample-user@example.com` | 이메일 주소 |
|
||||
| avatar | string\|null | `null` | 프로필 아바타 이미지 URL (미설정 시 null) |
|
||||
| language | string | `ko` | 사용자 언어 설정 (ko: 한국어, en: English) |
|
||||
| language_label | string | `한국어` | 언어 코드의 현지화 라벨 (`user.language.{code}` 번역) |
|
||||
| country | string\|null | `KR` | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| status | string | `active` | 계정 상태 (UserStatus Enum: active/inactive/blocked/withdrawn) |
|
||||
| status_label | string | `활성` | 상태의 사람이 읽는 라벨 (UserStatus::label()) |
|
||||
| status_variant | string | `success` | 상태 표시 색상/스타일 변형 키 (UserStatus::variant() — UI 배지용) |
|
||||
| is_admin | boolean | `true` | 관리자 역할 보유 여부 (User::isAdmin()) |
|
||||
| homepage | string\|null | `https://example.com` | 홈페이지 URL |
|
||||
| mobile | string\|null | `010-1234-5678` | 휴대폰 번호 |
|
||||
| phone | string\|null | `null` | 전화번호 |
|
||||
| zipcode | string\|null | `null` | 우편번호 |
|
||||
| address | string\|null | `null` | 기본 주소 |
|
||||
| address_detail | string\|null | `null` | 상세 주소 |
|
||||
| signature | string\|null | `null` | 서명 |
|
||||
| bio | string\|null | `null` | 자기소개 |
|
||||
| last_login_at | string\|null | `2026-07-07 10:41:24` | 마지막 로그인 일시 (미로그인 시 null) |
|
||||
| email_verified_at | string\|null | `2026-07-08 10:41:24` | 이메일 인증 일시 (미인증 시 null) |
|
||||
| timezone | string\|null | `Asia/Seoul` | 사용자 시간대 |
|
||||
| created_at | string | `2026-07-08 10:41:24` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-08 11:02:07` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `false` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":true,"can_create":true,"can_update":true,"can_delete":true,"can_assign_roles":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (슈퍼관리자 대상은 can_delete=false 강제) |
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 예시는 사람이 작성하세요. -->
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "사용자 정보가 성공적으로 업데이트되었습니다.",
|
||||
"data": {
|
||||
"uuid": "a234c2b1-cde8-437f-b28b-23323be2b98d",
|
||||
"name": "예시 이름",
|
||||
"nickname": null,
|
||||
"email": "user@example.com",
|
||||
"avatar": null,
|
||||
"language": "ko",
|
||||
"language_label": "한국어",
|
||||
"country": "KR",
|
||||
"status": "active",
|
||||
"status_label": "활성",
|
||||
"status_variant": "success",
|
||||
"is_admin": false,
|
||||
"homepage": "https://example.com",
|
||||
"mobile": "010-1234-5678",
|
||||
"phone": null,
|
||||
"zipcode": null,
|
||||
"address": null,
|
||||
"address_detail": null,
|
||||
"signature": null,
|
||||
"bio": null,
|
||||
"last_login_at": null,
|
||||
"email_verified_at": null,
|
||||
"timezone": "Asia/Seoul",
|
||||
"created_at": "2026-07-08 10:41:24",
|
||||
"updated_at": "2026-07-08 11:02:07",
|
||||
"is_owner": false,
|
||||
"abilities": {
|
||||
"can_read": true,
|
||||
"can_create": true,
|
||||
"can_update": true,
|
||||
"can_delete": true,
|
||||
"can_assign_roles": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
@@ -1164,7 +1428,8 @@ Content-Type: application/json
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지 — 마지막 관리자 본인의 admin 역할 제거 시도 시 `user.last_admin_role_cannot_remove` 포함) |
|
||||
| 500 | Internal Server Error | 수정 중 예외 발생 (`user.update_failed`, `errors.error` 에 예외 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
|
||||
@@ -45,18 +45,25 @@ Content-Type: application/json
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-401 — 응답 필드는 사람이 작성하세요. -->
|
||||
_이 엔드포인트는 `data` 를 반환하지 않습니다 (성공 메시지만 — 컨트롤러가 `ResponseHelper::success('user.password_verified')` 를 인자 없이 호출하므로 `data` 는 `null` 입니다)._
|
||||
|
||||
**응답 예시**
|
||||
|
||||
<!-- 실측 제외: http-401 — 응답 예시는 사람이 작성하세요. -->
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "비밀번호가 확인되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 401 | 비밀번호 불일치 | 전달한 `password` 가 저장된 해시와 일치하지 않는 경우 (`message`: 비밀번호가 일치하지 않습니다.) |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 500 | 비밀번호 확인 실패 | 확인 처리 중 예기치 못한 예외가 발생한 경우 (`message`: 비밀번호 확인에 실패했습니다.) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
|
||||
Reference in new issue
Block a user