feat(api-docs): API 레퍼런스 문서 전면화 — 추출 파이프라인·전 대상 문서화·audit 강제
코드에만 존재하던 REST API 계약(약 663 엔드포인트)을 코어/확장 책임별로
분리된 마크다운 레퍼런스로 전면 문서화한다. 674개 규모에서 수기 문서는
반드시 drift 하므로 "코드 추출 → 스캐폴딩 → 사람이 서술 채움 → 하네스가
커버리지 강제" 하이브리드로 구성했다.
추출 파이프라인 (app/Support/ApiDoc):
- ApiRouteInventory / FormRequestIntrospector / ApiEndpointProbe(실측 HTTP) /
ResponseSchemaInferrer / ApiDocScaffolder / ColumnCommentResolver /
ResourceFieldDescriber / ParameterDescriber
- api:docgen 커맨드(--scope/--seed/--check/--dry-run/--base-url/--user) +
응답/파라미터 in-place 백필 커맨드 2종(재생성 없이 TODO 셀만 치환, 멱등)
- ApiDocSampleSeeder 계약 + 코어/확장 시더로 실측용 완전 샘플 멱등 생성
문서화 (실측 기반, GET read-only 실호출):
- 코어 291엔드포인트 35파일(docs/backend/api) + 규정 docs/backend/api-documentation.md
- 확장: ecommerce(231)·board(80)·page(17)·hello_module(2)·pay_kginicis(22)·
gdpr(15)·ckeditor5(2)·marketing(2)·verification_kginicis(1)
- 표준 4구성(헤더·요청 파라미터·응답 필드·에러 표) + 엔드포인트 용도 서술
- 파라미터 용도·응답 필드 설명 셀 전수 채움(도메인 지식 수기)
하네스:
- audit 룰 api-doc-coverage — API 표면(라우트/컨트롤러/FormRequest/Resource)
변경 시 대응 문서 미동반이면 차단. 전 대상 문서 완비로 error 승격
- file-rules 리마인더(컨트롤러/라우트 편집 시), coverage.json, dev-dashboard 카드
- docs/backend/routing.md 확장 공개 API URL 스킴 정정(/api/modules|plugins/{id})
- /AGENTS.md/docs-index 동기
This commit is contained in:
@@ -6,13 +6,14 @@
|
||||
|
||||
<!-- AUTO-GENERATED-START: docs-quick-reference -->
|
||||
|
||||
### 백엔드 [backend/](docs/backend/) (31개)
|
||||
### 백엔드 [backend/](docs/backend/) (32개)
|
||||
|
||||
| 문서 | 설명 | TL;DR 핵심 |
|
||||
|------|------|-----------|
|
||||
| [activity-log-hooks.md](docs/backend/activity-log-hooks.md) | 활동 로그 훅 레퍼런스 (Activity Log Hooks Reference) | 코어 66훅 + 이커머스 92훅 + 게시판 32훅 + 페이지 8훅 = 총 198훅 |
|
||||
| [activity-log.md](docs/backend/activity-log.md) | 활동 로그 시스템 (Activity Log System) | Monolog 기반: Service 훅 → Listener → Log::channel('activity... |
|
||||
| [admin-settings-access.md](docs/backend/admin-settings-access.md) | Admin 환경설정 값 접근 (`g7_core_settings` vs `config()`) | 동기화 SSoT: storage/app/settings/*.json → SettingsServicePr... |
|
||||
| [api-documentation.md](docs/backend/api-documentation.md) | API 레퍼런스 문서 규정 (API Documentation) | 모든 API 엔드포인트는 레퍼런스 문서 필수 — 메서드/URI/파라미터/응답 필드 전수 기재 |
|
||||
| [api-resources.md](docs/backend/api-resources.md) | API 리소스 | Resource: BaseApiResource 상속 필수 / Collection: BaseApiColl... |
|
||||
| [authentication.md](docs/backend/authentication.md) | 인증 및 세션 처리 | Laravel Sanctum 토큰 전용 인증 (Bearer 토큰만 사용) |
|
||||
| [broadcasting.md](docs/backend/broadcasting.md) | Broadcasting (실시간 이벤트) | Laravel Reverb 사용 (WebSocket) |
|
||||
@@ -914,7 +915,7 @@ php artisan migrate:rollback
|
||||
|
||||
| 수정 대상 파일 패턴 | 작업 전 필수 참조 |
|
||||
| ------------------- | ------------------ |
|
||||
| `app/Http/Controllers/**` | [controllers.md](docs/backend/controllers.md) |
|
||||
| `app/Http/Controllers/**` | [controllers.md](docs/backend/controllers.md), [api-documentation.md](docs/backend/api-documentation.md) |
|
||||
| `app/Services/**` | [service-repository.md](docs/backend/service-repository.md) |
|
||||
| `app/Http/Requests/**` | [validation.md](docs/backend/validation.md) |
|
||||
| `app/Repositories/**` | [service-repository.md](docs/backend/service-repository.md) |
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Support\ApiDoc\ResourceFieldDescriber;
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
/**
|
||||
* 기존 API 문서의 응답 필드 설명 TODO 를 리소스 계약 사전 설명으로 소급 채웁니다.
|
||||
*
|
||||
* 파라미터 TODO 는 `api:docgen-backfill-params` 가 채우지만, 응답 필드 TODO 는 전용
|
||||
* 백필 커맨드가 없어 재생성(`api:docgen`)으로만 갱신되었습니다. 실측 서버 없이
|
||||
* 재생성하면 이미 실측된 응답 예시값이 퇴행하므로, 이 커맨드는 재생성 대신 응답 필드
|
||||
* 표의 `<!-- TODO: 설명 -->` 셀만 in-place 치환합니다.
|
||||
*
|
||||
* 채움 규칙 SSoT 는 ApiDocScaffolder::responseFieldTable 과 동일한 ResourceFieldDescriber
|
||||
* 입니다 — 이후 정상 재생성(실측 서버 가동 시)도 같은 설명을 산출하므로 멱등합니다.
|
||||
*
|
||||
* 도메인 특이 필드(ResourceFieldDescriber 가 null 반환)는 TODO 를 그대로 둡니다.
|
||||
* 응답 필드 표만 대상으로 하며, 파라미터 표(`<!-- TODO: 용도 -->`)는 건드리지 않습니다.
|
||||
*/
|
||||
class ApiDocBackfillFieldsCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var string 커맨드 시그니처
|
||||
*/
|
||||
protected $signature = 'api:docgen-backfill-fields
|
||||
{--dry-run : 치환하지 않고 채울 건수만 리포트}';
|
||||
|
||||
/**
|
||||
* @var string 커맨드 설명
|
||||
*/
|
||||
protected $description = '기존 API 문서의 응답 필드 설명 TODO 를 리소스 계약 사전 설명으로 소급 채웁니다';
|
||||
|
||||
/**
|
||||
* @var string 응답 필드 표를 식별하는 고유 헤더
|
||||
*/
|
||||
private const FIELD_TABLE_HEADER = '| 필드 | 타입 | 실측 예시값 | 용도/설명 |';
|
||||
|
||||
/**
|
||||
* @var string 응답 필드 설명 TODO 마커
|
||||
*/
|
||||
private const TODO_MARKER = '<!-- TODO: 설명 -->';
|
||||
|
||||
/**
|
||||
* 커맨드를 실행합니다.
|
||||
*
|
||||
* @return int 종료 코드
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$describer = new ResourceFieldDescriber;
|
||||
$dryRun = (bool) $this->option('dry-run');
|
||||
|
||||
$filled = 0;
|
||||
$skipped = 0;
|
||||
$filesChanged = 0;
|
||||
|
||||
foreach ($this->apiDocFiles() as $file) {
|
||||
$content = file_get_contents($file);
|
||||
$result = $this->backfillFile($content, $describer, $filled, $skipped);
|
||||
|
||||
if ($result !== $content) {
|
||||
$filesChanged++;
|
||||
if (! $dryRun) {
|
||||
file_put_contents($file, $result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$prefix = $dryRun ? '[dry-run] ' : '';
|
||||
$this->info("{$prefix}응답 필드 설명 채움: {$filled}건, TODO 유지(도메인 특이): {$skipped}건, 변경 파일: {$filesChanged}개");
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 대상 API 문서 파일 경로를 수집합니다.
|
||||
*
|
||||
* @return array<int, string> 파일 경로 목록
|
||||
*/
|
||||
private function apiDocFiles(): array
|
||||
{
|
||||
$dirs = array_filter([
|
||||
base_path('docs/backend/api'),
|
||||
...glob(base_path('modules/_bundled/*/docs/api')),
|
||||
...glob(base_path('plugins/_bundled/*/docs/api')),
|
||||
], 'is_dir');
|
||||
|
||||
if ($dirs === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$files = [];
|
||||
foreach (Finder::create()->files()->in($dirs)->name('*.md') as $f) {
|
||||
$files[] = $f->getRealPath();
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* 단일 문서의 응답 필드 표 TODO 를 채웁니다.
|
||||
*
|
||||
* 응답 필드 표 헤더 이후 표 행만 대상으로 하며, `<!-- TODO: 설명 -->` 셀을
|
||||
* ResourceFieldDescriber 결과로 치환합니다. 설명이 null(도메인 특이)이면 유지합니다.
|
||||
* 파라미터 표는 헤더가 달라 진입하지 않으므로 건드리지 않습니다.
|
||||
*
|
||||
* @param string $content 문서 내용
|
||||
* @param ResourceFieldDescriber $describer 설명기
|
||||
* @param int $filled 채운 건수 (참조 누적)
|
||||
* @param int $skipped 유지 건수 (참조 누적)
|
||||
* @return string 치환된 문서 내용
|
||||
*/
|
||||
private function backfillFile(string $content, ResourceFieldDescriber $describer, int &$filled, int &$skipped): string
|
||||
{
|
||||
$lines = explode("\n", $content);
|
||||
$inFieldTable = false;
|
||||
|
||||
foreach ($lines as $i => $line) {
|
||||
// 응답 필드 표 헤더 진입 감지
|
||||
if (str_contains($line, self::FIELD_TABLE_HEADER)) {
|
||||
$inFieldTable = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// 표 구분선(| --- | ...) 은 건너뜀
|
||||
if ($inFieldTable && preg_match('/^\|\s*-+\s*\|/', $line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 표가 아닌 라인(빈 줄 또는 | 로 시작하지 않음) → 표 종료
|
||||
if ($inFieldTable && ! str_starts_with(ltrim($line), '|')) {
|
||||
$inFieldTable = false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $inFieldTable || ! str_contains($line, self::TODO_MARKER)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 응답 필드 행 파싱: | name | type | `sample` | <!-- TODO: 설명 --> |
|
||||
$cells = array_map('trim', explode('|', trim($line, '| ')));
|
||||
if (count($cells) < 4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
[$name, $type] = [$cells[0], $cells[1]];
|
||||
$desc = $describer->describe($name, $type);
|
||||
|
||||
if ($desc === null) {
|
||||
$skipped++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$safe = str_replace(['|', "\n", "\r"], ['\\|', ' ', ''], $desc);
|
||||
$lines[$i] = str_replace(self::TODO_MARKER, $safe, $line);
|
||||
$filled++;
|
||||
}
|
||||
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Support\ApiDoc\ParameterDescriber;
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
/**
|
||||
* 기존 API 문서의 파라미터 용도 TODO 를 공통 파라미터 설명으로 소급 채웁니다.
|
||||
*
|
||||
* 실측 서버 없이 재생성하면 이미 실측된 응답표·사람 서술이 퇴행하므로, 이 커맨드는
|
||||
* 재생성 대신 파라미터 표의 `<!-- TODO: 용도 -->` 셀만 in-place 치환합니다.
|
||||
* 채움 규칙 SSoT 는 ApiDocScaffolder 와 동일한 ParameterDescriber 입니다 —
|
||||
* 이후 정상 재생성(실측 서버 가동 시)도 같은 설명을 산출하므로 멱등합니다.
|
||||
*
|
||||
* 도메인 특이 파라미터(ParameterDescriber 가 null 반환)는 TODO 를 그대로 둡니다.
|
||||
*/
|
||||
class ApiDocBackfillParamsCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var string 커맨드 시그니처
|
||||
*/
|
||||
protected $signature = 'api:docgen-backfill-params
|
||||
{--dry-run : 치환하지 않고 채울 건수만 리포트}';
|
||||
|
||||
/**
|
||||
* @var string 커맨드 설명
|
||||
*/
|
||||
protected $description = '기존 API 문서의 파라미터 용도 TODO 를 공통 파라미터 설명으로 소급 채웁니다';
|
||||
|
||||
/**
|
||||
* @var string 파라미터 표를 식별하는 고유 헤더
|
||||
*/
|
||||
private const PARAM_TABLE_HEADER = '| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |';
|
||||
|
||||
/**
|
||||
* @var string 파라미터 용도 TODO 마커
|
||||
*/
|
||||
private const TODO_MARKER = '<!-- TODO: 용도 -->';
|
||||
|
||||
/**
|
||||
* 커맨드를 실행합니다.
|
||||
*
|
||||
* @return int 종료 코드
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$describer = new ParameterDescriber;
|
||||
$dryRun = (bool) $this->option('dry-run');
|
||||
|
||||
$filled = 0;
|
||||
$skipped = 0;
|
||||
$filesChanged = 0;
|
||||
|
||||
foreach ($this->apiDocFiles() as $file) {
|
||||
$content = file_get_contents($file);
|
||||
$result = $this->backfillFile($content, $describer, $filled, $skipped);
|
||||
|
||||
if ($result !== $content) {
|
||||
$filesChanged++;
|
||||
if (! $dryRun) {
|
||||
file_put_contents($file, $result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$prefix = $dryRun ? '[dry-run] ' : '';
|
||||
$this->info("{$prefix}파라미터 용도 채움: {$filled}건, TODO 유지(도메인 특이): {$skipped}건, 변경 파일: {$filesChanged}개");
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 대상 API 문서 파일 경로를 수집합니다.
|
||||
*
|
||||
* @return array<int, string> 파일 경로 목록
|
||||
*/
|
||||
private function apiDocFiles(): array
|
||||
{
|
||||
$dirs = array_filter([
|
||||
base_path('docs/backend/api'),
|
||||
...glob(base_path('modules/_bundled/*/docs/api')),
|
||||
...glob(base_path('plugins/_bundled/*/docs/api')),
|
||||
], 'is_dir');
|
||||
|
||||
if ($dirs === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$files = [];
|
||||
foreach (Finder::create()->files()->in($dirs)->name('*.md') as $f) {
|
||||
$files[] = $f->getRealPath();
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* 단일 문서의 파라미터 표 TODO 를 채웁니다.
|
||||
*
|
||||
* 파라미터 표 헤더 이후 표 행만 대상으로 하며, `<!-- TODO: 용도 -->` 셀을
|
||||
* ParameterDescriber 결과로 치환합니다. 설명이 null(도메인 특이)이면 유지합니다.
|
||||
*
|
||||
* @param string $content 문서 내용
|
||||
* @param ParameterDescriber $describer 설명기
|
||||
* @param int $filled 채운 건수 (참조 누적)
|
||||
* @param int $skipped 유지 건수 (참조 누적)
|
||||
* @return string 치환된 문서 내용
|
||||
*/
|
||||
private function backfillFile(string $content, ParameterDescriber $describer, int &$filled, int &$skipped): string
|
||||
{
|
||||
$lines = explode("\n", $content);
|
||||
$inParamTable = false;
|
||||
|
||||
foreach ($lines as $i => $line) {
|
||||
// 파라미터 표 헤더 진입 감지
|
||||
if (str_contains($line, self::PARAM_TABLE_HEADER)) {
|
||||
$inParamTable = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// 표 구분선(| --- | ...) 은 건너뜀
|
||||
if ($inParamTable && preg_match('/^\|\s*-+\s*\|/', $line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 표가 아닌 라인(빈 줄 또는 | 로 시작하지 않음) → 표 종료
|
||||
if ($inParamTable && ! str_starts_with(ltrim($line), '|')) {
|
||||
$inParamTable = false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $inParamTable || ! str_contains($line, self::TODO_MARKER)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 파라미터 행 파싱: | name | location | type | 필수 | 허용값 | <!-- TODO: 용도 --> |
|
||||
$cells = array_map('trim', explode('|', trim($line, '| ')));
|
||||
if (count($cells) < 5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
[$name, $location, $type] = [$cells[0], $cells[1], $cells[2]];
|
||||
$desc = $describer->describe($name, $location, $type);
|
||||
|
||||
if ($desc === null) {
|
||||
$skipped++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$safe = str_replace(['|', "\n", "\r"], ['\\|', ' ', ''], $desc);
|
||||
$lines[$i] = str_replace(self::TODO_MARKER, $safe, $line);
|
||||
$filled++;
|
||||
}
|
||||
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,544 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Contracts\ApiDoc\ApiDocSampleSeeder;
|
||||
use App\Models\Module;
|
||||
use App\Models\Plugin;
|
||||
use App\Models\Template;
|
||||
use App\Models\User;
|
||||
use App\Support\ApiDoc\ApiDocSampleService;
|
||||
use App\Support\ApiDoc\ApiDocScaffolder;
|
||||
use App\Support\ApiDoc\ApiEndpointProbe;
|
||||
use App\Support\ApiDoc\ApiRouteInventory;
|
||||
use App\Support\ApiDoc\ColumnCommentResolver;
|
||||
use App\Support\ApiDoc\FormRequestIntrospector;
|
||||
use App\Support\ApiDoc\ResponseSchemaInferrer;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* API 레퍼런스 문서 생성 커맨드
|
||||
*
|
||||
* 등록된 API 라우트를 전수 수집하고, GET 엔드포인트는 실제 HTTP 호출로 응답을
|
||||
* 실측하여 요청 파라미터·응답 필드를 담은 마크다운 레퍼런스 문서를 생성합니다.
|
||||
*
|
||||
* @generated 블록만 갱신하며 사람이 작성한 서술은 보존합니다.
|
||||
*/
|
||||
class ApiDocgenCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var string 커맨드 시그니처
|
||||
*/
|
||||
protected $signature = 'api:docgen
|
||||
{--scope=core : 범위 (core, module:vendor-id, plugin:vendor-id, all)}
|
||||
{--base-url= : 실측 기준 URL (미지정 시 .env APP_URL)}
|
||||
{--user= : 실측 토큰 발급 대상 사용자 ID}
|
||||
{--seed : 실측 전 완전 샘플 데이터를 시드 (개발 환경 전용)}
|
||||
{--check : 생성하지 않고 누락/미실측만 리포트}
|
||||
{--dry-run : 생성 대상만 출력}';
|
||||
|
||||
/**
|
||||
* @var string 커맨드 설명
|
||||
*/
|
||||
protected $description = 'API 레퍼런스 문서를 실측 기반으로 생성/갱신합니다';
|
||||
|
||||
/**
|
||||
* 커맨드를 실행합니다.
|
||||
*
|
||||
* @param ApiRouteInventory $inventory 라우트 인벤토리
|
||||
* @param FormRequestIntrospector $introspector FormRequest 분석기
|
||||
* @param ResponseSchemaInferrer $inferrer 응답 스키마 추론기
|
||||
* @param ApiDocScaffolder $scaffolder 스캐폴딩 생성기
|
||||
* @param ColumnCommentResolver $commentResolver 컬럼 주석 해석기
|
||||
* @return int 종료 코드
|
||||
*/
|
||||
public function handle(
|
||||
ApiRouteInventory $inventory,
|
||||
FormRequestIntrospector $introspector,
|
||||
ResponseSchemaInferrer $inferrer,
|
||||
ApiDocScaffolder $scaffolder,
|
||||
ColumnCommentResolver $commentResolver
|
||||
): int {
|
||||
$scope = (string) $this->option('scope');
|
||||
$routes = $inventory->collect($scope);
|
||||
|
||||
if ($routes === []) {
|
||||
$this->warn("범위 '{$scope}' 에 해당하는 API 라우트가 없습니다.");
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$this->info(count($routes)."개 라우트 수집 (scope={$scope})");
|
||||
|
||||
// 도메인 파일 단위로 그룹핑
|
||||
$grouped = [];
|
||||
foreach ($routes as $route) {
|
||||
$file = $this->targetFile($route);
|
||||
$grouped[$file][] = $route;
|
||||
}
|
||||
|
||||
if ($this->option('dry-run')) {
|
||||
foreach ($grouped as $file => $items) {
|
||||
$this->line(sprintf(' %s (%d endpoints)', $file, count($items)));
|
||||
}
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
// --seed: 도메인별 완전 샘플을 시드해 상세 GET 실측 시 null 응답을 최소화
|
||||
// (인증보다 먼저 수행해 완전 샘플 사용자로 토큰을 발급 → /me 응답도 채워짐)
|
||||
$sampleMap = [];
|
||||
if ($this->option('seed')) {
|
||||
if (app()->environment('production')) {
|
||||
$this->error('--seed 는 개발 환경 전용입니다 (production 차단).');
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
// 코어 샘플 우선 시드 — 확장 샘플의 소유자/actor 로 쓰이는 완전 사용자를 확보한다.
|
||||
$sampleMap = (new ApiDocSampleService)->seed();
|
||||
$this->info('완전 샘플 시드: '.count($sampleMap).'개 도메인 (코어)');
|
||||
|
||||
// 확장 소유 라우트가 있으면 그 확장의 규약 시더를 발견해 도메인 샘플을 병합한다.
|
||||
foreach ($this->discoverExtensionSeeders($routes) as $label => $seeder) {
|
||||
$extMap = $seeder->seed();
|
||||
$sampleMap = array_merge($sampleMap, $extMap);
|
||||
$this->info('완전 샘플 시드: '.count($extMap)."개 도메인 ({$label})");
|
||||
}
|
||||
}
|
||||
|
||||
$probe = new ApiEndpointProbe($this->option('base-url') ?: null);
|
||||
// 인증 사용자: --user 명시 > 완전 샘플 사용자(/me 응답 충실) > 첫 사용자
|
||||
$authUserId = $this->option('user')
|
||||
? (int) $this->option('user')
|
||||
: $this->sampleUserId($sampleMap);
|
||||
$probed = $probe->authenticate($authUserId);
|
||||
|
||||
if (! $probed) {
|
||||
$this->warn('실측 토큰 발급 실패 — 실측 없이 정적 추출만 진행합니다.');
|
||||
} else {
|
||||
$this->info('실측 기준 URL: '.$probe->baseUrl());
|
||||
}
|
||||
|
||||
$stats = ['files' => 0, 'endpoints' => 0, 'probed' => 0, 'skipped' => 0];
|
||||
$checkFindings = [];
|
||||
|
||||
foreach ($grouped as $file => $items) {
|
||||
$sections = [];
|
||||
$sectionKeys = [];
|
||||
|
||||
foreach ($items as $route) {
|
||||
$request = $introspector->introspect($route['controller'], $route['controller_method']);
|
||||
[$schema, $probeMeta] = $this->probeEndpoint($probe, $inferrer, $route, $probed, $sampleMap);
|
||||
|
||||
if ($probeMeta['skipped_reason'] === null) {
|
||||
$stats['probed']++;
|
||||
} else {
|
||||
$stats['skipped']++;
|
||||
$checkFindings[] = "{$route['method']} {$route['uri']} — {$probeMeta['skipped_reason']}";
|
||||
}
|
||||
|
||||
$commentMap = $this->columnComments($route, $commentResolver, $sampleMap);
|
||||
$sections[] = $scaffolder->endpointSection($route, $request, $schema, $probeMeta, $commentMap);
|
||||
$sectionKeys[] = $route['name'] ?: $route['uri'];
|
||||
$stats['endpoints']++;
|
||||
}
|
||||
|
||||
if ($this->option('check')) {
|
||||
if (! File::exists($file)) {
|
||||
$checkFindings[] = "문서 파일 없음: {$file}";
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$header = $this->documentHeader($file, $items[0]);
|
||||
$existing = File::exists($file) ? File::get($file) : null;
|
||||
$content = $scaffolder->mergeDocument($existing, $header, $sections, $sectionKeys);
|
||||
|
||||
File::ensureDirectoryExists(dirname($file));
|
||||
File::put($file, $content);
|
||||
$stats['files']++;
|
||||
}
|
||||
|
||||
$probe->cleanup();
|
||||
|
||||
if ($this->option('check')) {
|
||||
if ($checkFindings !== []) {
|
||||
$this->warn('실측 제외/문서 누락 '.count($checkFindings).'건:');
|
||||
foreach (array_slice($checkFindings, 0, 50) as $f) {
|
||||
$this->line(' - '.$f);
|
||||
}
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$this->info('drift 없음.');
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$this->newLine();
|
||||
$this->info(sprintf(
|
||||
'완료: 파일 %d개, 엔드포인트 %d개 (실측 %d, 제외 %d)',
|
||||
$stats['files'],
|
||||
$stats['endpoints'],
|
||||
$stats['probed'],
|
||||
$stats['skipped']
|
||||
));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 수집된 라우트의 소유 확장에서 규약 위치의 샘플 시더를 발견합니다.
|
||||
*
|
||||
* 확장 컨트롤러 FQCN(`Modules\Vendor\Ext\Http\Controllers\...`)에서 확장 베이스
|
||||
* 네임스페이스를 추출하고, `{Base}\Support\ApiDoc\ApiDocSampleService` 규약 클래스가
|
||||
* 존재하며 ApiDocSampleSeeder 를 구현하면 인스턴스를 반환합니다. 각 확장은 1회만 처리합니다.
|
||||
*
|
||||
* @param array<int, array<string, mixed>> $routes 수집된 라우트 목록
|
||||
* @return array<string, ApiDocSampleSeeder> 확장 라벨(key) => 시더 인스턴스
|
||||
*/
|
||||
private function discoverExtensionSeeders(array $routes): array
|
||||
{
|
||||
$seeders = [];
|
||||
$seen = [];
|
||||
|
||||
foreach ($routes as $route) {
|
||||
$owner = $route['owner'];
|
||||
|
||||
if ($owner['type'] === 'core' || $owner['id'] === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$label = $owner['key'];
|
||||
|
||||
if (isset($seen[$label])) {
|
||||
continue;
|
||||
}
|
||||
$seen[$label] = true;
|
||||
|
||||
$base = $this->extensionBaseNamespace($route['controller'] ?? null);
|
||||
|
||||
if ($base === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class = $base.'\\Support\\ApiDoc\\ApiDocSampleService';
|
||||
|
||||
if (class_exists($class) && is_subclass_of($class, ApiDocSampleSeeder::class)) {
|
||||
$seeders[$label] = app($class);
|
||||
}
|
||||
}
|
||||
|
||||
return $seeders;
|
||||
}
|
||||
|
||||
/**
|
||||
* 확장 컨트롤러 FQCN 에서 확장 베이스 네임스페이스를 추출합니다.
|
||||
*
|
||||
* 두 컨트롤러 배치 규약을 모두 지원한다:
|
||||
* - `\Http\Controllers\` (대다수 확장): `Modules\Sirsoft\Page\Http\Controllers\Admin\PageController`
|
||||
* → `Modules\Sirsoft\Page`
|
||||
* - `\Controllers\` (일부 플러그인): `Plugins\Sirsoft\PayKginicis\Controllers\PaymentSignatureController`
|
||||
* → `Plugins\Sirsoft\PayKginicis`
|
||||
*
|
||||
* `\Http\Controllers\` 를 우선 판정하고, 없으면 `\Controllers\` 세그먼트 앞까지를 베이스로 본다.
|
||||
*
|
||||
* @param string|null $controller 컨트롤러 FQCN (클로저면 null)
|
||||
* @return string|null 확장 베이스 네임스페이스 (추출 불가 시 null)
|
||||
*/
|
||||
private function extensionBaseNamespace(?string $controller): ?string
|
||||
{
|
||||
if ($controller === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Str::contains($controller, '\\Http\\Controllers\\')) {
|
||||
return Str::before($controller, '\\Http\\Controllers\\');
|
||||
}
|
||||
|
||||
if (Str::contains($controller, '\\Controllers\\')) {
|
||||
return Str::before($controller, '\\Controllers\\');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 엔드포인트를 실측하고 응답 스키마를 추론합니다.
|
||||
*
|
||||
* @param ApiEndpointProbe $probe 실측 프로브
|
||||
* @param ResponseSchemaInferrer $inferrer 스키마 추론기
|
||||
* @param array<string, mixed> $route 라우트 메타데이터
|
||||
* @param bool $probed 실측 가능 여부
|
||||
* @param array<string, array{model: class-string, key: string, value: string}> $sampleMap 도메인별 대표 샘플 맵
|
||||
* @return array{0: array<string, mixed>|null, 1: array<string, mixed>} 스키마와 실측 메타
|
||||
*/
|
||||
private function probeEndpoint(ApiEndpointProbe $probe, ResponseSchemaInferrer $inferrer, array $route, bool $probed, array $sampleMap = []): array
|
||||
{
|
||||
if (! $probed) {
|
||||
return [null, ['status' => null, 'skipped_reason' => 'no-token']];
|
||||
}
|
||||
|
||||
$uri = $this->resolvePathParams($route, $sampleMap);
|
||||
$result = $probe->probe($route['method'], $uri);
|
||||
|
||||
if (! $result['ok'] || $result['body'] === null) {
|
||||
return [null, ['status' => $result['status'], 'skipped_reason' => $result['skipped_reason'] ?? ('http-'.$result['status'])]];
|
||||
}
|
||||
|
||||
return [$inferrer->infer($result['body']), ['status' => $result['status'], 'skipped_reason' => null]];
|
||||
}
|
||||
|
||||
/**
|
||||
* URI 의 path 파라미터를 바인딩된 모델의 실제 레코드로 치환합니다.
|
||||
*
|
||||
* @param array<string, mixed> $route 라우트 메타데이터
|
||||
* @param array<string, array{model: class-string, key: string, value: string}> $sampleMap 도메인별 대표 샘플 맵
|
||||
* @return string 치환된 URI (치환 실패 시 원본 유지 → 프로브가 실측 제외)
|
||||
*/
|
||||
private function resolvePathParams(array $route, array $sampleMap = []): string
|
||||
{
|
||||
$uri = $route['uri'];
|
||||
$domain = $route['domain_group'] ?? null;
|
||||
|
||||
// path 파라미터가 있으면: 완전 샘플 대표 레코드 우선, 없으면 첫 레코드 키로 치환
|
||||
foreach ($route['path_params'] as $param) {
|
||||
$modelClass = $route['path_bindings'][$param] ?? null;
|
||||
|
||||
// 라우트-모델 바인딩이 없는 확장 패턴(예: show(int $id))은 도메인 샘플 맵의
|
||||
// 대표 모델로 폴백한다. 단, 파라미터명이 도메인의 단수 리소스명과 일치할 때만
|
||||
// (pages/{page} → Page). {slug}/{hash}/{versionId} 등 route key 가 다른
|
||||
// 문자열/보조 파라미터에는 폴백하지 않아 잘못된 치환(404)을 피한다.
|
||||
if (! $modelClass && $domain !== null && isset($sampleMap[$domain]) && $this->paramMatchesDomain($param, $domain)) {
|
||||
$modelClass = $sampleMap[$domain]['model'];
|
||||
}
|
||||
|
||||
if (! $modelClass) {
|
||||
// route-model binding 도 도메인 폴백도 없는 문자열 path 파라미터
|
||||
// (예: board 의 boards/{slug}/posts/{id}). 도메인 대표 샘플이 명시한
|
||||
// path_params 맵(param 명 => 실제 값)에 해당 param 이 있으면 그 값으로 치환한다.
|
||||
// slug 라우팅을 쓰는 확장이 route key(id) 와 무관한 slug/id 조합을
|
||||
// 실측할 수 있도록 하는 일반 경로다. (파라미터명 정확 일치만 허용 → 오치환 방지)
|
||||
$explicit = $domain !== null ? ($sampleMap[$domain]['path_params'][$param] ?? null) : null;
|
||||
|
||||
if ($explicit !== null) {
|
||||
$uri = str_replace('{'.$param.'}', (string) $explicit, $uri);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// 시드된 완전 샘플 중 같은 모델이 있으면 그 route key 를 우선 사용
|
||||
$value = $this->sampleKeyForModel($modelClass, $sampleMap) ?? $this->firstRouteKey($modelClass);
|
||||
|
||||
if ($value !== null) {
|
||||
$uri = str_replace('{'.$param.'}', (string) $value, $uri);
|
||||
}
|
||||
}
|
||||
|
||||
// 목록 GET 은 여러 행을 받아 필드별 non-null 대표 샘플을 확보한다
|
||||
// (per_page=1 이면 첫 행이 우연히 비어 "항상 null" 처럼 보임).
|
||||
if ($route['method'] === 'GET' && ! Str::contains($uri, '{')) {
|
||||
return $uri.(Str::contains($uri, '?') ? '&' : '?').'per_page=25';
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* path 파라미터명이 도메인의 단수 리소스명과 일치하는지 판정합니다.
|
||||
*
|
||||
* 도메인 그룹은 복수형(pages)이고 라우트 파라미터는 단수(page)이므로,
|
||||
* 파라미터명 == 도메인명 또는 파라미터명 == 도메인 단수형일 때만 매칭으로 본다.
|
||||
* (page ↔ pages). {slug}/{hash}/{versionId} 는 어느 쪽과도 일치하지 않는다.
|
||||
*
|
||||
* @param string $param path 파라미터명
|
||||
* @param string $domain 도메인 그룹명 (복수형 가능)
|
||||
* @return bool 도메인 리소스 파라미터 여부
|
||||
*/
|
||||
private function paramMatchesDomain(string $param, string $domain): bool
|
||||
{
|
||||
return $param === $domain
|
||||
|| $param === Str::singular($domain)
|
||||
|| Str::plural($param) === $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* 라우트의 주 모델 컬럼 주석 맵을 반환합니다 (응답 필드 설명 기본값).
|
||||
*
|
||||
* path 파라미터에 바인딩된 모델을 우선하고, 없으면 도메인 샘플 맵의 대표
|
||||
* 모델을 주 모델로 보고 그 테이블 주석을 사용합니다.
|
||||
*
|
||||
* @param array<string, mixed> $route 라우트 메타데이터
|
||||
* @param ColumnCommentResolver $resolver 컬럼 주석 해석기
|
||||
* @param array<string, array{model: class-string, key: string, value: string}> $sampleMap 도메인별 대표 샘플 맵
|
||||
* @return array<string, string> 컬럼명 => 주석
|
||||
*/
|
||||
private function columnComments(array $route, ColumnCommentResolver $resolver, array $sampleMap = []): array
|
||||
{
|
||||
$bindings = $route['path_bindings'] ?? [];
|
||||
|
||||
// 마지막 path 바인딩 모델(가장 구체적인 리소스)을 주 모델로 사용
|
||||
$modelClass = null;
|
||||
foreach ($bindings as $class) {
|
||||
$modelClass = $class;
|
||||
}
|
||||
|
||||
// path 바인딩이 없으면(목록/단건 me 등) 도메인 샘플 맵 → 정적 힌트 순으로 유추
|
||||
if (! $modelClass) {
|
||||
$domain = $route['domain_group'] ?? null;
|
||||
$modelClass = ($domain && isset($sampleMap[$domain]) ? $sampleMap[$domain]['model'] : null)
|
||||
?? $this->domainModelHint($domain);
|
||||
}
|
||||
|
||||
return $modelClass ? $resolver->forModel($modelClass) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 샘플 맵으로 유추되지 않는 도메인의 주 모델을 정적 힌트로 매핑합니다.
|
||||
*
|
||||
* me/auth/profile/password 등은 path 바인딩도 없고 sampleMap 키(users)와도
|
||||
* 도메인명이 달라 자동 유추가 안 되지만, 모두 User 필드를 반환합니다.
|
||||
*
|
||||
* @param string|null $domain 도메인 그룹명
|
||||
* @return class-string|null 주 모델 FQCN (없으면 null)
|
||||
*/
|
||||
private function domainModelHint(?string $domain): ?string
|
||||
{
|
||||
if ($domain === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$hints = [
|
||||
'me' => User::class,
|
||||
'auth' => User::class,
|
||||
'profile' => User::class,
|
||||
'password' => User::class,
|
||||
'modules' => Module::class,
|
||||
'plugins' => Plugin::class,
|
||||
'templates' => Template::class,
|
||||
];
|
||||
|
||||
return $hints[$domain] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전 샘플 맵에서 샘플 사용자의 DB id 를 조회합니다 (토큰 발급 대상).
|
||||
*
|
||||
* @param array<string, array{model: class-string, key: string, value: string}> $sampleMap 대표 샘플 맵
|
||||
* @return int|null 샘플 사용자 id (없으면 null → 첫 사용자로 fallback)
|
||||
*/
|
||||
private function sampleUserId(array $sampleMap): ?int
|
||||
{
|
||||
$users = $sampleMap['users'] ?? null;
|
||||
|
||||
if (! $users) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return User::query()
|
||||
->where($users['key'], $users['value'])
|
||||
->value('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 시드된 완전 샘플 맵에서 해당 모델의 대표 route key 를 찾습니다.
|
||||
*
|
||||
* @param class-string $modelClass 모델 FQCN
|
||||
* @param array<string, array{model: class-string, key: string, value: string}> $sampleMap 대표 샘플 맵
|
||||
* @return string|null 대표 route key 값 (없으면 null)
|
||||
*/
|
||||
private function sampleKeyForModel(string $modelClass, array $sampleMap): ?string
|
||||
{
|
||||
foreach ($sampleMap as $sample) {
|
||||
if ($sample['model'] === $modelClass) {
|
||||
return $sample['value'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 모델의 첫 레코드 route key 값을 반환합니다.
|
||||
*
|
||||
* @param class-string $modelClass 모델 FQCN
|
||||
* @return mixed route key 값 (레코드 없으면 null)
|
||||
*/
|
||||
private function firstRouteKey(string $modelClass): mixed
|
||||
{
|
||||
try {
|
||||
/** @var Model $model */
|
||||
$model = new $modelClass;
|
||||
$keyName = $model->getRouteKeyName();
|
||||
|
||||
$record = $modelClass::query()->orderBy($model->getKeyName())->first();
|
||||
|
||||
return $record?->getAttribute($keyName);
|
||||
} catch (\Throwable) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 라우트가 저장될 문서 파일 경로를 산출합니다.
|
||||
*
|
||||
* @param array<string, mixed> $route 라우트 메타데이터
|
||||
* @return string 절대 파일 경로
|
||||
*/
|
||||
private function targetFile(array $route): string
|
||||
{
|
||||
$owner = $route['owner'];
|
||||
$domain = $route['domain_group'];
|
||||
|
||||
if ($owner['type'] === 'core') {
|
||||
return base_path("docs/backend/api/{$domain}.md");
|
||||
}
|
||||
|
||||
$base = $owner['type'] === 'module' ? 'modules' : 'plugins';
|
||||
|
||||
return base_path("{$base}/_bundled/{$owner['id']}/docs/api/{$domain}.md");
|
||||
}
|
||||
|
||||
/**
|
||||
* 문서 헤더(제목 + TL;DR)를 생성합니다.
|
||||
*
|
||||
* @param string $file 문서 파일 경로
|
||||
* @param array<string, mixed> $firstRoute 대표 라우트
|
||||
* @return string 문서 헤더
|
||||
*/
|
||||
private function documentHeader(string $file, array $firstRoute): string
|
||||
{
|
||||
$domain = Str::headline(pathinfo($file, PATHINFO_FILENAME));
|
||||
$owner = $firstRoute['owner'];
|
||||
$ownerLabel = $owner['type'] === 'core' ? '코어' : "{$owner['type']} `{$owner['id']}`";
|
||||
|
||||
return <<<MD
|
||||
# {$domain} API 레퍼런스
|
||||
|
||||
> **소유**: {$ownerLabel} · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 {$domain} 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
MD;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts\ApiDoc;
|
||||
|
||||
/**
|
||||
* API 문서 실측용 완전 샘플 시더 계약
|
||||
*
|
||||
* 확장(모듈/플러그인)이 자신의 API 도메인 대표 엔티티에 완전한 샘플 레코드를
|
||||
* 멱등하게 생성하고, docgen 이 상세 GET 실측(path 파라미터 치환)에 사용할
|
||||
* 도메인별 대표 route key 맵을 제공하기 위한 인터페이스입니다.
|
||||
*
|
||||
* 확장은 이 인터페이스를 구현한 클래스를 `{Namespace}\Support\ApiDoc\ApiDocSampleService`
|
||||
* 규약 위치에 두며, `api:docgen --scope=module:{id}` 실행 시 커맨드가 자동으로 발견합니다.
|
||||
* 코어의 `App\Support\ApiDoc\ApiDocSampleService` 도 동일 계약을 구현합니다.
|
||||
*/
|
||||
interface ApiDocSampleSeeder
|
||||
{
|
||||
/**
|
||||
* 도메인별 완전 샘플을 멱등 생성하고 대표 route key 맵을 반환합니다.
|
||||
*
|
||||
* 반환 맵의 키는 라우트 도메인 그룹명(`domain_group`, 예: pages)이며,
|
||||
* 값은 그 도메인의 상세 GET path 파라미터를 실측 가능한 실제 레코드로
|
||||
* 치환하기 위한 모델 FQCN·route key 이름·route key 값입니다.
|
||||
*
|
||||
* 선택 필드 `path_params`(param 명 => 실제 값 맵)를 두면, route-model binding
|
||||
* 도 도메인 폴백도 없는 문자열 path 파라미터(예: 게시판 slug 라우팅
|
||||
* `boards/{slug}/posts/{id}`)를 param 명 정확 일치로 치환해 상세 GET 을
|
||||
* 실측할 수 있습니다. 미제공 시 route key 기반 자동 치환만 적용됩니다.
|
||||
*
|
||||
* @return array<string, array{model: class-string, key: string, value: string, path_params?: array<string, string>}> 도메인 => 대표 레코드 정보
|
||||
*/
|
||||
public function seed(): array;
|
||||
}
|
||||
@@ -0,0 +1,374 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support\ApiDoc;
|
||||
|
||||
use App\Contracts\ApiDoc\ApiDocSampleSeeder;
|
||||
use App\Models\ActivityLog;
|
||||
use App\Models\LanguagePack;
|
||||
use App\Models\Menu;
|
||||
use App\Models\NotificationDefinition;
|
||||
use App\Models\NotificationLog;
|
||||
use App\Models\NotificationTemplate;
|
||||
use App\Models\Permission;
|
||||
use App\Models\Role;
|
||||
use App\Models\Schedule;
|
||||
use App\Models\User;
|
||||
|
||||
/**
|
||||
* API 문서 실측용 완전 샘플 데이터 서비스
|
||||
*
|
||||
* 각 API 도메인의 대표 엔티티에 모든 필드가 채워진 완전한 샘플 레코드를
|
||||
* 멱등하게 생성하고, docgen 이 상세 GET 실측에 사용할 도메인별 대표 route key
|
||||
* 맵을 제공합니다. 개발 환경 전용 — 생성된 샘플은 개발 DB 에 남습니다.
|
||||
*/
|
||||
class ApiDocSampleService implements ApiDocSampleSeeder
|
||||
{
|
||||
/**
|
||||
* @var string 샘플 레코드 식별용 마커 (이메일/식별자 prefix)
|
||||
*/
|
||||
private const MARKER = 'apidoc-sample';
|
||||
|
||||
/**
|
||||
* 도메인별 완전 샘플을 멱등 생성하고 대표 route key 맵을 반환합니다.
|
||||
*
|
||||
* @return array<string, array{model: class-string, key: string, value: string}> 도메인 => 대표 레코드 정보
|
||||
*/
|
||||
public function seed(): array
|
||||
{
|
||||
$map = [];
|
||||
|
||||
// permissions → roles → users 순: user 가 role 을, role 이 permission 을 참조
|
||||
$map['permissions'] = $this->seedPermission();
|
||||
$map['roles'] = $this->seedRole();
|
||||
$map['users'] = $this->seedUser();
|
||||
$map['menus'] = $this->seedMenu();
|
||||
$map['notification-definitions'] = $this->seedNotificationDefinition();
|
||||
$map['schedules'] = $this->seedSchedule();
|
||||
$map['activity-logs'] = $this->seedActivityLog();
|
||||
$map['language-packs'] = $this->seedLanguagePack();
|
||||
$map['notification-logs'] = $this->seedNotificationLog();
|
||||
$map['notification-templates'] = $this->seedNotificationTemplate();
|
||||
|
||||
return array_filter($map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전한 사용자 샘플을 생성하고 roles 관계를 연결합니다.
|
||||
*
|
||||
* @return array{model: class-string, key: string, value: string} 대표 레코드 정보
|
||||
*/
|
||||
private function seedUser(): array
|
||||
{
|
||||
$user = User::query()->where('email', self::MARKER.'-user@example.com')->first();
|
||||
|
||||
if (! $user) {
|
||||
$user = User::factory()->complete()->create([
|
||||
'name' => 'API 문서 샘플 사용자',
|
||||
'email' => self::MARKER.'-user@example.com',
|
||||
]);
|
||||
|
||||
$role = Role::query()->where('identifier', self::MARKER.'-role')->first()
|
||||
?? Role::query()->where('identifier', 'admin')->first()
|
||||
?? Role::query()->first()
|
||||
?? Role::factory()->create(['identifier' => self::MARKER.'-role-fallback']);
|
||||
$user->roles()->syncWithoutDetaching([$role->id]);
|
||||
}
|
||||
|
||||
return ['model' => User::class, 'key' => $user->getRouteKeyName(), 'value' => (string) $user->getRouteKey()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전한 역할 샘플을 생성하고 permissions 관계를 연결합니다.
|
||||
*
|
||||
* @return array{model: class-string, key: string, value: string} 대표 레코드 정보
|
||||
*/
|
||||
private function seedRole(): array
|
||||
{
|
||||
$role = Role::query()->where('identifier', self::MARKER.'-role')->first();
|
||||
|
||||
if (! $role) {
|
||||
$role = Role::factory()->create([
|
||||
'identifier' => self::MARKER.'-role',
|
||||
'name' => ['ko' => 'API 문서 샘플 역할', 'en' => 'API Doc Sample Role'],
|
||||
'description' => ['ko' => '문서 실측용 역할', 'en' => 'Sample role for API docs'],
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
$permissionIds = Permission::query()->limit(3)->pluck('id')->all();
|
||||
if ($permissionIds !== []) {
|
||||
$role->permissions()->syncWithoutDetaching($permissionIds);
|
||||
}
|
||||
}
|
||||
|
||||
return ['model' => Role::class, 'key' => $role->getRouteKeyName(), 'value' => (string) $role->getRouteKey()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전한 권한 샘플(부모-자식 계층)을 생성합니다.
|
||||
*
|
||||
* @return array{model: class-string, key: string, value: string} 대표 레코드 정보
|
||||
*/
|
||||
private function seedPermission(): array
|
||||
{
|
||||
$permission = Permission::query()->where('identifier', self::MARKER.'.parent')->first();
|
||||
|
||||
if (! $permission) {
|
||||
$permission = Permission::factory()->create([
|
||||
'identifier' => self::MARKER.'.parent',
|
||||
'name' => ['ko' => 'API 문서 샘플 권한', 'en' => 'API Doc Sample Permission'],
|
||||
'description' => ['ko' => '문서 실측용 권한', 'en' => 'Sample permission'],
|
||||
'type' => 'admin',
|
||||
]);
|
||||
|
||||
Permission::factory()->create([
|
||||
'parent_id' => $permission->id,
|
||||
'identifier' => self::MARKER.'.child',
|
||||
'name' => ['ko' => '하위 권한', 'en' => 'Child Permission'],
|
||||
'type' => 'admin',
|
||||
]);
|
||||
}
|
||||
|
||||
return ['model' => Permission::class, 'key' => $permission->getRouteKeyName(), 'value' => (string) $permission->getRouteKey()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전한 메뉴 샘플(부모-자식)을 생성합니다.
|
||||
*
|
||||
* @return array{model: class-string, key: string, value: string} 대표 레코드 정보
|
||||
*/
|
||||
private function seedMenu(): array
|
||||
{
|
||||
$menu = Menu::query()->where('slug', self::MARKER.'-menu')->first();
|
||||
|
||||
if (! $menu) {
|
||||
$creator = User::query()->where('email', self::MARKER.'-user@example.com')->first();
|
||||
|
||||
$menu = Menu::factory()->create([
|
||||
'name' => ['ko' => 'API 문서 샘플 메뉴', 'en' => 'API Doc Sample Menu'],
|
||||
'slug' => self::MARKER.'-menu',
|
||||
'url' => '/admin/apidoc-sample',
|
||||
'icon' => 'fas fa-book',
|
||||
'is_active' => true,
|
||||
'created_by' => $creator?->id,
|
||||
]);
|
||||
|
||||
Menu::factory()->create([
|
||||
'name' => ['ko' => '하위 메뉴', 'en' => 'Child Menu'],
|
||||
'slug' => self::MARKER.'-menu-child',
|
||||
'parent_id' => $menu->id,
|
||||
'created_by' => $creator?->id,
|
||||
]);
|
||||
}
|
||||
|
||||
return ['model' => Menu::class, 'key' => $menu->getRouteKeyName(), 'value' => (string) $menu->getRouteKey()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전한 알림 정의 샘플(템플릿 포함)을 생성합니다.
|
||||
*
|
||||
* @return array{model: class-string, key: string, value: string} 대표 레코드 정보
|
||||
*/
|
||||
private function seedNotificationDefinition(): array
|
||||
{
|
||||
$definition = NotificationDefinition::query()->where('type', self::MARKER.'.event')->first();
|
||||
|
||||
if (! $definition) {
|
||||
$definition = NotificationDefinition::factory()->create([
|
||||
'type' => self::MARKER.'.event',
|
||||
'name' => ['ko' => 'API 문서 샘플 알림', 'en' => 'API Doc Sample Notification'],
|
||||
'description' => ['ko' => '문서 실측용 알림 정의', 'en' => 'Sample notification'],
|
||||
'channels' => ['database', 'mail'],
|
||||
'is_active' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
return ['model' => NotificationDefinition::class, 'key' => $definition->getRouteKeyName(), 'value' => (string) $definition->getRouteKey()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전한 스케줄 샘플(실행 이력 포함)을 생성합니다.
|
||||
*
|
||||
* @return array{model: class-string, key: string, value: string} 대표 레코드 정보
|
||||
*/
|
||||
private function seedSchedule(): array
|
||||
{
|
||||
$schedule = Schedule::query()->where('name', 'API 문서 샘플 스케줄')->first();
|
||||
|
||||
if (! $schedule) {
|
||||
$creator = $this->sampleUser();
|
||||
|
||||
$schedule = Schedule::create([
|
||||
'name' => 'API 문서 샘플 스케줄',
|
||||
'description' => '문서 실측용 스케줄',
|
||||
'type' => 'artisan',
|
||||
'command' => 'cache:clear',
|
||||
'expression' => '0 3 * * *',
|
||||
'frequency' => 'daily',
|
||||
'without_overlapping' => true,
|
||||
'run_in_maintenance' => false,
|
||||
'timeout' => 300,
|
||||
'is_active' => true,
|
||||
'last_result' => 'success',
|
||||
'last_run_at' => now()->subDay(),
|
||||
'next_run_at' => now()->addDay(),
|
||||
'created_by' => $creator?->id,
|
||||
]);
|
||||
}
|
||||
|
||||
return ['model' => Schedule::class, 'key' => $schedule->getRouteKeyName(), 'value' => (string) $schedule->getRouteKey()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전한 활동 로그 샘플(actor + changes 포함)을 생성합니다.
|
||||
*
|
||||
* @return array{model: class-string, key: string, value: string} 대표 레코드 정보
|
||||
*/
|
||||
private function seedActivityLog(): array
|
||||
{
|
||||
$log = ActivityLog::query()->where('description_key', 'apidoc.sample.action')->first();
|
||||
|
||||
if (! $log) {
|
||||
$user = $this->sampleUser();
|
||||
|
||||
$log = ActivityLog::create([
|
||||
'log_type' => 'admin',
|
||||
'loggable_type' => User::class,
|
||||
'loggable_id' => $user?->id,
|
||||
'user_id' => $user?->id,
|
||||
'action' => 'user.update',
|
||||
'description_key' => 'apidoc.sample.action',
|
||||
'description_params' => ['name' => 'API 문서 샘플'],
|
||||
'properties' => ['source' => 'apidoc'],
|
||||
'changes' => ['status' => ['old' => 'inactive', 'new' => 'active']],
|
||||
'ip_address' => '127.0.0.1',
|
||||
'user_agent' => 'ApiDocgen/1.0',
|
||||
'created_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
return ['model' => ActivityLog::class, 'key' => $log->getRouteKeyName(), 'value' => (string) $log->getRouteKey()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전한 언어팩 샘플(manifest 채움)을 생성합니다.
|
||||
*
|
||||
* @return array{model: class-string, key: string, value: string} 대표 레코드 정보
|
||||
*/
|
||||
private function seedLanguagePack(): array
|
||||
{
|
||||
$pack = LanguagePack::query()->where('identifier', 'apidoc-sample-lang')->first();
|
||||
|
||||
if (! $pack) {
|
||||
$installer = $this->sampleUser();
|
||||
|
||||
$pack = LanguagePack::create([
|
||||
'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',
|
||||
'license' => 'MIT',
|
||||
'description' => ['ko' => '문서 실측용 언어팩', 'en' => 'Sample language pack'],
|
||||
'status' => 'active',
|
||||
'is_protected' => false,
|
||||
'manifest' => [
|
||||
'name' => ['ko' => 'API 문서 샘플 언어팩', 'en' => 'API Doc Sample Pack'],
|
||||
'version' => '1.0.0',
|
||||
'locale' => 'fr',
|
||||
],
|
||||
'source_type' => 'bundled',
|
||||
'installed_by' => $installer?->id,
|
||||
'installed_at' => now()->subDays(3),
|
||||
'activated_at' => now()->subDays(3),
|
||||
]);
|
||||
}
|
||||
|
||||
return ['model' => LanguagePack::class, 'key' => $pack->getRouteKeyName(), 'value' => (string) $pack->getRouteKey()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전한 알림 로그 샘플(수신자/발신자 포함)을 생성합니다.
|
||||
*
|
||||
* @return array{model: class-string, key: string, value: string} 대표 레코드 정보
|
||||
*/
|
||||
private function seedNotificationLog(): array
|
||||
{
|
||||
$log = NotificationLog::query()->where('notification_type', 'apidoc.sample.event')->first();
|
||||
|
||||
if (! $log) {
|
||||
$user = $this->sampleUser();
|
||||
|
||||
$log = NotificationLog::create([
|
||||
'channel' => 'mail',
|
||||
'notification_type' => 'apidoc.sample.event',
|
||||
'extension_type' => 'core',
|
||||
'extension_identifier' => '',
|
||||
'recipient_user_id' => $user?->id,
|
||||
'recipient_identifier' => $user?->email,
|
||||
'recipient_name' => $user?->name,
|
||||
'sender_user_id' => $user?->id,
|
||||
'subject' => 'API 문서 샘플 알림',
|
||||
'body' => '문서 실측용 알림 본문입니다.',
|
||||
'status' => 'sent',
|
||||
'error_message' => null,
|
||||
'source' => 'apidoc',
|
||||
'sent_at' => now()->subHour(),
|
||||
]);
|
||||
}
|
||||
|
||||
return ['model' => NotificationLog::class, 'key' => $log->getRouteKeyName(), 'value' => (string) $log->getRouteKey()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전한 알림 템플릿 샘플(정의 연결)을 생성합니다.
|
||||
*
|
||||
* @return array{model: class-string, key: string, value: string} 대표 레코드 정보
|
||||
*/
|
||||
private function seedNotificationTemplate(): array
|
||||
{
|
||||
$this->seedNotificationDefinition();
|
||||
$definitionId = NotificationDefinition::query()->where('type', self::MARKER.'.event')->value('id');
|
||||
|
||||
$template = NotificationTemplate::query()
|
||||
->where('definition_id', $definitionId)
|
||||
->where('channel', 'mail')
|
||||
->first();
|
||||
|
||||
if (! $template && $definitionId) {
|
||||
$updater = $this->sampleUser();
|
||||
|
||||
$template = NotificationTemplate::create([
|
||||
'definition_id' => $definitionId,
|
||||
'channel' => 'mail',
|
||||
'subject' => 'API 문서 샘플 템플릿 제목',
|
||||
'body' => '안녕하세요 {{name}} 님, 문서 실측용 본문입니다.',
|
||||
'click_url' => '/admin/apidoc-sample',
|
||||
'recipients' => [['type' => 'role', 'value' => 'admin']],
|
||||
'is_active' => true,
|
||||
'is_default' => false,
|
||||
'updated_by' => $updater?->id,
|
||||
]);
|
||||
}
|
||||
|
||||
if (! $template) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return ['model' => NotificationTemplate::class, 'key' => $template->getRouteKeyName(), 'value' => (string) $template->getRouteKey()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 시드된 완전 샘플 사용자를 반환합니다 (연관 엔티티의 소유자/actor 용).
|
||||
*
|
||||
* @return User|null 샘플 사용자 (없으면 null)
|
||||
*/
|
||||
private function sampleUser(): ?User
|
||||
{
|
||||
return User::query()->where('email', self::MARKER.'-user@example.com')->first();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support\ApiDoc;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* API 문서 스캐폴딩 생성기
|
||||
*
|
||||
* 라우트 메타데이터 + 요청 파라미터 + 실측 응답 스키마를 표준 마크다운 포맷으로
|
||||
* 조립합니다. @generated 블록 경계로 기존 문서의 사람 서술을 보존(idempotent)합니다.
|
||||
*/
|
||||
class ApiDocScaffolder
|
||||
{
|
||||
/**
|
||||
* @var string 생성 블록 시작 마커 접두
|
||||
*/
|
||||
private const GEN_START = '<!-- @generated:start:';
|
||||
|
||||
/**
|
||||
* @var string 생성 블록 종료 마커
|
||||
*/
|
||||
private const GEN_END = '<!-- @generated:end -->';
|
||||
|
||||
/**
|
||||
* @param ResourceFieldDescriber $fieldDescriber accessor/computed 필드 설명기
|
||||
* @param ParameterDescriber $paramDescriber 공통 요청 파라미터 설명기
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ResourceFieldDescriber $fieldDescriber = new ResourceFieldDescriber,
|
||||
private readonly ParameterDescriber $paramDescriber = new ParameterDescriber
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 단일 엔드포인트의 마크다운 섹션을 생성합니다.
|
||||
*
|
||||
* @param array<string, mixed> $route 라우트 메타데이터
|
||||
* @param array<string, mixed> $request FormRequest 분석 결과
|
||||
* @param array<string, mixed>|null $schema 실측 응답 스키마 (null=실측 안 됨)
|
||||
* @param array<string, mixed> $probeMeta 실측 메타 (status, skipped_reason)
|
||||
* @param array<string, string> $commentMap 컬럼명 => 주석 (필드 설명 기본값)
|
||||
* @return string 마크다운 섹션
|
||||
*/
|
||||
public function endpointSection(array $route, array $request, ?array $schema, array $probeMeta, array $commentMap = []): string
|
||||
{
|
||||
$name = $route['name'] ?: '(unnamed)';
|
||||
$heading = "### {$route['method']} {$route['uri']}";
|
||||
$genKey = $name;
|
||||
|
||||
$lines = [];
|
||||
$lines[] = $heading;
|
||||
$lines[] = self::GEN_START.$genKey.' -->';
|
||||
$lines[] = "- **라우트명**: `{$name}`";
|
||||
if ($route['controller']) {
|
||||
$lines[] = "- **컨트롤러**: `{$route['controller']}@{$route['controller_method']}`";
|
||||
}
|
||||
$lines[] = '- **인증/권한**: '.$this->authLine($route);
|
||||
$lines[] = '';
|
||||
|
||||
$lines[] = '**요청 파라미터**';
|
||||
$lines[] = '';
|
||||
$lines[] = $this->requestParamTable($route, $request);
|
||||
if (! empty($request['hook_filters'])) {
|
||||
$hooks = implode('`, `', $request['hook_filters']);
|
||||
$lines[] = '';
|
||||
$lines[] = "> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`{$hooks}`).";
|
||||
}
|
||||
$lines[] = '';
|
||||
|
||||
$lines[] = '**응답 필드** (`data` 내부)';
|
||||
$lines[] = '';
|
||||
$lines[] = $this->responseFieldTable($schema, $probeMeta, $commentMap);
|
||||
$lines[] = '';
|
||||
|
||||
$lines[] = '**에러 응답**';
|
||||
$lines[] = '';
|
||||
$lines[] = $this->errorTable($route, $request);
|
||||
$lines[] = '';
|
||||
$lines[] = self::GEN_END;
|
||||
$lines[] = '';
|
||||
$lines[] = '**설명** <!-- TODO: 이 엔드포인트의 용도·주의사항·예시 시나리오를 작성하세요 -->';
|
||||
$lines[] = '';
|
||||
|
||||
return implode("\n", $lines)."\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* 인증/권한 라인을 구성합니다.
|
||||
*
|
||||
* @param array<string, mixed> $route 라우트 메타데이터
|
||||
* @return string 인증/권한 설명
|
||||
*/
|
||||
private function authLine(array $route): string
|
||||
{
|
||||
$mw = $route['middleware'] ?? [];
|
||||
$parts = [];
|
||||
|
||||
// optional.sanctum(회원/비회원 모두 접근 — Bearer 토큰 있으면 인증, 없으면 guest)은
|
||||
// auth:sanctum(인증 필수)과 계약이 다르므로 별도 표기한다. 'sanctum' 부분일치가
|
||||
// optional.sanctum 까지 auth:sanctum 으로 오표기하던 회귀를 막는다.
|
||||
if ($this->hasMiddleware($mw, 'optional.sanctum')) {
|
||||
$parts[] = '`optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)';
|
||||
} elseif ($this->hasMiddleware($mw, 'sanctum')) {
|
||||
$parts[] = '`auth:sanctum`';
|
||||
}
|
||||
if ($this->hasMiddleware($mw, 'AdminMiddleware')) {
|
||||
$parts[] = '`admin`';
|
||||
}
|
||||
if ($route['permission']) {
|
||||
$parts[] = "`permission:{$route['permission']}`";
|
||||
}
|
||||
|
||||
return $parts === [] ? '공개 (인증 불필요)' : implode(' + ', $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* 미들웨어 목록에 특정 토큰이 포함되는지 확인합니다.
|
||||
*
|
||||
* @param array<int, string> $middleware 미들웨어 목록
|
||||
* @param string $needle 검색 토큰
|
||||
* @return bool 포함 여부
|
||||
*/
|
||||
private function hasMiddleware(array $middleware, string $needle): bool
|
||||
{
|
||||
foreach ($middleware as $mw) {
|
||||
if (Str::contains($mw, $needle)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 요청 파라미터 표를 생성합니다.
|
||||
*
|
||||
* @param array<string, mixed> $route 라우트 메타데이터
|
||||
* @param array<string, mixed> $request FormRequest 분석 결과
|
||||
* @return string 마크다운 표
|
||||
*/
|
||||
private function requestParamTable(array $route, array $request): string
|
||||
{
|
||||
$rows = [];
|
||||
|
||||
foreach ($route['path_params'] as $pathParam) {
|
||||
$desc = $this->paramDescriber->describe($pathParam, 'path', 'string');
|
||||
$descCell = $desc !== null ? $this->escapeCell($desc) : '<!-- TODO: 용도 -->';
|
||||
$rows[] = "| {$pathParam} | path | string | 예 | — | {$descCell} |";
|
||||
}
|
||||
|
||||
$location = in_array($route['method'], ['GET', 'DELETE'], true) ? 'query' : 'body';
|
||||
|
||||
foreach ($request['params'] as $p) {
|
||||
$required = $p['required'] ? '예' : '아니오';
|
||||
$allowed = $p['allowed'] !== '' ? $p['allowed'] : '—';
|
||||
$desc = $this->paramDescriber->describe($p['name'], $location, $p['type']);
|
||||
$descCell = $desc !== null ? $this->escapeCell($desc) : '<!-- TODO: 용도 -->';
|
||||
$rows[] = "| {$p['name']} | {$location} | {$p['type']} | {$required} | {$allowed} | {$descCell} |";
|
||||
}
|
||||
|
||||
if ($rows === []) {
|
||||
return '_요청 파라미터 없음._';
|
||||
}
|
||||
|
||||
return "| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |\n| --- | --- | --- | --- | --- | --- |\n".implode("\n", $rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* 응답 필드 표를 생성합니다.
|
||||
*
|
||||
* @param array<string, mixed>|null $schema 실측 응답 스키마
|
||||
* @param array<string, mixed> $probeMeta 실측 메타
|
||||
* @param array<string, string> $commentMap 컬럼명 => 주석 (필드 설명 기본값)
|
||||
* @return string 마크다운 표 또는 실측 제외 사유
|
||||
*/
|
||||
private function responseFieldTable(?array $schema, array $probeMeta, array $commentMap = []): string
|
||||
{
|
||||
if ($schema === null) {
|
||||
$reason = $probeMeta['skipped_reason'] ?? 'not-probed';
|
||||
|
||||
return "<!-- 실측 제외: {$reason} — 응답 필드는 사람이 작성하세요. -->";
|
||||
}
|
||||
|
||||
$note = '';
|
||||
if ($schema['shape'] === 'collection') {
|
||||
$note = '_목록 응답: `data.data[]` 배열 항목의 필드'.($schema['pagination'] ? ' + `data.pagination`' : '').'._';
|
||||
} elseif ($schema['shape'] === 'object') {
|
||||
$note = '_단건 응답: `data` 객체의 필드._';
|
||||
}
|
||||
|
||||
if ($schema['fields'] === []) {
|
||||
return $note."\n\n<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->";
|
||||
}
|
||||
|
||||
$rows = [];
|
||||
foreach ($schema['fields'] as $f) {
|
||||
// 필드 설명 우선순위:
|
||||
// 1) 리소스 계약 사전 (accessor/computed — status_label, is_owner, *_at 등)
|
||||
// 2) 컬럼 주석 (한국어 comment — 테이블 실제 컬럼)
|
||||
// 3) TODO (사람 보강)
|
||||
// 계약 사전이 앞서는 이유: created_at 은 어느 테이블이든 "생성 일시" 이고,
|
||||
// status_label 은 컬럼이 아니라 Enum label() 산물이라 주석이 없기 때문.
|
||||
$desc = $this->fieldDescriber->describe($f['name'], $f['type'] ?? '')
|
||||
?? ($commentMap[$f['name']] ?? null);
|
||||
$descCell = $desc !== null ? $this->escapeCell($desc) : '<!-- TODO: 설명 -->';
|
||||
$rows[] = "| {$f['name']} | {$f['type']} | `{$f['sample']}` | {$descCell} |";
|
||||
}
|
||||
|
||||
$table = "| 필드 | 타입 | 실측 예시값 | 용도/설명 |\n| --- | --- | --- | --- |\n".implode("\n", $rows);
|
||||
|
||||
return $note !== '' ? $note."\n\n".$table : $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* 에러 응답 표를 생성합니다.
|
||||
*
|
||||
* 라우트 메타에서 대표 에러 상태코드와 발생 조건을 자동 추론합니다.
|
||||
* - 401: 인증 필수(`auth:sanctum`) 미들웨어. `optional.sanctum`(선택 인증)은 제외.
|
||||
* - 403: `admin` 미들웨어 또는 `permission:` 요구 → 권한 부족 시.
|
||||
* - 422: FormRequest 검증 규칙 존재 → 검증 실패 시.
|
||||
* - 404: path 파라미터 존재 → 대상 리소스 미발견 시.
|
||||
*
|
||||
* 자동 추론은 대표 상태코드의 초안이며, 도메인 특이 에러(409 충돌·429 제한 등)는
|
||||
* `@generated` 블록 밖 사람 서술에서 보강한다.
|
||||
*
|
||||
* @param array<string, mixed> $route 라우트 메타데이터
|
||||
* @param array<string, mixed> $request FormRequest 분석 결과
|
||||
* @return string 마크다운 표
|
||||
*/
|
||||
private function errorTable(array $route, array $request): string
|
||||
{
|
||||
$mw = $route['middleware'] ?? [];
|
||||
$rows = [];
|
||||
|
||||
// 401: 인증 필수. optional.sanctum(선택 인증)은 미인증도 허용하므로 제외.
|
||||
if (! $this->hasMiddleware($mw, 'optional.sanctum') && $this->hasMiddleware($mw, 'sanctum')) {
|
||||
$rows[] = '| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |';
|
||||
}
|
||||
|
||||
// 403: admin 게이트 또는 permission 요구 → 권한 부족.
|
||||
if ($this->hasMiddleware($mw, 'AdminMiddleware') || ! empty($route['permission'])) {
|
||||
$cond = ! empty($route['permission'])
|
||||
? "요구 권한(`{$route['permission']}`)이 없는 경우"
|
||||
: '관리자 권한이 없는 경우';
|
||||
$rows[] = "| 403 | Forbidden | {$cond} |";
|
||||
}
|
||||
|
||||
// 422: FormRequest 검증 규칙 존재 → 검증 실패. (훅 주입 규칙 포함 가능)
|
||||
$hasValidation = ! empty($request['params']) || ! empty($request['hook_filters']);
|
||||
if ($hasValidation) {
|
||||
$rows[] = '| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |';
|
||||
}
|
||||
|
||||
// 404: path 파라미터 존재 → 대상 리소스 미발견.
|
||||
if (! empty($route['path_params'])) {
|
||||
$rows[] = '| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |';
|
||||
}
|
||||
|
||||
if ($rows === []) {
|
||||
return '_대표 에러 없음 (공개 조회). <!-- TODO: 도메인 특이 에러가 있으면 보강 -->_';
|
||||
}
|
||||
|
||||
return "| 상태코드 | 의미 | 발생 조건 |\n| --- | --- | --- |\n".implode("\n", $rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* 마크다운 표 셀 안에서 안전하도록 파이프/개행을 이스케이프합니다.
|
||||
*
|
||||
* @param string $text 원본 텍스트
|
||||
* @return string 이스케이프된 텍스트
|
||||
*/
|
||||
private function escapeCell(string $text): string
|
||||
{
|
||||
return str_replace(['|', "\n", "\r"], ['\\|', ' ', ''], $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 기존 문서에 새 생성 블록을 병합합니다. 사람 서술은 보존합니다.
|
||||
*
|
||||
* @param string|null $existing 기존 문서 내용 (null=신규)
|
||||
* @param string $header 문서 헤더 (제목 + TL;DR 등)
|
||||
* @param array<int, string> $sections 엔드포인트 섹션 목록 (라우트명 순)
|
||||
* @param array<int, string> $sectionKeys 각 섹션의 라우트명 키
|
||||
* @return string 병합된 문서 내용
|
||||
*/
|
||||
public function mergeDocument(?string $existing, string $header, array $sections, array $sectionKeys): string
|
||||
{
|
||||
if ($existing === null) {
|
||||
return $header."\n".implode("\n", $sections);
|
||||
}
|
||||
|
||||
$merged = $header."\n";
|
||||
|
||||
foreach ($sections as $i => $section) {
|
||||
$key = $sectionKeys[$i];
|
||||
$preserved = $this->extractHumanProse($existing, $key);
|
||||
$merged .= $this->applyPreservedProse($section, $preserved)."\n";
|
||||
}
|
||||
|
||||
return $merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* 기존 문서에서 특정 엔드포인트의 사람 서술(생성 블록 밖)을 추출합니다.
|
||||
*
|
||||
* @param string $existing 기존 문서
|
||||
* @param string $key 라우트명 키
|
||||
* @return string|null 보존할 사람 서술 (없으면 null)
|
||||
*/
|
||||
private function extractHumanProse(string $existing, string $key): ?string
|
||||
{
|
||||
$startMarker = self::GEN_START.$key.' -->';
|
||||
$startPos = strpos($existing, $startMarker);
|
||||
|
||||
if ($startPos === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$endPos = strpos($existing, self::GEN_END, $startPos);
|
||||
if ($endPos === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$afterGen = substr($existing, $endPos + strlen(self::GEN_END));
|
||||
// 다음 ### 헤딩 전까지가 이 엔드포인트의 사람 서술
|
||||
$nextHeading = preg_match('/\n### /', $afterGen, $m, PREG_OFFSET_CAPTURE)
|
||||
? $m[0][1]
|
||||
: strlen($afterGen);
|
||||
|
||||
$prose = trim(substr($afterGen, 0, $nextHeading));
|
||||
|
||||
// 기본 TODO 스텁만 있으면 보존할 것 없음
|
||||
if ($prose === '' || Str::contains($prose, 'TODO: 이 엔드포인트의 용도')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $prose;
|
||||
}
|
||||
|
||||
/**
|
||||
* 새 섹션의 기본 서술 스텁을 보존된 사람 서술로 치환합니다.
|
||||
*
|
||||
* @param string $section 새로 생성된 섹션
|
||||
* @param string|null $preserved 보존할 사람 서술
|
||||
* @return string 서술이 반영된 섹션
|
||||
*/
|
||||
private function applyPreservedProse(string $section, ?string $preserved): string
|
||||
{
|
||||
if ($preserved === null) {
|
||||
return $section;
|
||||
}
|
||||
|
||||
$stub = '**설명** <!-- TODO: 이 엔드포인트의 용도·주의사항·예시 시나리오를 작성하세요 -->';
|
||||
|
||||
return str_replace($stub, $preserved, $section);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support\ApiDoc;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Sanctum\PersonalAccessToken;
|
||||
|
||||
/**
|
||||
* API 엔드포인트 실측 프로브
|
||||
*
|
||||
* 임시 Sanctum 토큰을 발급해 실제 HTTP 요청으로 엔드포인트를 호출하고,
|
||||
* 실제 응답 JSON 에서 필드 스키마(키·타입·샘플값)를 관측합니다.
|
||||
* 쓰기 메서드는 기본적으로 실호출하지 않으며 GET/HEAD 만 read-only 로 실측합니다.
|
||||
*/
|
||||
class ApiEndpointProbe
|
||||
{
|
||||
/**
|
||||
* @var string 실측 대상 기준 URL
|
||||
*/
|
||||
private string $baseUrl;
|
||||
|
||||
/**
|
||||
* @var string|null 발급된 임시 토큰 평문
|
||||
*/
|
||||
private ?string $token = null;
|
||||
|
||||
/**
|
||||
* @var string 임시 토큰 식별용 이름
|
||||
*/
|
||||
private string $tokenName = 'api-docgen-probe';
|
||||
|
||||
/**
|
||||
* @param string|null $baseUrl 기준 URL (null 이면 .env 의 APP_URL 직접 사용)
|
||||
*/
|
||||
public function __construct(?string $baseUrl = null)
|
||||
{
|
||||
// config('app.url') 은 테스트 환경에서 override 될 수 있으므로(test.example.com 등),
|
||||
// 실측은 .env 의 APP_URL 을 우선 신뢰한다. 명시 인자가 있으면 그것을 최우선한다.
|
||||
$resolved = $baseUrl
|
||||
?: (string) env('APP_URL')
|
||||
?: (string) config('app.url');
|
||||
|
||||
$this->baseUrl = rtrim($resolved, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* 실측 기준 URL 을 반환합니다.
|
||||
*
|
||||
* @return string 기준 URL
|
||||
*/
|
||||
public function baseUrl(): string
|
||||
{
|
||||
return $this->baseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 실측용 관리자 토큰을 발급합니다.
|
||||
*
|
||||
* @param int|null $userId 토큰 발급 대상 사용자 ID (null 이면 첫 관리자)
|
||||
* @return bool 발급 성공 여부
|
||||
*/
|
||||
public function authenticate(?int $userId = null): bool
|
||||
{
|
||||
$user = $userId
|
||||
? User::find($userId)
|
||||
: User::query()->orderBy('id')->first();
|
||||
|
||||
if (! $user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->cleanupTokens();
|
||||
$this->token = $user->createToken($this->tokenName)->plainTextToken;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* GET 엔드포인트를 실호출하여 응답을 관측합니다.
|
||||
*
|
||||
* @param string $method HTTP 메서드
|
||||
* @param string $uri 라우트 URI (path 파라미터 치환 완료된 실제 경로)
|
||||
* @return array{ok: bool, status: int|null, body: array<string, mixed>|null, skipped_reason: string|null}
|
||||
*/
|
||||
public function probe(string $method, string $uri): array
|
||||
{
|
||||
$method = strtoupper($method);
|
||||
|
||||
// 쓰기 메서드는 부수효과 위험으로 실호출하지 않는다 (정적 문서화로 대체).
|
||||
if (! in_array($method, ['GET', 'HEAD'], true)) {
|
||||
return ['ok' => false, 'status' => null, 'body' => null, 'skipped_reason' => 'write-method'];
|
||||
}
|
||||
|
||||
// path 파라미터가 남아 있으면(치환 실패) 실호출 불가.
|
||||
if (Str::contains($uri, '{')) {
|
||||
return ['ok' => false, 'status' => null, 'body' => null, 'skipped_reason' => 'unresolved-path-param'];
|
||||
}
|
||||
|
||||
if (! $this->token) {
|
||||
return ['ok' => false, 'status' => null, 'body' => null, 'skipped_reason' => 'no-token'];
|
||||
}
|
||||
|
||||
try {
|
||||
$response = Http::withoutVerifying()
|
||||
->withToken($this->token)
|
||||
->acceptJson()
|
||||
->timeout(15)
|
||||
->get($this->baseUrl.$uri);
|
||||
|
||||
$json = $response->json();
|
||||
|
||||
return [
|
||||
'ok' => $response->successful() && is_array($json),
|
||||
'status' => $response->status(),
|
||||
'body' => is_array($json) ? $json : null,
|
||||
'skipped_reason' => null,
|
||||
];
|
||||
} catch (\Throwable $e) {
|
||||
return ['ok' => false, 'status' => null, 'body' => null, 'skipped_reason' => 'request-failed: '.$e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 발급한 임시 토큰을 정리합니다.
|
||||
*/
|
||||
public function cleanup(): void
|
||||
{
|
||||
$this->cleanupTokens();
|
||||
$this->token = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 실측용 토큰 레코드를 모두 삭제합니다.
|
||||
*/
|
||||
private function cleanupTokens(): void
|
||||
{
|
||||
PersonalAccessToken::query()
|
||||
->where('name', $this->tokenName)
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support\ApiDoc;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Routing\Route;
|
||||
use Illuminate\Support\Facades\Route as RouteFacade;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* API 라우트 인벤토리
|
||||
*
|
||||
* 등록된 라우트를 전수 수집하여 API 문서 생성에 필요한 메타데이터
|
||||
* (메서드·URI·라우트명·소유 확장·권한·컨트롤러 액션)로 정규화합니다.
|
||||
*/
|
||||
class ApiRouteInventory
|
||||
{
|
||||
/**
|
||||
* API 라우트를 전수 수집하여 정규화된 배열로 반환합니다.
|
||||
*
|
||||
* @param string|null $scope 범위 필터 (null=전체, 'core', 'module:{id}', 'plugin:{id}')
|
||||
* @return array<int, array<string, mixed>> 정규화된 라우트 메타데이터 목록
|
||||
*/
|
||||
public function collect(?string $scope = null): array
|
||||
{
|
||||
$routes = [];
|
||||
|
||||
foreach (RouteFacade::getRoutes() as $route) {
|
||||
/** @var Route $route */
|
||||
$uri = $route->uri();
|
||||
|
||||
if (! Str::startsWith($uri, 'api/')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $route->getName() ?? '';
|
||||
$owner = $this->resolveOwner($name, $uri);
|
||||
|
||||
if ($scope !== null && ! $this->matchesScope($owner, $scope)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($this->normalizeRoute($route, $uri, $name, $owner) as $entry) {
|
||||
$routes[] = $entry;
|
||||
}
|
||||
}
|
||||
|
||||
// route:list 는 활성 확장만 노출한다. 비활성/미설치 확장을 명시 범위로 지정하면
|
||||
// (module:{id} / plugin:{id}) 등록된 라우트가 0건이 되므로, 그 확장의 번들 라우트
|
||||
// 파일을 프로바이더와 동일한 prefix/name 규약으로 임시 라우터에 로드해 폴백 수집한다.
|
||||
if ($routes === [] && $scope !== null && $scope !== 'core' && $scope !== 'all') {
|
||||
$routes = $this->collectFromBundledFiles($scope);
|
||||
}
|
||||
|
||||
usort($routes, fn ($a, $b) => [$a['owner']['key'], $a['uri'], $a['method']] <=> [$b['owner']['key'], $b['uri'], $b['method']]);
|
||||
|
||||
return $routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 하나의 라우트를 HTTP 메서드별 정규화 엔트리 배열로 변환합니다.
|
||||
*
|
||||
* @param Route $route 라우트 인스턴스
|
||||
* @param string $uri 라우트 URI ('api/' prefix 포함)
|
||||
* @param string $name 라우트명
|
||||
* @param array{type: string, id: string|null, key: string} $owner 소유 주체
|
||||
* @return array<int, array<string, mixed>> 정규화된 엔트리 목록
|
||||
*/
|
||||
private function normalizeRoute(Route $route, string $uri, string $name, array $owner): array
|
||||
{
|
||||
$entries = [];
|
||||
|
||||
$middleware = $this->gatherMiddleware($route);
|
||||
|
||||
foreach ($this->httpMethods($route) as $method) {
|
||||
$entries[] = [
|
||||
'method' => $method,
|
||||
'uri' => '/'.ltrim($uri, '/'),
|
||||
'name' => $name,
|
||||
'owner' => $owner,
|
||||
'action' => $route->getActionName(),
|
||||
'controller' => $this->controllerClass($route),
|
||||
'controller_method' => $this->controllerMethod($route),
|
||||
'middleware' => $middleware,
|
||||
'permission' => $this->resolvePermission($middleware),
|
||||
'path_params' => $this->pathParams($uri),
|
||||
'path_bindings' => $this->pathBindings($route),
|
||||
'domain_group' => $this->domainGroup($name, $uri, $owner),
|
||||
];
|
||||
}
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* 라우트의 미들웨어 목록을 안전하게 수집합니다.
|
||||
*
|
||||
* `gatherMiddleware()` 는 컨트롤러 정의 미들웨어를 읽기 위해 컨트롤러를 인스턴스화한다.
|
||||
* 비활성/미설치 확장은 서비스 바인딩이 부팅되지 않아 인스턴스화가 실패할 수 있으므로,
|
||||
* 실패 시 라우트에 직접 부여된 정적 미들웨어(`middleware()`)로 폴백한다.
|
||||
*
|
||||
* @param Route $route 라우트 인스턴스
|
||||
* @return array<int, string> 미들웨어 목록
|
||||
*/
|
||||
private function gatherMiddleware(Route $route): array
|
||||
{
|
||||
try {
|
||||
return $route->gatherMiddleware();
|
||||
} catch (\Throwable) {
|
||||
return $route->middleware();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 비활성/미설치 확장의 번들 라우트 파일을 임시 라우터에 로드해 수집합니다.
|
||||
*
|
||||
* 프로바이더(`ModuleRouteServiceProvider`/`PluginRouteServiceProvider`)와 동일한
|
||||
* prefix(`api/{modules|plugins}/{id}`)·name(`api.{modules|plugins}.{id}.`)·`api`
|
||||
* 미들웨어 그룹으로 `src/routes/api.php` 를 라우터에 로드한다. `api/` 로 시작하는
|
||||
* 라우트만 대상이므로 web(admin) 라우트는 자동 제외된다(그 라우트는 API 문서 대상이 아니다).
|
||||
*
|
||||
* 라우트 파일은 `use Illuminate\Support\Facades\Route` 로 전역 파사드에 등록하므로,
|
||||
* 등록 전 라우트 이름 스냅샷을 떠서 이번 로드로 추가된 라우트만 골라낸다. 이 커맨드는
|
||||
* CLI 단발 프로세스라 전역 라우트 테이블 추가가 웹 요청에 영향을 주지 않는다.
|
||||
*
|
||||
* @param string $scope 범위 필터 (`module:{id}` / `plugin:{id}`)
|
||||
* @return array<int, array<string, mixed>> 정규화된 라우트 메타데이터 목록
|
||||
*/
|
||||
private function collectFromBundledFiles(string $scope): array
|
||||
{
|
||||
if (! preg_match('/^(module|plugin):(.+)$/', $scope, $m)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
[$type, $id] = [$m[1], $m[2]];
|
||||
$dir = $type === 'module' ? 'modules' : 'plugins';
|
||||
$apiRouteFile = base_path("{$dir}/_bundled/{$id}/src/routes/api.php");
|
||||
|
||||
if (! is_file($apiRouteFile)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$urlPrefix = "api/{$dir}/{$id}";
|
||||
$namePrefix = "api.{$dir}.{$id}.";
|
||||
|
||||
// 등록 전 스냅샷 — 이미 등록된(활성) 라우트와 이번 로드분을 구분한다.
|
||||
$existing = [];
|
||||
foreach (RouteFacade::getRoutes() as $route) {
|
||||
/** @var Route $route */
|
||||
$existing[spl_object_id($route)] = true;
|
||||
}
|
||||
|
||||
try {
|
||||
RouteFacade::prefix($urlPrefix)
|
||||
->name($namePrefix)
|
||||
->middleware('api')
|
||||
->group($apiRouteFile);
|
||||
RouteFacade::getRoutes()->refreshNameLookups();
|
||||
} catch (\Throwable) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$routes = [];
|
||||
|
||||
foreach (RouteFacade::getRoutes() as $route) {
|
||||
/** @var Route $route */
|
||||
if (isset($existing[spl_object_id($route)])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$uri = $route->uri();
|
||||
|
||||
if (! Str::startsWith($uri, 'api/')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $route->getName() ?? '';
|
||||
$owner = $this->resolveOwner($name, $uri);
|
||||
|
||||
// 폴백 대상 확장 소유로 확정되지 않으면(코어 등) 제외
|
||||
if ($owner['key'] !== $scope) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($this->normalizeRoute($route, $uri, $name, $owner) as $entry) {
|
||||
$routes[] = $entry;
|
||||
}
|
||||
}
|
||||
|
||||
return $routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 라우트명/URI 로 소유 주체(코어/모듈/플러그인)를 판별합니다.
|
||||
*
|
||||
* @param string $name 라우트명
|
||||
* @param string $uri 라우트 URI
|
||||
* @return array{type: string, id: string|null, key: string} 소유 주체 정보
|
||||
*/
|
||||
private function resolveOwner(string $name, string $uri): array
|
||||
{
|
||||
if (preg_match('/^api\.modules\.([^.]+)\./', $name, $m) && $this->isRealExtensionId($m[1])) {
|
||||
return ['type' => 'module', 'id' => $m[1], 'key' => 'module:'.$m[1]];
|
||||
}
|
||||
|
||||
if (preg_match('/^api\.plugins\.([^.]+)\./', $name, $m) && $this->isRealExtensionId($m[1])) {
|
||||
return ['type' => 'plugin', 'id' => $m[1], 'key' => 'plugin:'.$m[1]];
|
||||
}
|
||||
|
||||
// 라우트명이 비어도 URI prefix 로 보조 판별
|
||||
if (preg_match('#^api/modules/([^/{]+)/#', $uri, $m) && $this->isRealExtensionId($m[1])) {
|
||||
return ['type' => 'module', 'id' => $m[1], 'key' => 'module:'.$m[1]];
|
||||
}
|
||||
|
||||
if (preg_match('#^api/plugins/([^/{]+)/#', $uri, $m) && $this->isRealExtensionId($m[1])) {
|
||||
return ['type' => 'plugin', 'id' => $m[1], 'key' => 'plugin:'.$m[1]];
|
||||
}
|
||||
|
||||
// 코어가 제공하는 확장 메타/에셋 라우트(/api/modules/{identifier}/license,
|
||||
// /api/modules/bundle.js 등)는 실제 확장 소유가 아니라 코어 소유다.
|
||||
return ['type' => 'core', 'id' => null, 'key' => 'core'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 세그먼트가 실제 확장 식별자인지 판별합니다 (플레이스홀더/에셋 라우트 제외).
|
||||
*
|
||||
* @param string $segment URI/라우트명 세그먼트
|
||||
* @return bool 실제 확장 식별자 여부
|
||||
*/
|
||||
private function isRealExtensionId(string $segment): bool
|
||||
{
|
||||
// {identifier} 같은 라우트 파라미터, bundle/assets 같은 코어 에셋 라우트 제외.
|
||||
// 실제 확장 식별자는 vendor-name 형태로 하이픈을 포함한다.
|
||||
if (Str::startsWith($segment, '{') || in_array($segment, ['assets', 'bundle', 'bundle.js', 'bundle.css'], true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Str::contains($segment, '-');
|
||||
}
|
||||
|
||||
/**
|
||||
* 소유 주체가 지정된 범위 필터에 매칭되는지 확인합니다.
|
||||
*
|
||||
* @param array{type: string, id: string|null, key: string} $owner 소유 주체
|
||||
* @param string $scope 범위 필터
|
||||
* @return bool 매칭 여부
|
||||
*/
|
||||
private function matchesScope(array $owner, string $scope): bool
|
||||
{
|
||||
if ($scope === 'all') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($scope === 'core') {
|
||||
return $owner['type'] === 'core';
|
||||
}
|
||||
|
||||
return $owner['key'] === $scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* 라우트의 HTTP 메서드 목록을 반환합니다 (HEAD 제외).
|
||||
*
|
||||
* @param Route $route 라우트 인스턴스
|
||||
* @return array<int, string> HTTP 메서드 목록
|
||||
*/
|
||||
private function httpMethods(Route $route): array
|
||||
{
|
||||
return array_values(array_filter(
|
||||
$route->methods(),
|
||||
fn ($m) => $m !== 'HEAD'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 컨트롤러 클래스명을 반환합니다.
|
||||
*
|
||||
* @param Route $route 라우트 인스턴스
|
||||
* @return string|null 컨트롤러 FQCN (클로저면 null)
|
||||
*/
|
||||
private function controllerClass(Route $route): ?string
|
||||
{
|
||||
$action = $route->getActionName();
|
||||
|
||||
if ($action === 'Closure' || ! Str::contains($action, '@')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Str::before($action, '@');
|
||||
}
|
||||
|
||||
/**
|
||||
* 컨트롤러 메서드명을 반환합니다.
|
||||
*
|
||||
* @param Route $route 라우트 인스턴스
|
||||
* @return string|null 메서드명 (클로저면 null)
|
||||
*/
|
||||
private function controllerMethod(Route $route): ?string
|
||||
{
|
||||
$action = $route->getActionName();
|
||||
|
||||
if ($action === 'Closure' || ! Str::contains($action, '@')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Str::after($action, '@');
|
||||
}
|
||||
|
||||
/**
|
||||
* 미들웨어 목록에서 permission 식별자를 추출합니다.
|
||||
*
|
||||
* @param array<int, string> $middleware 미들웨어 목록
|
||||
* @return string|null permission 식별자 (예: core.users.read)
|
||||
*/
|
||||
private function resolvePermission(array $middleware): ?string
|
||||
{
|
||||
foreach ($middleware as $mw) {
|
||||
if (! Str::contains($mw, 'PermissionMiddleware') && ! Str::startsWith($mw, 'permission:')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$args = Str::after($mw, ':');
|
||||
// permission:admin,core.users.read,except:self:user → core.users.read
|
||||
foreach (explode(',', $args) as $part) {
|
||||
$part = trim($part);
|
||||
if (Str::contains($part, '.') && ! Str::startsWith($part, 'except')) {
|
||||
return $part;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* URI 의 path 파라미터 목록을 추출합니다.
|
||||
*
|
||||
* @param string $uri 라우트 URI
|
||||
* @return array<int, string> path 파라미터명 목록
|
||||
*/
|
||||
private function pathParams(string $uri): array
|
||||
{
|
||||
preg_match_all('/\{([^}?]+)\??\}/', $uri, $m);
|
||||
|
||||
return $m[1] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* path 파라미터명 → 바인딩된 Eloquent 모델 클래스 맵을 추출합니다.
|
||||
*
|
||||
* @param Route $route 라우트 인스턴스
|
||||
* @return array<string, string> 파라미터명 => 모델 FQCN
|
||||
*/
|
||||
private function pathBindings(Route $route): array
|
||||
{
|
||||
$bindings = [];
|
||||
|
||||
try {
|
||||
foreach ($route->signatureParameters() as $param) {
|
||||
$type = $param->getType();
|
||||
|
||||
if ($type instanceof \ReflectionNamedType && ! $type->isBuiltin()) {
|
||||
$class = $type->getName();
|
||||
|
||||
if (is_subclass_of($class, Model::class)) {
|
||||
$bindings[$param->getName()] = $class;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
// signatureParameters 실패 시 빈 맵
|
||||
}
|
||||
|
||||
return $bindings;
|
||||
}
|
||||
|
||||
/**
|
||||
* 문서 파일 그룹핑용 도메인 키를 산출합니다.
|
||||
*
|
||||
* @param string $name 라우트명
|
||||
* @param string $uri 라우트 URI
|
||||
* @param array{type: string, id: string|null, key: string} $owner 소유 주체
|
||||
* @return string 도메인 키 (예: users, products)
|
||||
*/
|
||||
private function domainGroup(string $name, string $uri, array $owner): string
|
||||
{
|
||||
// 라우트명 구조: api.{context}.{resource}.{action} 또는
|
||||
// api.modules.{ext-id}.{context}.{resource}.{action}
|
||||
// 도메인 = 앞쪽 연속된 context/소유 세그먼트를 걷어낸 뒤의 첫 세그먼트(리소스).
|
||||
// 위치 기반이므로 'auth' 같은 리소스가 skip 리스트에 걸려 소실되지 않는다.
|
||||
// 'modules'/'plugins' 는 확장 소유 prefix(api.modules.{id}.*)로도, 코어 확장관리
|
||||
// 리소스(api.admin.modules.*)로도 쓰인다. 소유 prefix 는 owner['id'] 스킵으로 이미
|
||||
// 걷히므로, leading 에는 순수 컨텍스트(api/admin/user/me/public)만 둔다.
|
||||
$leading = ['api', 'admin', 'user', 'me', 'public'];
|
||||
$segments = array_values(array_filter(explode('.', $name), fn ($s) => $s !== ''));
|
||||
|
||||
$i = 0;
|
||||
while ($i < count($segments)) {
|
||||
$seg = $segments[$i];
|
||||
// 확장 소유 prefix 세그먼트(modules/plugins + ext-id)만 스킵
|
||||
$isOwnerPrefix = in_array($seg, ['modules', 'plugins'], true) && isset($segments[$i + 1]) && $segments[$i + 1] === $owner['id'];
|
||||
$isLeading = in_array($seg, $leading, true) || $isOwnerPrefix || ($owner['id'] !== null && $seg === $owner['id']);
|
||||
|
||||
if (! $isLeading) {
|
||||
break;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
// context(me 등) 직후가 REST 액션명이면 리소스가 아니라 그 컨텍스트가 도메인이다
|
||||
// (api.me.show → 'me', api.me.destroy → 'me'). 아니면 그 세그먼트가 리소스.
|
||||
$restActions = ['show', 'index', 'store', 'update', 'destroy', 'edit', 'create'];
|
||||
if (isset($segments[$i])) {
|
||||
if (in_array($segments[$i], $restActions, true) && $i > 0 && in_array($segments[$i - 1], $leading, true)) {
|
||||
return Str::slug($segments[$i - 1]) ?: 'misc';
|
||||
}
|
||||
|
||||
return Str::slug($segments[$i]) ?: 'misc';
|
||||
}
|
||||
|
||||
// 리소스 세그먼트가 없으면(context 직속) 마지막 컨텍스트를 도메인으로.
|
||||
if ($i > 0 && isset($segments[$i - 1]) && in_array($segments[$i - 1], $leading, true)) {
|
||||
return Str::slug($segments[$i - 1]) ?: 'misc';
|
||||
}
|
||||
|
||||
// 라우트명이 비었으면 URI 에서 소유/컨텍스트 prefix 를 걷어낸 첫 리소스 세그먼트
|
||||
$parts = array_values(array_filter(explode('/', $uri), fn ($p) => $p !== '' && ! Str::startsWith($p, '{')));
|
||||
$uriLeading = ['api', 'admin', 'user', 'me', 'public'];
|
||||
foreach ($parts as $p) {
|
||||
if (in_array($p, $uriLeading, true) || ($owner['id'] !== null && $p === $owner['id'])) {
|
||||
continue;
|
||||
}
|
||||
if (in_array($p, ['modules', 'plugins'], true) && ($owner['id'] !== null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return Str::slug($p) ?: 'misc';
|
||||
}
|
||||
|
||||
return 'misc';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support\ApiDoc;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* 컬럼 주석 해석기
|
||||
*
|
||||
* 모델 테이블의 컬럼 주석(한국어 comment) 을 조회해 응답 필드 설명의 기본값으로
|
||||
* 제공합니다. G7 은 마이그레이션 한국어 comment 를 필수화하므로, 이 주석이 필드
|
||||
* 설명의 SSoT 가 됩니다. 정적 스키마 조회이므로 실측 없이도 동작합니다.
|
||||
*/
|
||||
class ColumnCommentResolver
|
||||
{
|
||||
/**
|
||||
* @var array<string, array<string, string>> 테이블별 컬럼 주석 캐시
|
||||
*/
|
||||
private array $cache = [];
|
||||
|
||||
/**
|
||||
* 모델 테이블의 컬럼명 => 주석 맵을 반환합니다.
|
||||
*
|
||||
* @param class-string|null $modelClass 모델 FQCN
|
||||
* @return array<string, string> 컬럼명 => 주석
|
||||
*/
|
||||
public function forModel(?string $modelClass): array
|
||||
{
|
||||
if (! $modelClass || ! class_exists($modelClass) || ! is_subclass_of($modelClass, Model::class)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
$table = (new $modelClass)->getTable();
|
||||
} catch (\Throwable) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->forTable($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* 테이블의 컬럼명 => 주석 맵을 반환합니다 (캐시).
|
||||
*
|
||||
* @param string $table 테이블명
|
||||
* @return array<string, string> 컬럼명 => 주석
|
||||
*/
|
||||
public function forTable(string $table): array
|
||||
{
|
||||
if (isset($this->cache[$table])) {
|
||||
return $this->cache[$table];
|
||||
}
|
||||
|
||||
$map = [];
|
||||
|
||||
try {
|
||||
foreach (Schema::getColumns($table) as $column) {
|
||||
$comment = $column['comment'] ?? null;
|
||||
|
||||
if (is_string($comment) && $comment !== '') {
|
||||
$map[$column['name']] = $comment;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
// 테이블 부재/드라이버 미지원 시 빈 맵
|
||||
}
|
||||
|
||||
return $this->cache[$table] = $map;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support\ApiDoc;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use ReflectionNamedType;
|
||||
|
||||
/**
|
||||
* FormRequest 정적 분석기
|
||||
*
|
||||
* 컨트롤러 메서드 시그니처에서 FormRequest 를 찾아 rules() 를 리플렉션으로
|
||||
* 읽고, 요청 파라미터의 타입·필수 여부·허용값을 문서용 메타데이터로 변환합니다.
|
||||
*/
|
||||
class FormRequestIntrospector
|
||||
{
|
||||
/**
|
||||
* 컨트롤러 메서드의 첫 FormRequest 파라미터에서 rules 메타데이터를 추출합니다.
|
||||
*
|
||||
* @param string|null $controller 컨트롤러 FQCN
|
||||
* @param string|null $method 메서드명
|
||||
* @return array{request_class: string|null, params: array<int, array<string, mixed>>, hook_filters: array<int, string>}
|
||||
*/
|
||||
public function introspect(?string $controller, ?string $method): array
|
||||
{
|
||||
$empty = ['request_class' => null, 'params' => [], 'hook_filters' => []];
|
||||
|
||||
if (! $controller || ! $method || ! class_exists($controller)) {
|
||||
return $empty;
|
||||
}
|
||||
|
||||
try {
|
||||
$ref = new ReflectionMethod($controller, $method);
|
||||
} catch (\ReflectionException) {
|
||||
return $empty;
|
||||
}
|
||||
|
||||
$requestClass = $this->findFormRequestParam($ref);
|
||||
|
||||
if (! $requestClass) {
|
||||
return $empty;
|
||||
}
|
||||
|
||||
$rules = $this->extractRules($requestClass);
|
||||
|
||||
return [
|
||||
'request_class' => $requestClass,
|
||||
'params' => $this->rulesToParams($rules),
|
||||
'hook_filters' => $this->extractHookFilters($requestClass),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 메서드 파라미터 중 FormRequest 하위 클래스를 찾습니다.
|
||||
*
|
||||
* @param ReflectionMethod $ref 메서드 리플렉션
|
||||
* @return class-string<FormRequest>|null FormRequest FQCN
|
||||
*/
|
||||
private function findFormRequestParam(ReflectionMethod $ref): ?string
|
||||
{
|
||||
foreach ($ref->getParameters() as $param) {
|
||||
$type = $param->getType();
|
||||
|
||||
if (! $type instanceof ReflectionNamedType || $type->isBuiltin()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class = $type->getName();
|
||||
|
||||
if (is_subclass_of($class, FormRequest::class)) {
|
||||
return $class;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* FormRequest 인스턴스를 만들어 rules() 를 호출합니다.
|
||||
*
|
||||
* @param class-string<FormRequest> $requestClass FormRequest FQCN
|
||||
* @return array<string, mixed> 검증 규칙 배열
|
||||
*/
|
||||
private function extractRules(string $requestClass): array
|
||||
{
|
||||
try {
|
||||
$instance = new $requestClass;
|
||||
|
||||
if (! method_exists($instance, 'rules')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$rules = $instance->rules();
|
||||
|
||||
return is_array($rules) ? $rules : [];
|
||||
} catch (\Throwable) {
|
||||
// rules() 가 컨테이너/route 의존이면 정적 호출 실패 — 파라미터 표는 비운다.
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 검증 규칙 배열을 문서용 파라미터 메타데이터로 변환합니다.
|
||||
*
|
||||
* @param array<string, mixed> $rules 검증 규칙 배열
|
||||
* @return array<int, array<string, mixed>> 파라미터 메타데이터 목록
|
||||
*/
|
||||
private function rulesToParams(array $rules): array
|
||||
{
|
||||
$params = [];
|
||||
|
||||
foreach ($rules as $field => $rule) {
|
||||
// 중첩 필드(items.*.id)는 상위만 대표로 노출
|
||||
if (str_contains((string) $field, '.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$tokens = is_array($rule) ? $rule : explode('|', (string) $rule);
|
||||
$tokens = array_map(fn ($t) => is_string($t) ? $t : '', $tokens);
|
||||
|
||||
$params[] = [
|
||||
'name' => $field,
|
||||
'type' => $this->inferType($tokens),
|
||||
'required' => in_array('required', $tokens, true),
|
||||
'allowed' => $this->inferAllowed($tokens),
|
||||
];
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 규칙 토큰에서 파라미터 타입을 유추합니다.
|
||||
*
|
||||
* @param array<int, string> $tokens 규칙 토큰 목록
|
||||
* @return string 유추된 타입
|
||||
*/
|
||||
private function inferType(array $tokens): string
|
||||
{
|
||||
foreach (['integer', 'numeric', 'boolean', 'array', 'string', 'date', 'email', 'file', 'image', 'uuid'] as $type) {
|
||||
foreach ($tokens as $t) {
|
||||
if ($t === $type || str_starts_with($t, $type)) {
|
||||
return $type === 'numeric' ? 'number' : $type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 'string';
|
||||
}
|
||||
|
||||
/**
|
||||
* 규칙 토큰에서 허용값(in:, max:, min: 등)을 유추합니다.
|
||||
*
|
||||
* @param array<int, string> $tokens 규칙 토큰 목록
|
||||
* @return string 허용값 설명 (없으면 빈 문자열)
|
||||
*/
|
||||
private function inferAllowed(array $tokens): string
|
||||
{
|
||||
$parts = [];
|
||||
|
||||
foreach ($tokens as $t) {
|
||||
if (str_starts_with($t, 'in:')) {
|
||||
$parts[] = '`'.str_replace(',', '`, `', substr($t, 3)).'`';
|
||||
} elseif (str_starts_with($t, 'max:')) {
|
||||
$parts[] = 'max '.substr($t, 4);
|
||||
} elseif (str_starts_with($t, 'min:')) {
|
||||
$parts[] = 'min '.substr($t, 4);
|
||||
} elseif (str_starts_with($t, 'between:')) {
|
||||
$parts[] = 'between '.substr($t, 8);
|
||||
}
|
||||
}
|
||||
|
||||
return implode(', ', $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* FormRequest 소스에서 HookManager::applyFilters 훅 이름을 추출합니다.
|
||||
*
|
||||
* @param class-string<FormRequest> $requestClass FormRequest FQCN
|
||||
* @return array<int, string> 훅 필터 이름 목록
|
||||
*/
|
||||
private function extractHookFilters(string $requestClass): array
|
||||
{
|
||||
try {
|
||||
$file = (new ReflectionClass($requestClass))->getFileName();
|
||||
|
||||
if (! $file || ! is_readable($file)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$source = file_get_contents($file);
|
||||
preg_match_all('/applyFilters\(\s*[\'"]([a-z0-9_.-]+)[\'"]/i', $source, $m);
|
||||
|
||||
return array_values(array_unique($m[1] ?? []));
|
||||
} catch (\Throwable) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support\ApiDoc;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* 요청 파라미터 설명기
|
||||
*
|
||||
* G7 전역에서 의미가 표준화된 공통 요청 파라미터(페이지네이션·정렬·검색·필터·
|
||||
* 소프트삭제 토글 등)와, 일관된 명명 규칙(*_id / *Id / is_* / *_date / sort_* 등)의
|
||||
* 설명을 코드에서 확인된 계약 그대로 서술합니다.
|
||||
*
|
||||
* ResourceFieldDescriber(응답 필드)의 요청 파라미터 대응물입니다. 도메인 특이
|
||||
* 파라미터(예: refund_priority, temp_key)는 여기서 커버하지 않고 사람 서술(TODO)로
|
||||
* 남깁니다 — 자동 채움은 "도메인 무관하게 의미가 고정된 파라미터"에만 한정합니다.
|
||||
*/
|
||||
class ParameterDescriber
|
||||
{
|
||||
/**
|
||||
* @var array<string, string> 정확 이름 => 설명 (위치 무관 공통 파라미터)
|
||||
*/
|
||||
private const EXACT = [
|
||||
// 페이지네이션
|
||||
'page' => '조회할 페이지 번호 (1부터 시작)',
|
||||
'per_page' => '페이지당 항목 수',
|
||||
'limit' => '반환할 최대 항목 수',
|
||||
'offset' => '건너뛸 항목 수 (오프셋 페이지네이션)',
|
||||
'cursor' => '커서 기반 페이지네이션의 다음 페이지 커서',
|
||||
|
||||
// 정렬
|
||||
'sort' => '정렬 기준 (필드명, `-` 접두 시 내림차순)',
|
||||
'sort_by' => '정렬 기준 필드명',
|
||||
'sort_field' => '정렬 기준 필드명',
|
||||
'sort_direction' => '정렬 방향 (asc / desc)',
|
||||
'order_by' => '정렬 기준 필드명',
|
||||
'direction' => '정렬 방향 (asc / desc)',
|
||||
// sort_order / order 는 문맥에 따라 정렬 방향(문자열 asc/desc)과
|
||||
// 표시 순서 값(정수)으로 갈리므로 EXACT 에 두지 않고 describe() 에서
|
||||
// 타입으로 분기한다.
|
||||
|
||||
// 검색/필터
|
||||
'search' => '검색어 (지정한 검색 대상 필드에서 부분 일치)',
|
||||
'q' => '검색어 (부분 일치)',
|
||||
'keyword' => '검색 키워드 (부분 일치)',
|
||||
'search_keyword' => '검색 키워드 (부분 일치)',
|
||||
'search_field' => '검색 대상 필드명 (검색어를 적용할 컬럼)',
|
||||
'search_type' => '검색 유형 (검색 대상/방식 구분)',
|
||||
'filters' => '추가 필터 조건 맵 (필드별 조건)',
|
||||
'filter' => '필터 조건',
|
||||
'start_date' => '조회 기간 시작일 (이 날짜 이후 데이터)',
|
||||
'end_date' => '조회 기간 종료일 (이 날짜 이전 데이터)',
|
||||
'date_from' => '조회 기간 시작일',
|
||||
'date_to' => '조회 기간 종료일',
|
||||
'from' => '조회 시작 값 (기간/범위 하한)',
|
||||
'to' => '조회 종료 값 (기간/범위 상한)',
|
||||
'scope' => '조회 범위 한정 키',
|
||||
|
||||
// 상태 토글/플래그
|
||||
'is_active' => '활성 여부 (true 활성 / false 비활성)',
|
||||
'is_default' => '기본값 지정 여부',
|
||||
'active' => '활성 여부',
|
||||
'published' => '발행 여부 (발행된 항목만 필터)',
|
||||
'enabled' => '사용 여부',
|
||||
'force' => '강제 실행 여부 (안전 확인/선행 검사 우회)',
|
||||
'with_trashed' => '소프트 삭제된 항목 포함 여부',
|
||||
'only_trashed' => '소프트 삭제된 항목만 조회 여부',
|
||||
|
||||
// 대량 처리
|
||||
'ids' => '대상 리소스 식별자 배열 (대량 작업 대상)',
|
||||
'items' => '처리 대상 항목 배열',
|
||||
|
||||
// 국제화
|
||||
'locale' => '로케일 코드 (표시 언어/지역)',
|
||||
'language' => '언어 코드',
|
||||
'country_code' => '국가 코드 (ISO 3166-1 alpha-2)',
|
||||
'timezone' => '타임존 식별자',
|
||||
|
||||
// 인증/보안 공통
|
||||
'password' => '비밀번호',
|
||||
'current_password' => '현재 비밀번호 (변경 전 확인용)',
|
||||
'password_confirmation' => '비밀번호 확인 (password 와 일치해야 함)',
|
||||
'token' => '인증/검증 토큰',
|
||||
'email' => '이메일 주소',
|
||||
|
||||
// 주소 공통
|
||||
'zipcode' => '우편번호',
|
||||
'address' => '기본 주소',
|
||||
'address_detail' => '상세 주소',
|
||||
'recipient_name' => '수령인 이름',
|
||||
'recipient_phone' => '수령인 연락처',
|
||||
'address_line_1' => '주소 1행 (기본 주소)',
|
||||
'address_line_2' => '주소 2행 (상세 주소)',
|
||||
'intl_city' => '도시 (국제 주소)',
|
||||
'intl_state' => '주/도 (국제 주소)',
|
||||
'intl_postal_code' => '우편번호 (국제 주소)',
|
||||
'region' => '지역/권역',
|
||||
|
||||
// SEO 메타 공통 (근거: Seo\* / Page\* / Product\* FormRequest 의
|
||||
// meta_title/meta_description — 검색엔진 노출용 메타 태그 값. 도메인 무관.)
|
||||
'meta_title' => 'SEO 메타 제목 (검색엔진/소셜 공유 표시 제목)',
|
||||
'meta_description' => 'SEO 메타 설명 (검색엔진/소셜 공유 표시 요약)',
|
||||
'alt_text' => '이미지 대체 텍스트 (접근성/이미지 미표시 시 대체 문구)',
|
||||
|
||||
// 프로필/콘텐츠 공통 필드 (User/프로필/일반 리소스에서 의미 고정)
|
||||
// 근거: User\{Create,Update}UserRequest, UpdateProfileRequest, Auth\RegisterRequest,
|
||||
// Layout\* / Menu\* / Notification* / Schedule\* FormRequest
|
||||
'name' => '대상의 이름/명칭',
|
||||
'nickname' => '닉네임',
|
||||
'description' => '설명',
|
||||
'content' => '본문 내용',
|
||||
'body' => '본문',
|
||||
'subject' => '제목',
|
||||
'title' => '제목',
|
||||
'slug' => 'URL 친화 식별자 (slug)',
|
||||
'label' => '표시용 라벨',
|
||||
'phone' => '전화번호',
|
||||
'mobile' => '휴대전화 번호',
|
||||
'homepage' => '홈페이지 URL',
|
||||
'bio' => '자기소개',
|
||||
'signature' => '서명',
|
||||
'country' => '국가 코드 (ISO 3166-1 alpha-2)',
|
||||
'url' => 'URL',
|
||||
'file' => '업로드 파일',
|
||||
'files' => '업로드 파일 배열',
|
||||
'collection' => '첨부 컬렉션 그룹명 (첨부를 용도별로 묶는 키, 미지정 시 default)',
|
||||
'avatar' => '아바타 이미지',
|
||||
'icon' => '아이콘',
|
||||
'value' => '값',
|
||||
'values' => '값 배열',
|
||||
'username' => '사용자명 (로그인/인증 아이디)',
|
||||
'path' => '경로',
|
||||
'data' => '데이터 페이로드',
|
||||
|
||||
// 확장/버전 공통 (module/plugin/template/language-pack 설치·업데이트 계약)
|
||||
// 근거: Module/Plugin/Template/LanguagePack Install·Update·Activate FormRequest,
|
||||
// Extension\ChangelogRequest, Menu/Schedule/Notification* Request
|
||||
'extension_type' => '확장 유형 (core/module/plugin/template)',
|
||||
'extension_identifier' => '확장 식별자',
|
||||
'from_version' => '시작 버전 (범위 하한)',
|
||||
'to_version' => '대상 버전 (범위 상한)',
|
||||
'github_url' => 'GitHub 저장소 URL',
|
||||
'vendor' => '벤더명 (확장 제작자 식별자)',
|
||||
'vendor_mode' => '벤더 설치 모드 (auto/composer/bundled)',
|
||||
'checksum' => '무결성 검증 체크섬 (SHA-256)',
|
||||
'target_identifier' => '대상 확장 식별자',
|
||||
'source_identifier' => '출처 식별자',
|
||||
'auto_activate' => '설치 후 자동 활성화 여부',
|
||||
'cascade' => '연쇄 처리 여부 (의존 항목 함께 처리)',
|
||||
'exclude_protected' => '보호 항목 제외 여부',
|
||||
|
||||
// 스케줄/작업 공통 (근거: Schedule\{Create,Update}ScheduleRequest, ScheduleListRequest)
|
||||
'command' => '실행할 아티즌 커맨드',
|
||||
'frequency' => '실행 주기',
|
||||
'priority' => '우선순위 (작을수록 우선)',
|
||||
'timeout' => '타임아웃 (초)',
|
||||
'run_in_maintenance' => '점검 모드 중 실행 여부',
|
||||
'without_overlapping' => '중복 실행 방지 여부',
|
||||
'expected_lock_version' => '낙관적 잠금 버전 (동시 편집 충돌 감지)',
|
||||
|
||||
// 메일/드라이버 설정 (근거: Settings\SaveSettingsRequest,
|
||||
// Settings\TestMailRequest, Settings\TestDriverConnectionRequest)
|
||||
'mailer' => '메일 발송 드라이버 (smtp/mailgun/ses)',
|
||||
'from_address' => '발신자 주소',
|
||||
'from_name' => '발신자 이름',
|
||||
'to_email' => '테스트 수신 주소',
|
||||
'host' => '호스트 주소',
|
||||
'port' => '포트 번호',
|
||||
'encryption' => '전송 암호화 방식 (tls/ssl)',
|
||||
'storage_driver' => '스토리지 드라이버 (local/s3)',
|
||||
'cache_driver' => '캐시 드라이버 (file/redis/memcached)',
|
||||
'session_driver' => '세션 드라이버 (file/database/redis)',
|
||||
'queue_driver' => '큐 드라이버 (sync/database/redis)',
|
||||
'redis_host' => 'Redis 호스트 주소',
|
||||
'redis_port' => 'Redis 포트 번호',
|
||||
'redis_password' => 'Redis 비밀번호',
|
||||
'redis_database' => 'Redis 데이터베이스 번호',
|
||||
'memcached_host' => 'Memcached 호스트 주소',
|
||||
'memcached_port' => 'Memcached 포트 번호',
|
||||
's3_bucket' => 'S3 버킷명',
|
||||
's3_region' => 'S3 리전',
|
||||
's3_access_key' => 'S3 액세스 키',
|
||||
's3_secret_key' => 'S3 시크릿 키',
|
||||
's3_url' => 'S3 엔드포인트 URL',
|
||||
'ses_key' => 'SES 액세스 키',
|
||||
'ses_secret' => 'SES 시크릿 키',
|
||||
'ses_region' => 'SES 리전',
|
||||
'mailgun_domain' => 'Mailgun 도메인',
|
||||
'mailgun_secret' => 'Mailgun 시크릿 키',
|
||||
'mailgun_endpoint' => 'Mailgun 엔드포인트',
|
||||
'websocket_enabled' => 'WebSocket 사용 여부',
|
||||
'websocket_host' => 'WebSocket 호스트 주소',
|
||||
'websocket_port' => 'WebSocket 포트 번호',
|
||||
'websocket_scheme' => 'WebSocket 스킴 (http/https)',
|
||||
'websocket_app_key' => 'WebSocket 앱 키',
|
||||
];
|
||||
|
||||
/**
|
||||
* 파라미터 설명을 반환합니다. 없으면 null (호출자가 TODO 로 폴백).
|
||||
*
|
||||
* @param string $name 파라미터명
|
||||
* @param string $location 위치 (path/query/body)
|
||||
* @param string $type 타입 (integer/string/boolean/array...)
|
||||
* @return string|null 설명 (없으면 null)
|
||||
*/
|
||||
public function describe(string $name, string $location = '', string $type = ''): ?string
|
||||
{
|
||||
// sort_order / order 는 타입에 따라 의미가 갈린다:
|
||||
// - 문자열: 정렬 방향(asc/desc)
|
||||
// - 정수: 표시 정렬 순서 값(작을수록 우선 — 컬럼 값)
|
||||
if (in_array($name, ['sort_order', 'order'], true)) {
|
||||
return match ($type) {
|
||||
'integer', 'number' => '표시 정렬 순서 값 (작을수록 우선)',
|
||||
'string' => '정렬 방향 (asc 오름차순 / desc 내림차순)',
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
// status / type / category 는 query(목록 조회)에서만 필터 의미가 고정된다.
|
||||
// body(생성/수정)에서는 설정할 도메인 값이므로 의미가 도메인마다 달라
|
||||
// 사람 서술(TODO)로 남긴다.
|
||||
if (in_array($name, ['status', 'type', 'category'], true)) {
|
||||
if ($location !== 'query') {
|
||||
return null;
|
||||
}
|
||||
$label = ['status' => '상태', 'type' => '유형', 'category' => '분류'][$name];
|
||||
|
||||
return "{$label} 필터 (해당 {$label}의 항목만 조회)";
|
||||
}
|
||||
|
||||
if (isset(self::EXACT[$name])) {
|
||||
return self::EXACT[$name];
|
||||
}
|
||||
|
||||
// path 파라미터는 대부분 리소스 식별자 — 위치를 근거로 유추.
|
||||
if ($location === 'path') {
|
||||
return $this->describePathParam($name);
|
||||
}
|
||||
|
||||
return $this->byPattern($name, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* path 파라미터(리소스 식별자)의 설명을 유추합니다.
|
||||
*
|
||||
* @param string $name path 파라미터명
|
||||
* @return string|null 설명 (미매칭 시 null)
|
||||
*/
|
||||
private function describePathParam(string $name): ?string
|
||||
{
|
||||
// 순수 id / *_id / *Id: 대상 리소스의 식별자
|
||||
if ($name === 'id') {
|
||||
return '대상 리소스의 식별자';
|
||||
}
|
||||
if (Str::endsWith($name, '_id')) {
|
||||
$base = $this->humanize(Str::beforeLast($name, '_id'));
|
||||
|
||||
return "대상 {$base}의 식별자";
|
||||
}
|
||||
if (Str::endsWith($name, 'Id') && $name !== 'Id') {
|
||||
$base = $this->humanizeCamel(Str::beforeLast($name, 'Id'));
|
||||
|
||||
return "대상 {$base}의 식별자";
|
||||
}
|
||||
|
||||
// slug / identifier / hash / uuid: 리소스 지시 키
|
||||
if (in_array($name, ['slug', 'identifier', 'hash', 'uuid', 'code'], true)) {
|
||||
$labels = [
|
||||
'slug' => '대상 리소스의 slug (URL 친화 식별자)',
|
||||
'identifier' => '대상 리소스의 식별자',
|
||||
'hash' => '대상 리소스의 해시 식별자',
|
||||
'uuid' => '대상 리소스의 UUID',
|
||||
'code' => '대상 리소스의 코드',
|
||||
];
|
||||
|
||||
return $labels[$name];
|
||||
}
|
||||
|
||||
// *Name (templateName, pluginName, moduleName): 확장/리소스 이름 식별자
|
||||
if (Str::endsWith($name, 'Name') && $name !== 'Name') {
|
||||
$base = $this->humanizeCamel(Str::beforeLast($name, 'Name'));
|
||||
|
||||
return "대상 {$base}의 이름 (식별자)";
|
||||
}
|
||||
|
||||
// *Identifier (templateIdentifier 등): 확장/리소스 식별자
|
||||
if (Str::endsWith($name, 'Identifier') && $name !== 'Identifier') {
|
||||
$base = $this->humanizeCamel(Str::beforeLast($name, 'Identifier'));
|
||||
|
||||
return "대상 {$base}의 식별자";
|
||||
}
|
||||
|
||||
// bare 리소스명 path 파라미터: Laravel route-model binding 은
|
||||
// `/{user}`, `/{role}`, `/{definition}` 처럼 대상 모델의 단수형(또는
|
||||
// camelCase)을 그대로 세그먼트로 쓴다. 접미 패턴(_id/slug/*Id 등)에
|
||||
// 걸리지 않은 path 파라미터는 이 바인딩 대상 리소스의 식별자로 본다.
|
||||
// 예외: key/version 은 리소스가 아니라 설정 키/버전 값이므로 EXACT 폴백.
|
||||
$bareExact = [
|
||||
'key' => '대상 설정/항목의 키',
|
||||
'version' => '대상 버전 (버전 문자열)',
|
||||
];
|
||||
if (isset($bareExact[$name])) {
|
||||
return $bareExact[$name];
|
||||
}
|
||||
$base = str_contains($name, '_')
|
||||
? $this->humanize($name)
|
||||
: $this->humanizeCamel($name);
|
||||
|
||||
return "대상 {$base}의 식별자";
|
||||
}
|
||||
|
||||
/**
|
||||
* query/body 파라미터의 일관된 명명 규칙으로 설명을 유추합니다.
|
||||
*
|
||||
* @param string $name 파라미터명
|
||||
* @param string $type 타입
|
||||
* @return string|null 설명 (미매칭 시 null)
|
||||
*/
|
||||
private function byPattern(string $name, string $type): ?string
|
||||
{
|
||||
// identifier: 확장/리소스 지시 식별자 (query/body).
|
||||
// path 위치는 describePathParam 이 먼저 처리하므로 여기 도달하지 않는다.
|
||||
if ($name === 'identifier') {
|
||||
return '대상 확장/리소스의 식별자';
|
||||
}
|
||||
|
||||
// *_name: 확장/리소스 이름 식별자 (template_name/plugin_name/module_name/layout_name 등).
|
||||
// EXACT 의 recipient_name/from_name 은 여기 도달 전에 이미 처리된다.
|
||||
if (Str::endsWith($name, '_name')) {
|
||||
$base = $this->humanize(Str::beforeLast($name, '_name'));
|
||||
|
||||
return "{$base} 이름 (식별자)";
|
||||
}
|
||||
|
||||
// *_id: 연관 리소스 식별자 참조
|
||||
if (Str::endsWith($name, '_id')) {
|
||||
$base = $this->humanize(Str::beforeLast($name, '_id'));
|
||||
|
||||
return "{$base} 식별자";
|
||||
}
|
||||
|
||||
// *_ids: 연관 리소스 식별자 배열
|
||||
if (Str::endsWith($name, '_ids')) {
|
||||
$base = $this->humanize(Str::beforeLast($name, '_ids'));
|
||||
|
||||
return "{$base} 식별자 배열";
|
||||
}
|
||||
|
||||
// is_*/has_*: 불리언 토글
|
||||
if ((Str::startsWith($name, 'is_') || Str::startsWith($name, 'has_')) && $type === 'boolean') {
|
||||
$base = $this->humanize(Str::after($name, '_'));
|
||||
|
||||
return "{$base} 여부";
|
||||
}
|
||||
|
||||
// *_date: 날짜 값
|
||||
if (Str::endsWith($name, '_date')) {
|
||||
$base = $this->humanize(Str::beforeLast($name, '_date'));
|
||||
|
||||
return "{$base} 날짜";
|
||||
}
|
||||
|
||||
// *_at: 일시 값
|
||||
if (Str::endsWith($name, '_at')) {
|
||||
$base = $this->humanize(Str::beforeLast($name, '_at'));
|
||||
|
||||
return "{$base} 일시";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* snake_case 를 사람이 읽는 문구로 변환합니다.
|
||||
*
|
||||
* @param string $token snake_case 토큰
|
||||
* @return string 공백 구분 문구
|
||||
*/
|
||||
private function humanize(string $token): string
|
||||
{
|
||||
return str_replace('_', ' ', $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* camelCase 를 사람이 읽는 문구로 변환합니다.
|
||||
*
|
||||
* @param string $token camelCase 토큰
|
||||
* @return string 공백 구분 소문자 문구
|
||||
*/
|
||||
private function humanizeCamel(string $token): string
|
||||
{
|
||||
return Str::lower(trim(preg_replace('/([A-Z])/', ' $1', $token)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support\ApiDoc;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* 리소스 계약 필드 설명기
|
||||
*
|
||||
* 컬럼 주석이 없는 accessor/computed 필드(Resource 의 toArray() 가 파생하는 값)의
|
||||
* 설명을 제공합니다. G7 전역에서 의미가 표준화된 필드(BaseApiResource 의 is_owner /
|
||||
* abilities, Enum 파생 status_label / status_variant, User::isAdmin() 등)와, 일관된
|
||||
* 파생 규칙(_label / _variant / _flag / _name / is_* / *_at 접미·접두)을 코드에서
|
||||
* 확인된 의미 그대로 서술합니다.
|
||||
*
|
||||
* 우선순위: 이 계약 사전은 컬럼 주석보다 앞섭니다 — created_at 은 어느 테이블이든
|
||||
* "생성 일시" 이고, status_label 은 컬럼이 아니라 Enum label() 산물이기 때문입니다.
|
||||
*/
|
||||
class ResourceFieldDescriber
|
||||
{
|
||||
/**
|
||||
* @var array<string, string> 정확 필드명 => 설명 (BaseApiResource/공통 Resource 계약)
|
||||
*/
|
||||
private const EXACT = [
|
||||
// BaseApiResource 표준 메타 (resourceMeta)
|
||||
'is_owner' => '현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타)',
|
||||
'abilities' => '현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반)',
|
||||
|
||||
// 공통 식별/타임스탬프
|
||||
'id' => '기본 키 (내부 식별자)',
|
||||
'uuid' => '외부 노출용 UUID (URL/API 식별자, 내부 id 비노출)',
|
||||
'created_at' => '생성 일시',
|
||||
'updated_at' => '최종 수정 일시',
|
||||
'deleted_at' => '소프트 삭제 일시 (미삭제 시 null)',
|
||||
|
||||
// 공통 콘텐츠/표시 필드 (도메인 무관하게 역할이 고정 — 요청 파라미터
|
||||
// ParameterDescriber 의 name/title/content/description 대응물).
|
||||
// 근거: 실측 시 board 게시글·category·brand·notification 등 전 도메인에서
|
||||
// 동일 역할(명칭/제목/본문/설명)로 관측. 다국어(object)/문자열 무관.
|
||||
'name' => '대상의 이름/명칭 (다국어 필드는 로케일별 값 객체)',
|
||||
'title' => '제목',
|
||||
'content' => '본문 내용',
|
||||
'description' => '설명 (다국어 필드는 로케일별 값 객체)',
|
||||
'slug' => 'URL 친화 식별자 (slug)',
|
||||
'label' => '표시용 라벨',
|
||||
'icon' => '아이콘 식별자 (아이콘 클래스/이름)',
|
||||
'thumbnail' => '썸네일 이미지 URL/경로',
|
||||
'ip_address' => '요청/행위가 발생한 IP 주소',
|
||||
|
||||
// User 계약 파생 필드 (UserResource)
|
||||
'status_label' => '상태의 사람이 읽는 라벨 (상태 Enum label() 산물)',
|
||||
'status_variant' => '상태 표시 색상/스타일 변형 키 (상태 Enum variant() 산물 — UI 배지용)',
|
||||
'language_label' => '언어 코드의 현지화 라벨 (user.language.{code} 번역)',
|
||||
'country_flag' => '국가 코드의 국기 이모지 (country 값에서 파생)',
|
||||
'country_name' => '국가 코드의 현지화 국가명 (country 값에서 파생)',
|
||||
'is_admin' => '관리자 역할 보유 여부 (User::isAdmin() — 역할 관계 기반 파생)',
|
||||
|
||||
// 확장 상태 계약 필드 (ModuleResource/PluginResource/TemplateResource)
|
||||
'is_bundled' => '코어에 선탑재된 번들 확장인지 여부',
|
||||
'is_pending' => '_pending 대기소에 있어 설치 대기 중인지 여부',
|
||||
'update_available' => '최신 버전 대비 업데이트 가능 여부',
|
||||
'update_source' => '업데이트 감지 출처 (github, bundled 등)',
|
||||
'latest_version' => '감지된 최신 배포 버전',
|
||||
'file_version' => '설치된 파일의 manifest 버전',
|
||||
'incompatible_required_version' => '요구 코어 버전 미충족 시 필요한 버전 (호환되면 null)',
|
||||
'status_variant_label' => '상태 표시용 라벨/변형',
|
||||
'dependencies' => '의존하는 확장 맵 (manifest 파생 — {modules, plugins})',
|
||||
'assets' => '프론트엔드 에셋 매니페스트 (manifest 파생 — js/css 진입점·로딩 전략)',
|
||||
|
||||
// 관계/연관 객체 (여러 Resource 에서 동일 계약)
|
||||
'creator' => '생성자 정보 객체 (uuid/name/email — creator 관계 파생)',
|
||||
'children' => '하위 항목 배열 (계층 트리 — children 관계 파생)',
|
||||
'parent' => '상위 항목 객체 (parent 관계 파생)',
|
||||
'permissions' => '연결된 권한 목록 (id/identifier/name — 역할 경유 권한 관계 파생)',
|
||||
'recipient' => '수신자 사용자 객체 (uuid/name/email — recipientUser 관계 파생)',
|
||||
'sender' => '발신자 사용자 객체 (uuid/name/email — senderUser 관계 파생)',
|
||||
'author' => '작성자 사용자 객체 (uuid/name — author 관계 파생)',
|
||||
'actor_name' => '행위를 수행한 주체(사용자/시스템)의 이름',
|
||||
|
||||
// 시스템/집계 공통 (DashboardService/UserRepository/SettingsService)
|
||||
'total' => '전체 개수 (집계)',
|
||||
'total_users' => '전체 사용자 수 (통계 객체는 count/추이 포함)',
|
||||
'time' => '상대 시각 표시 (예: "24초 전" — diffForHumans() 산물)',
|
||||
'server_time' => '서버 현재 시각 (Y-m-d H:i:s)',
|
||||
'number' => '목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생)',
|
||||
|
||||
// 로케일 (TemplateResource/LocaleController)
|
||||
'locales' => '활성 로케일 코드 배열',
|
||||
'locale_names' => '로케일 코드별 표시명 맵 (config app.locale_names)',
|
||||
|
||||
// 확장/버전 공통 (Module/Plugin/Template/LanguagePack Resource, 확장 Manager)
|
||||
'extension_type' => '이 리소스를 소유한 확장의 타입 (core/module/plugin/template)',
|
||||
'extension_identifier' => '이 리소스를 소유한 확장의 식별자',
|
||||
'extension_name' => '이 리소스를 소유한 확장의 표시 이름 (manifest name)',
|
||||
'github_url' => 'GitHub 저장소 URL (manifest 파생)',
|
||||
'github_changelog_url' => 'GitHub 변경 이력(CHANGELOG) URL (manifest 파생)',
|
||||
'changelog' => '변경 이력 텍스트 (원격/파일 CHANGELOG 본문)',
|
||||
'current_core_version' => '현재 설치된 코어 버전',
|
||||
'installed_modules' => '설치된 모듈 집계 객체 (total/active)',
|
||||
'installed_templates' => '설치된 템플릿 집계 객체 (total/active)',
|
||||
'active_plugins' => '활성 플러그인 집계 객체 (total/active)',
|
||||
'bundled_identifier' => '대응하는 번들 확장 식별자 (번들 원본 매칭용)',
|
||||
'origin' => '출처 (설치/등록 원천 구분 값)',
|
||||
'target_name' => '대상 확장의 표시 이름 (scope+target_identifier 로 해석)',
|
||||
'install_blocked_reason' => '설치가 차단된 사유 (차단 없으면 null)',
|
||||
];
|
||||
|
||||
/**
|
||||
* 필드명에 대한 설명을 반환합니다. 없으면 null (호출자가 컬럼 주석/TODO 로 폴백).
|
||||
*
|
||||
* @param string $field 필드명
|
||||
* @param string $type 실측 타입 (boolean/integer/string/object/array...)
|
||||
* @return string|null 설명 (없으면 null)
|
||||
*/
|
||||
public function describe(string $field, string $type = ''): ?string
|
||||
{
|
||||
// sort_order 는 응답에서 표시 정렬 순서 값(정수 컬럼)으로 고정된다.
|
||||
// 문자열이면 정렬 방향일 수 있어 도메인 특이 → TODO 유지.
|
||||
// (ParameterDescriber 의 sort_order 타입 분기와 동일 계약)
|
||||
if ($field === 'sort_order') {
|
||||
return in_array($type, ['integer', 'number'], true)
|
||||
? '표시 정렬 순서 값 (작을수록 우선)'
|
||||
: null;
|
||||
}
|
||||
|
||||
if (isset(self::EXACT[$field])) {
|
||||
return self::EXACT[$field];
|
||||
}
|
||||
|
||||
return $this->byPattern($field, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 일관된 파생 규칙(접미/접두 패턴)으로 설명을 유추합니다.
|
||||
*
|
||||
* @param string $field 필드명
|
||||
* @param string $type 실측 타입
|
||||
* @return string|null 설명 (패턴 미매칭 시 null)
|
||||
*/
|
||||
private function byPattern(string $field, string $type): ?string
|
||||
{
|
||||
// *_at: 타임스탬프 (UI 포맷 문자열 또는 ISO)
|
||||
if (Str::endsWith($field, '_at')) {
|
||||
$base = $this->humanize(Str::beforeLast($field, '_at'));
|
||||
|
||||
return "{$base} 일시";
|
||||
}
|
||||
|
||||
// *_formatted: 원본 값을 사람이 읽는 문자열로 포맷한 표시용 파생 필드
|
||||
// (근거: size_formatted accessor, formatCurrencyPrice/formatFileSize/
|
||||
// formatCreatedAtFormat — 통화·용량·일시 등을 로케일/단위 포맷). 도메인
|
||||
// 무관하게 "`base` 값의 표시용 포맷 문자열" 로 의미가 고정된다.
|
||||
if (Str::endsWith($field, '_formatted')) {
|
||||
$base = Str::beforeLast($field, '_formatted');
|
||||
|
||||
return "`{$base}` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷)";
|
||||
}
|
||||
|
||||
// *_label: 원본 값의 현지화 라벨 (Enum label() 또는 번역)
|
||||
if (Str::endsWith($field, '_label')) {
|
||||
$base = Str::beforeLast($field, '_label');
|
||||
|
||||
return "`{$base}` 값의 사람이 읽는 라벨 (현지화/Enum 파생)";
|
||||
}
|
||||
|
||||
// *_variant: UI 배지 색상/스타일 변형 키
|
||||
if (Str::endsWith($field, '_variant')) {
|
||||
$base = Str::beforeLast($field, '_variant');
|
||||
|
||||
return "`{$base}` 값의 표시 변형 키 (UI 배지 색상/스타일)";
|
||||
}
|
||||
|
||||
// can_*: abilities 맵 내부 능력 불리언
|
||||
if (Str::startsWith($field, 'can_')) {
|
||||
$action = $this->humanize(Str::after($field, 'can_'));
|
||||
|
||||
return "{$action} 수행 가능 여부 (권한 기반)";
|
||||
}
|
||||
|
||||
// is_*/has_*: 불리언 상태 플래그
|
||||
if ((Str::startsWith($field, 'is_') || Str::startsWith($field, 'has_')) && $type === 'boolean') {
|
||||
$base = $this->humanize(Str::after($field, '_'));
|
||||
|
||||
return "{$base} 여부";
|
||||
}
|
||||
|
||||
// *_count: 집계 개수
|
||||
if (Str::endsWith($field, '_count') && in_array($type, ['integer', 'number'], true)) {
|
||||
$base = $this->humanize(Str::beforeLast($field, '_count'));
|
||||
|
||||
return "{$base} 개수 (집계)";
|
||||
}
|
||||
|
||||
// *_raw: 다국어/현지화 이전 원본 값 (getValue 로 로케일 미해석 원본 반환)
|
||||
// 예: name_raw = name 의 원본, description_raw = description 의 원본
|
||||
if (Str::endsWith($field, '_raw')) {
|
||||
$base = Str::beforeLast($field, '_raw');
|
||||
|
||||
return "`{$base}` 의 원본 값 (현재 로케일 미해석 원본 JSON/문자열)";
|
||||
}
|
||||
|
||||
// localized_* / *_localized: 다국어 필드를 현재 로케일로 해석한 표시용 값
|
||||
// (근거: getLocalizedName() / getLocalizedOptionName() 등 — 다국어 JSON 을
|
||||
// 현재 로케일 문자열로 해석). 도메인 무관 파생 규칙.
|
||||
if (Str::startsWith($field, 'localized_')) {
|
||||
$base = $this->humanize(Str::after($field, 'localized_'));
|
||||
|
||||
return "`{$base}` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석)";
|
||||
}
|
||||
if (Str::endsWith($field, '_localized')) {
|
||||
$base = $this->humanize(Str::beforeLast($field, '_localized'));
|
||||
|
||||
return "`{$base}` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석)";
|
||||
}
|
||||
|
||||
// *_url: 리소스에 접근하는 URL (썸네일/다운로드/이미지 등)
|
||||
// (근거: thumbnail_url => download_url / getThumbnailUrl()). 도메인 무관.
|
||||
if (Str::endsWith($field, '_url')) {
|
||||
$base = $this->humanize(Str::beforeLast($field, '_url'));
|
||||
|
||||
return "{$base} URL";
|
||||
}
|
||||
|
||||
// *_id: 연관 리소스를 참조하는 정수/UUID 식별자 (parent_id/user_id/loggable_id 등).
|
||||
// *_ids: 연관 리소스 식별자 배열.
|
||||
// 예외: login_id 는 참조 식별자가 아니라 로그인 계정 아이디(문자열)이므로 제외
|
||||
// (도메인 특이 → TODO 유지).
|
||||
if (Str::endsWith($field, '_ids')) {
|
||||
$base = $this->humanize(Str::beforeLast($field, '_ids'));
|
||||
|
||||
return "{$base} 식별자 배열 (연관 리소스 참조)";
|
||||
}
|
||||
if (Str::endsWith($field, '_id') && ! Str::endsWith($field, 'login_id')) {
|
||||
$base = $this->humanize(Str::beforeLast($field, '_id'));
|
||||
|
||||
return "{$base} 식별자 (연관 리소스 참조)";
|
||||
}
|
||||
|
||||
// depth: 계층 트리에서의 깊이 (0 = 최상위). children/parent 트리 파생 필드로
|
||||
// 도메인 무관하게 의미가 고정된다 (근거: CommentResource/CategoryResource depth).
|
||||
if ($field === 'depth' && in_array($type, ['integer', 'number'], true)) {
|
||||
return '계층 트리에서의 깊이 (0 = 최상위, 하위로 갈수록 증가)';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* snake_case 를 사람이 읽는 문구로 변환합니다.
|
||||
*
|
||||
* @param string $token snake_case 토큰
|
||||
* @return string 공백 구분 문구
|
||||
*/
|
||||
private function humanize(string $token): string
|
||||
{
|
||||
return str_replace('_', ' ', $token);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support\ApiDoc;
|
||||
|
||||
/**
|
||||
* 응답 스키마 추론기
|
||||
*
|
||||
* 실측한 응답 JSON(ResponseHelper envelope)에서 data 내부의 필드 스키마를
|
||||
* 추론합니다. 각 필드의 타입과 샘플값을 문서용 메타데이터로 변환합니다.
|
||||
*/
|
||||
class ResponseSchemaInferrer
|
||||
{
|
||||
/**
|
||||
* envelope 응답 body 에서 data 필드 스키마를 추론합니다.
|
||||
*
|
||||
* @param array<string, mixed> $body 실측 응답 body (envelope)
|
||||
* @return array{envelope: array<int, string>, shape: string, fields: array<int, array<string, mixed>>, pagination: bool}
|
||||
*/
|
||||
public function infer(array $body): array
|
||||
{
|
||||
$envelope = array_keys($body);
|
||||
$data = $body['data'] ?? null;
|
||||
|
||||
// 목록 응답: data.data 가 배열 (BaseApiCollection)
|
||||
if (is_array($data) && isset($data['data']) && is_array($data['data'])) {
|
||||
$rows = array_values(array_filter($data['data'], 'is_array'));
|
||||
|
||||
return [
|
||||
'envelope' => $envelope,
|
||||
'shape' => 'collection',
|
||||
'fields' => $this->fieldsFromRows($rows),
|
||||
'pagination' => isset($data['pagination']),
|
||||
];
|
||||
}
|
||||
|
||||
// 단건 응답: data 가 연관 배열
|
||||
if (is_array($data) && $this->isAssoc($data)) {
|
||||
return [
|
||||
'envelope' => $envelope,
|
||||
'shape' => 'object',
|
||||
'fields' => $this->fieldsFromRow($data),
|
||||
'pagination' => false,
|
||||
];
|
||||
}
|
||||
|
||||
// data 가 순수 배열(목록만)
|
||||
if (is_array($data) && ! $this->isAssoc($data) && isset($data[0]) && is_array($data[0])) {
|
||||
$rows = array_values(array_filter($data, 'is_array'));
|
||||
|
||||
return [
|
||||
'envelope' => $envelope,
|
||||
'shape' => 'array',
|
||||
'fields' => $this->fieldsFromRows($rows),
|
||||
'pagination' => false,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'envelope' => $envelope,
|
||||
'shape' => 'scalar',
|
||||
'fields' => [],
|
||||
'pagination' => false,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 한 행(row)에서 필드별 타입·샘플값을 추출합니다.
|
||||
*
|
||||
* @param array<string, mixed> $row 응답 데이터 한 행
|
||||
* @return array<int, array<string, mixed>> 필드 메타데이터 목록
|
||||
*/
|
||||
private function fieldsFromRow(array $row): array
|
||||
{
|
||||
$fields = [];
|
||||
|
||||
foreach ($row as $key => $value) {
|
||||
$fields[] = [
|
||||
'name' => (string) $key,
|
||||
'type' => $this->typeOf($value),
|
||||
'sample' => $this->sampleOf($value),
|
||||
];
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 여러 행을 병합해 필드별로 non-null 대표 샘플과 실제 타입을 선택합니다.
|
||||
*
|
||||
* 첫 행이 우연히 비어있어(null) "항상 null" 처럼 보이는 문제를 방지하기 위해,
|
||||
* 각 필드에서 값이 채워진 행을 우선 채택합니다.
|
||||
*
|
||||
* @param array<int, array<string, mixed>> $rows 응답 데이터 행 목록
|
||||
* @return array<int, array<string, mixed>> 필드 메타데이터 목록
|
||||
*/
|
||||
private function fieldsFromRows(array $rows): array
|
||||
{
|
||||
if ($rows === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 첫 행의 키 순서를 기준으로 필드 목록 확정
|
||||
$keys = array_keys($rows[0]);
|
||||
$fields = [];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$chosenValue = null;
|
||||
$chosenType = 'null';
|
||||
|
||||
foreach ($rows as $row) {
|
||||
if (! array_key_exists($key, $row)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $row[$key];
|
||||
$type = $this->typeOf($value);
|
||||
|
||||
// 값이 채워진(non-null) 첫 행을 대표로 채택하고 탐색 종료
|
||||
if ($type !== 'null') {
|
||||
$chosenValue = $value;
|
||||
$chosenType = $type;
|
||||
break;
|
||||
}
|
||||
|
||||
// 아직 non-null 을 못 찾았으면 null 이라도 후보로 유지
|
||||
$chosenValue = $value;
|
||||
}
|
||||
|
||||
$fields[] = [
|
||||
'name' => (string) $key,
|
||||
'type' => $chosenType,
|
||||
'sample' => $this->sampleOf($chosenValue),
|
||||
];
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 값의 JSON 타입을 판별합니다.
|
||||
*
|
||||
* @param mixed $value 값
|
||||
* @return string 타입 문자열
|
||||
*/
|
||||
private function typeOf(mixed $value): string
|
||||
{
|
||||
return match (true) {
|
||||
is_bool($value) => 'boolean',
|
||||
is_int($value) => 'integer',
|
||||
is_float($value) => 'number',
|
||||
is_string($value) => 'string',
|
||||
is_null($value) => 'null',
|
||||
is_array($value) && $this->isAssoc($value) => 'object',
|
||||
is_array($value) => 'array',
|
||||
default => 'mixed',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 값의 샘플 표현을 반환합니다 (문서 표에 표시할 축약형).
|
||||
*
|
||||
* @param mixed $value 값
|
||||
* @return string 샘플 표현 (마크다운 표 셀 안전)
|
||||
*/
|
||||
private function sampleOf(mixed $value): string
|
||||
{
|
||||
if (is_bool($value)) {
|
||||
return $value ? 'true' : 'false';
|
||||
}
|
||||
|
||||
if (is_null($value)) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
$encoded = json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||
$encoded = (string) $encoded;
|
||||
|
||||
if (mb_strlen($encoded) > 60) {
|
||||
$encoded = mb_substr($encoded, 0, 57).'…';
|
||||
}
|
||||
|
||||
return $this->escapeCell($encoded);
|
||||
}
|
||||
|
||||
$str = (string) $value;
|
||||
|
||||
if (mb_strlen($str) > 40) {
|
||||
$str = mb_substr($str, 0, 37).'…';
|
||||
}
|
||||
|
||||
return $this->escapeCell($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 마크다운 표 셀 안에서 안전하도록 파이프/개행을 이스케이프합니다.
|
||||
*
|
||||
* @param string $text 원본 텍스트
|
||||
* @return string 이스케이프된 텍스트
|
||||
*/
|
||||
private function escapeCell(string $text): string
|
||||
{
|
||||
return str_replace(['|', "\n", "\r"], ['\\|', ' ', ''], $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 배열이 연관 배열(맵)인지 판별합니다.
|
||||
*
|
||||
* @param array<mixed> $arr 배열
|
||||
* @return bool 연관 배열 여부
|
||||
*/
|
||||
private function isAssoc(array $arr): bool
|
||||
{
|
||||
if ($arr === []) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array_keys($arr) !== range(0, count($arr) - 1);
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,13 @@
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\UserStatus;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||
* @extends Factory<User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
@@ -49,4 +50,37 @@ class UserFactory extends Factory
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 모든 프로필 필드가 채워진 완전한 상태를 만듭니다.
|
||||
*
|
||||
* API 문서 실측 시 응답 필드의 예시값이 null 이 되지 않도록, 모델 로직상
|
||||
* 유효한 값으로 nullable 프로필 컬럼을 전수 채웁니다.
|
||||
* (language=지원 로케일, country=ISO alpha-2, status=UserStatus enum 등)
|
||||
*/
|
||||
public function complete(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'nickname' => fake()->userName(),
|
||||
'language' => 'ko',
|
||||
'timezone' => 'Asia/Seoul',
|
||||
'country' => 'KR',
|
||||
'homepage' => 'https://example.com',
|
||||
'mobile' => '010-'.fake()->numerify('####-####'),
|
||||
'phone' => '02-'.fake()->numerify('###-####'),
|
||||
'zipcode' => fake()->numerify('#####'),
|
||||
'address' => fake()->address(),
|
||||
'address_detail' => fake()->numerify('##동 ###호'),
|
||||
'signature' => fake()->sentence(),
|
||||
'bio' => fake()->paragraph(),
|
||||
// avatar 는 users 테이블 컬럼이 아니라 avatarAttachment 관계에서 파생되는
|
||||
// accessor(getAvatarUrl) 이므로 factory 에서 직접 세팅하지 않는다.
|
||||
'admin_memo' => fake()->sentence(),
|
||||
'ip_address' => fake()->ipv4(),
|
||||
'last_login_at' => now()->subDays(1),
|
||||
'identity_verified_at' => now()->subDays(5),
|
||||
'mobile_verified_at' => now()->subDays(5),
|
||||
'failed_login_attempts' => 0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -9,7 +9,7 @@
|
||||
|
||||
| 카테고리 | 문서 수 | 링크 상태 |
|
||||
|----------|---------|----------|
|
||||
| [백엔드](backend/) | 32개 | 정상 |
|
||||
| [백엔드](backend/) | 33개 | 정상 |
|
||||
| [프론트엔드](frontend/) | 51개 | 정상 |
|
||||
| [확장 시스템](extension/) | 31개 | 정상 |
|
||||
| 공통 | 20개 | 정상 |
|
||||
@@ -113,13 +113,14 @@
|
||||
<!-- AUTO-GENERATED-START: docs-readme-full-list -->
|
||||
## 카테고리별 전체 문서 목록
|
||||
|
||||
### 백엔드 (32개)
|
||||
### 백엔드 (33개)
|
||||
|
||||
| 문서 | 제목 |
|
||||
|------|------|
|
||||
| [activity-log-hooks.md](backend/activity-log-hooks.md) | 활동 로그 훅 레퍼런스 (Activity Log Hooks Reference) |
|
||||
| [activity-log.md](backend/activity-log.md) | 활동 로그 시스템 (Activity Log System) |
|
||||
| [admin-settings-access.md](backend/admin-settings-access.md) | Admin 환경설정 값 접근 (`g7_core_settings` vs `config()`) |
|
||||
| [api-documentation.md](backend/api-documentation.md) | API 레퍼런스 문서 규정 (API Documentation) |
|
||||
| [api-resources.md](backend/api-resources.md) | API 리소스 |
|
||||
| [authentication.md](backend/authentication.md) | 인증 및 세션 처리 |
|
||||
| [broadcasting.md](backend/broadcasting.md) | Broadcasting (실시간 이벤트) |
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
| [activity-log-hooks.md](activity-log-hooks.md) | 활동 로그 훅 레퍼런스 (Activity Log Hooks Reference) | 코어 66훅 + 이커머스 92훅 + 게시판 32훅 + 페이지 8훅 = 총 198훅 |
|
||||
| [activity-log.md](activity-log.md) | 활동 로그 시스템 (Activity Log System) | Monolog 기반: Service 훅 → Listener → Log::channel... |
|
||||
| [admin-settings-access.md](admin-settings-access.md) | Admin 환경설정 값 접근 (`g7_core_settings` vs `config()`) | 동기화 SSoT: storage/app/settings/*.json → Setting... |
|
||||
| [api-documentation.md](api-documentation.md) | API 레퍼런스 문서 규정 (API Documentation) | 모든 API 엔드포인트는 레퍼런스 문서 필수 — 메서드/URI/파라미터/응답 필드 전... |
|
||||
| [api-resources.md](api-resources.md) | API 리소스 | Resource: BaseApiResource 상속 필수 / Collection: B... |
|
||||
| [authentication.md](authentication.md) | 인증 및 세션 처리 | Laravel Sanctum 토큰 전용 인증 (Bearer 토큰만 사용) |
|
||||
| [broadcasting.md](broadcasting.md) | Broadcasting (실시간 이벤트) | Laravel Reverb 사용 (WebSocket) |
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
# API 레퍼런스 문서 규정 (API Documentation)
|
||||
|
||||
> **관련 문서**: [routing.md](routing.md) | [api-resources.md](api-resources.md) | [response-helper.md](response-helper.md) | [validation.md](validation.md)
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 모든 API 엔드포인트는 레퍼런스 문서 필수 — 메서드/URI/파라미터/응답 필드 전수 기재
|
||||
2. 위치: 코어 = docs/backend/api/, 확장 = {modules|plugins}/_bundled/{id}/docs/api/
|
||||
3. 생성: php artisan api:docgen — 코드에서 추출한 스캐폴딩 + 사람이 서술 보강 (순수 수기 금지)
|
||||
4. 추출 불가분(훅 주입 파라미터·동적 응답)은 <!-- TODO --> 마커 남기고 사람이 채움
|
||||
5. Swagger/OpenAPI 도구 미사용 — 마크다운 레퍼런스 전용
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 목차
|
||||
|
||||
1. [왜 이 규정이 필요한가](#왜-이-규정이-필요한가)
|
||||
2. [문서 위치 규칙](#문서-위치-규칙)
|
||||
3. [표준 문서 포맷](#표준-문서-포맷)
|
||||
4. [생성 커맨드 api:docgen](#생성-커맨드-apidocgen)
|
||||
5. [문서 갱신 의무](#문서-갱신-의무)
|
||||
6. [체크리스트](#체크리스트)
|
||||
|
||||
---
|
||||
|
||||
## 왜 이 규정이 필요한가
|
||||
|
||||
G7 의 REST API 는 라우트 `->name()` 규약은 있으나 엔드포인트별 공개 레퍼런스가 부재했다. 프론트엔드
|
||||
(레이아웃 JSON `data_sources`)와 외부 통합 개발자가 소비하는 요청/응답 계약이 코드에만 존재해, 변경 시
|
||||
소비처가 침묵 속에서 깨진다(이슈 #64 의 `data_source` `auth_required` 계약 변화 사고가 계기).
|
||||
|
||||
문서는 **코드에서 추출한 스캐폴딩 + 사람이 채운 서술의 하이브리드**로 유지한다. 674개 규모에서 완전 수기
|
||||
문서는 반드시 drift 하고, 완전 자동 추출은 훅 주입 파라미터·동적 응답을 못 잡으므로 둘 다 단독으로는
|
||||
불충분하다.
|
||||
|
||||
---
|
||||
|
||||
## 문서 위치 규칙
|
||||
|
||||
| 대상 | 문서 위치 | 예시 |
|
||||
|------|----------|------|
|
||||
| 코어 | `docs/backend/api/{도메인}.md` | `docs/backend/api/users.md` |
|
||||
| 모듈 | `modules/_bundled/{id}/docs/api/{도메인}.md` | `modules/_bundled/sirsoft-ecommerce/docs/api/products.md` |
|
||||
| 플러그인 | `plugins/_bundled/{id}/docs/api/{도메인}.md` | `plugins/_bundled/sirsoft-gdpr/docs/api/consents.md` |
|
||||
|
||||
확장 API 문서는 **확장이 소유**한다(코어에 모으지 않음). 확장을 배포/삭제하면 그 API 문서도 함께 이동한다.
|
||||
|
||||
도메인 그룹핑은 URI/라우트명 prefix 기준(`api.admin.users.*` → `users.md`)으로 커맨드가 자동 분류한다.
|
||||
|
||||
---
|
||||
|
||||
## 표준 문서 포맷
|
||||
|
||||
엔드포인트 1개당 아래 4개 구성(헤더 · 요청 파라미터 · 응답 필드 · 에러 응답)을 따른다.
|
||||
`<!-- @generated:start -->` ~ `<!-- @generated:end -->` 사이는 `api:docgen` 이 재생성하는 추출 블록이며,
|
||||
그 바깥의 사람 서술은 재생성 시 보존된다.
|
||||
|
||||
에러 응답 표는 라우트 메타에서 대표 상태코드를 자동 추론한다: 인증 필수(`auth:sanctum`)→401,
|
||||
`admin`/`permission:` 요구→403, FormRequest 검증 규칙 존재→422, path 파라미터 존재→404.
|
||||
`optional.sanctum`(선택 인증)은 401 을 유발하지 않는다. 도메인 특이 에러(409·429 등)는 사람이 보강한다.
|
||||
|
||||
```markdown
|
||||
### GET /api/admin/users
|
||||
<!-- @generated:start:api.admin.users.index -->
|
||||
- **라우트명**: `api.admin.users.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\UserController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `admin` + `permission:admin,core.users.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
|------|------|------|------|--------|------|
|
||||
| keyword | query | string | 아니오 | — | <!-- TODO: 용도 --> |
|
||||
| status | query | string | 아니오 | `active`, `dormant`, `withdrawn` | <!-- TODO: 용도 --> |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있음 (`core.user.search_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
| 필드 | 타입 | 용도/설명 |
|
||||
|------|------|-----------|
|
||||
| id | integer | <!-- TODO: 설명 --> |
|
||||
| uuid | string | <!-- TODO: 설명 --> |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`admin,core.users.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** <!-- 사람이 작성: 이 엔드포인트의 용도, 주의사항, 예시 시나리오 -->
|
||||
|
||||
**응답 예시**
|
||||
|
||||
```json
|
||||
{ "success": true, "data": { }, "message": null, "error": null }
|
||||
```
|
||||
```
|
||||
|
||||
### 응답 envelope 표준
|
||||
|
||||
모든 응답은 `ResponseHelper` 로 `{success, data, message, error}` 로 래핑된다(response-helper.md).
|
||||
문서의 "응답 필드" 표는 이 envelope 의 `data` 내부 필드를 기재한다.
|
||||
|
||||
- 목록 응답 pagination: `BaseApiCollection::paginationMeta()` →
|
||||
`{current_page, last_page, per_page, total, from, to, has_more_pages}`
|
||||
- 권한 메타: `BaseApiResource::resourceMeta()` → `is_owner` + `abilities.can_*`
|
||||
|
||||
### 파라미터 위치 판정
|
||||
|
||||
| 위치 | 판정 근거 |
|
||||
|------|----------|
|
||||
| `path` | URI 의 `{param}` 세그먼트 |
|
||||
| `query` | GET/DELETE 요청의 FormRequest rule |
|
||||
| `body` | POST/PUT/PATCH 요청의 FormRequest rule |
|
||||
|
||||
허용값은 FormRequest rule 의 `in:`, `max:`, `min:`, `Rule::in(...)`, `boolean`, `date` 등에서 유추한다.
|
||||
|
||||
---
|
||||
|
||||
## 생성 커맨드 api:docgen
|
||||
|
||||
```bash
|
||||
# 코어 스캐폴딩 생성 (docs/backend/api/*.md)
|
||||
php artisan api:docgen --scope=core
|
||||
|
||||
# 특정 확장 스캐폴딩 생성
|
||||
php artisan api:docgen --scope=module:sirsoft-ecommerce
|
||||
php artisan api:docgen --scope=plugin:sirsoft-gdpr
|
||||
|
||||
# 전체
|
||||
php artisan api:docgen --scope=all
|
||||
|
||||
# 생성 없이 누락/drift 만 리포트 (하네스가 소비)
|
||||
php artisan api:docgen --check
|
||||
|
||||
# 생성될 대상만 미리보기
|
||||
php artisan api:docgen --scope=core --dry-run
|
||||
```
|
||||
|
||||
동작 (실측 기반):
|
||||
|
||||
1. `route:list --json` 으로 API 라우트 전수 수집 (method·uri·name·middleware·action).
|
||||
2. name prefix 로 소유 확장 판별 (`api.modules.{id}.*` / `api.plugins.{id}.*` / 그 외 코어) → 출력 파일 라우팅.
|
||||
3. 컨트롤러 메서드의 FormRequest 타입힌트 → `rules()` 리플렉션 → 요청 파라미터 표 (타입·필수·허용값).
|
||||
4. **실측**: 임시 Sanctum 토큰 발급 → 실제 요청 파라미터로 엔드포인트 호출 → **실제 응답 JSON** 관측.
|
||||
- GET/HEAD: 실호출(read-only). 목록이 비면 최소 시드 데이터 자동 생성 후 재호출.
|
||||
- 쓰기(POST/PUT/PATCH/DELETE): DB 트랜잭션 내 실행 후 롤백(응답 shape 만 관측, 영속 안 함).
|
||||
- 외부 부수효과(결제 PG·외부 인증 콜백·메일)가 있는 라우트: allowlist 로 실호출 제외 → 정적+예시 대체.
|
||||
5. 실제 응답 JSON 의 키·타입·샘플값 → 응답 필드 표 + 응답 예시. `@generated` 블록만 갱신, 사람 서술 보존.
|
||||
6. 실측 후 임시 토큰·시드 데이터 정리.
|
||||
|
||||
한계 / 보강:
|
||||
|
||||
- FormRequest 가 `HookManager::applyFilters` 로 규칙을 주입하는 경우(163개) 정적 리플렉션은 훅 주입분을
|
||||
못 읽는다 → 커맨드가 훅 필터 존재 시 주석을 남기고 사람이 보강. 단 **응답 필드는 실측이므로 훅으로
|
||||
병합된 응답 필드까지 실제로 포착**된다.
|
||||
- `route:list`(=`RouteFacade::getRoutes()`)는 활성 확장만 노출한다. 명시 범위(`module:{id}`/`plugin:{id}`)로
|
||||
지정한 확장이 비활성/미설치여서 등록 라우트가 0건이면, 인벤토리가 그 확장의 번들 라우트 파일
|
||||
(`{modules|plugins}/_bundled/{id}/src/routes/api.php`)을 프로바이더와 동일한 prefix
|
||||
(`api/{modules|plugins}/{id}`)·name(`api.{modules|plugins}.{id}.`)·`api` 미들웨어 규약으로 로드해
|
||||
**정적 폴백 수집**한다. 이때 실측(HTTP 호출)은 불가하므로 응답 필드는 `<!-- 실측 제외 -->` + 정적
|
||||
추정으로 대체되며, 설치 후 `--seed` 실측으로 채운다. 폴백은 `api/` 로 시작하는 라우트만 대상이므로
|
||||
web(admin) 라우트는 자동 제외된다.
|
||||
- 실측이 불가한 라우트(외부 의존·allowlist 제외)는 `<!-- 실측 제외: {사유} -->` 마커 + 정적 추정으로 대체.
|
||||
|
||||
### 확장 실측 샘플 시더 (`--seed`)
|
||||
|
||||
`--seed` 는 상세 GET 실측 시 응답 필드가 null 로 관측되는 것을 줄이기 위해, 도메인 대표 엔티티에
|
||||
완전한 샘플 레코드를 멱등 시드한다. 코어 도메인은 `App\Support\ApiDoc\ApiDocSampleService` 가 담당한다.
|
||||
|
||||
확장은 자신의 도메인 샘플을 **확장이 소유**한다. `App\Contracts\ApiDoc\ApiDocSampleSeeder` 를 구현한
|
||||
클래스를 규약 위치 `{확장 네임스페이스}\Support\ApiDoc\ApiDocSampleService`
|
||||
(예: `Modules\Sirsoft\Page\Support\ApiDoc\ApiDocSampleService`, 파일은 `src/Support/ApiDoc/`)에 두면,
|
||||
`api:docgen --scope=module:{id} --seed` 실행 시 커맨드가 자동으로 발견해 코어 시드 뒤에 병합한다.
|
||||
|
||||
- `seed()` 반환 맵의 키는 라우트 도메인 그룹명(`pages` 등), 값은 `{model, key, value}`
|
||||
(모델 FQCN·route key 이름·route key 값)이다.
|
||||
- 이 맵은 상세 GET 의 path 파라미터 치환에 쓰인다. 라우트-모델 바인딩이 없는 확장 패턴
|
||||
(`show(int $id)`)도, 파라미터명이 도메인의 단수 리소스명과 일치하면(`pages/{page}`) 이 맵으로 실측된다.
|
||||
`{slug}`·`{hash}`·`{versionId}` 처럼 route key 가 다른 문자열/보조 파라미터는 폴백하지 않고 실측 제외된다.
|
||||
- 확장에 새 PHP 클래스를 추가했으므로 `_bundled` 작업 후 `{type}:update {id} --force` 로 활성 디렉토리에
|
||||
반영해야 오토로드된다.
|
||||
|
||||
---
|
||||
|
||||
## 문서 갱신 의무
|
||||
|
||||
컨트롤러/라우트/FormRequest/Resource 를 추가·변경하면 대응 API 문서를 같은 변경 단위에서 갱신한다.
|
||||
|
||||
- 트리거: `app/Http/Controllers/**`, `routes/api.php`, `app/Http/Requests/**`, `app/Http/Resources/**`
|
||||
(+ 확장 대응 경로) 편집.
|
||||
- 절차: 코드 변경 → `api:docgen --scope=...` 재실행 → `@generated` 블록 갱신 → 신규 TODO 서술 채움.
|
||||
- 검증: `api:docgen --check` 로 drift 0 확인. audit 룰 `api-doc-coverage` 가 변경셋에 대응 문서
|
||||
동반 여부를 검사한다. severity 는 **대상별**로 부여된다 — 문서가 완비된 대상은 `error`(문서
|
||||
미동반 변경 차단), 진행 중 대상은 `warn`. 코어(`docs/backend/api/`)는 2026-07-08 완료로
|
||||
`error` 승격됨. 즉 코어 API 표면(`routes/api.php`·`app/Http/{Controllers,Requests,Resources}/**`)을
|
||||
변경하면서 코어 API 문서를 함께 갱신하지 않으면 세션 종료 시 차단된다. 나머지 확장은 문서 완비
|
||||
시 순차 승격된다(룰의 `ENFORCED_TARGETS`).
|
||||
|
||||
---
|
||||
|
||||
## 체크리스트
|
||||
|
||||
```text
|
||||
□ 엔드포인트가 대응 위치(코어 docs/backend/api/ 또는 확장 docs/api/)에 문서화되었는가?
|
||||
□ 요청 파라미터 표에 위치/타입/필수/허용값/용도가 모두 기재되었는가?
|
||||
□ 응답 필드 표가 envelope 의 data 내부 기준으로 작성되었는가?
|
||||
□ 훅 주입 파라미터가 있으면 주석 + 사람 보강이 되었는가?
|
||||
□ TODO 마커가 모두 채워졌는가?
|
||||
□ api:docgen --check 가 drift 0 인가?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 관련 문서
|
||||
|
||||
- [routing.md](routing.md) - 라우트 네이밍/URL 규칙 (확장 URL 스킴은 `/api/modules/{module}/...`)
|
||||
- [api-resources.md](api-resources.md) - 응답 필드/pagination/abilities 형태
|
||||
- [response-helper.md](response-helper.md) - 응답 envelope 표준
|
||||
- [validation.md](validation.md) - FormRequest rule → 파라미터 허용값 유추 근거
|
||||
@@ -0,0 +1,143 @@
|
||||
# Activity Logs API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Activity Logs 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/activity-logs
|
||||
<!-- @generated:start:api.admin.activity-logs.index -->
|
||||
- **라우트명**: `api.admin.activity-logs.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ActivityLogController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.activities.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| log_type | query | array | 아니오 | — | 로그 유형 필터 (원소별 값: admin 관리자, user 사용자, system 시스템 — ActivityLogType Enum). 배열로 다중 유형 동시 조회 가능 |
|
||||
| action | query | string | 아니오 | max 100 | 액션 유형 필터 (예: created, updated, deleted, login — action 필드 부분/일치 검색 대상) |
|
||||
| user_id | query | integer | 아니오 | — | user 식별자 |
|
||||
| loggable_type | query | string | 아니오 | max 255 | 연관 리소스 모델 클래스명 필터 (예: App\Models\User — 특정 엔티티 유형의 로그만 조회) |
|
||||
| search | query | string | 아니오 | max 255 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
|
||||
| search_type | query | string | 아니오 | — | 검색 유형 (검색 대상/방식 구분) |
|
||||
| created_by | query | string | 아니오 | max 36 | 로그를 생성한 행위 주체 식별자 필터 (행위자 기준 조회) |
|
||||
| date_from | query | date | 아니오 | — | 조회 기간 시작일 |
|
||||
| date_to | query | date | 아니오 | — | 조회 기간 종료일 |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| sort_by | query | string | 아니오 | — | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | — | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.activity_log.index_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `87675` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | integer | `210842` | 기본 키 (내부 식별자) |
|
||||
| log_type | string | `user` | 로그 유형 (admin: 관리자, user: 사용자, system: 시스템) |
|
||||
| log_type_label | string | `사용자` | `log_type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| loggable_type | string | `Modules\Sirsoft\Board\Models\Attachment` | 로그가 연관된 대상 리소스의 모델 클래스 FQCN (loggable 다형성 관계 타입) |
|
||||
| loggable_type_display | string | `Attachment` | `loggable_type` 의 표시용 짧은 이름 (네임스페이스 제외 클래스명 파생) |
|
||||
| loggable_id | integer | `155` | loggable 식별자 (연관 리소스 참조) |
|
||||
| action | string | `attachment.download` | 액션 유형 (created, updated, deleted, login, export 등) |
|
||||
| action_label | string | `다운로드` | `action` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| localized_description | string | `첨부파일 다운로드 (게시물: 237)` | `description` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| description_key | string | `sirsoft-board::activity_log.descripti…` | 다국어 번역 키 (예: activity_log.description.user_create) |
|
||||
| properties | object | `{"original_filename":"apidoc-sample.png","post_id":237,"c…` | 변경 상세 데이터 (old/new 값) |
|
||||
| changes | object | `{"status":{"old":"inactive","new":"active","label":""}}` | 구조화된 변경 이력 (필드별 label_key, old, new, type) |
|
||||
| bulk_changes | null | `null` | 일괄 수정 로그의 모델별 변경 이력 배열 (원소: model_id + changes[]). 단일 수정 로그이면 null이고 대신 changes 필드가 채워짐 |
|
||||
| has_changes | boolean | `false` | changes 여부 |
|
||||
| actor_name | string | `API 문서 샘플 사용자` | 행위를 수행한 주체(사용자/시스템)의 이름 |
|
||||
| user | object | `{"uuid":"a231747f-e82e-4cf2-9ae1-a261849dce40","name":"AP…` | 행위를 수행한 사용자 정보 (uuid/name/email). 시스템 발생 로그로 사용자가 없으면 name 에 "시스템" 라벨만 담김 |
|
||||
| ip_address | string | `127.0.0.1` | IP 주소 (IPv6 대응) |
|
||||
| created_at | string | `2026-07-07 10:00:47` | 생성 일시 |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.activities.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 시스템 활동 로그를 페이지네이션 목록으로 조회합니다. `log_type`(admin/user/system), `action`, `user_id`, `loggable_type`, 기간(`date_from`/`date_to`), 키워드(`search`) 등으로 필터링하고 `sort_by`/`sort_order`로 정렬합니다. null 값 필터는 자동으로 제외됩니다. `core.activities.read` 권한이 필요하며, 각 항목에는 현지화된 액션 라벨·변경 이력(changes)·소유자/권한 메타가 포함됩니다. 확장은 `core.activity_log.index_validation_rules` 훅으로 필터 파라미터를 추가할 수 있습니다.
|
||||
|
||||
|
||||
### POST /api/admin/activity-logs/bulk-delete
|
||||
<!-- @generated:start:api.admin.activity-logs.bulk-destroy -->
|
||||
- **라우트명**: `api.admin.activity-logs.bulk-destroy`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ActivityLogController@bulkDestroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.activities.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.activities.delete`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 지정한 활동 로그들을 일괄 삭제합니다. `ids` 배열에 삭제할 로그 ID를 담아 요청하며, 서비스가 각 항목을 삭제하고 실제 삭제된 건수(`deleted_count`)를 반환합니다. `core.activities.delete` 권한이 필요합니다. 로그 목록에서 여러 항목을 선택해 한 번에 정리하는 시나리오에 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/admin/activity-logs/{activityLog}
|
||||
<!-- @generated:start:api.admin.activity-logs.destroy -->
|
||||
- **라우트명**: `api.admin.activity-logs.destroy`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ActivityLogController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.activities.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| activityLog | path | string | 예 | — | 대상 activity log의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.activities.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 단일 활동 로그를 삭제합니다. 경로의 `{activityLog}`는 라우트 모델 바인딩으로 로그 ID를 받아 해당 레코드를 삭제합니다. `core.activities.delete` 권한이 필요하며, 삭제 실패 시 오류가 로그로 기록되고 500이 반환됩니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Attachment API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Attachment 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/attachment/{hash}
|
||||
<!-- @generated:start:api.attachment.download -->
|
||||
- **라우트명**: `api.attachment.download`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicAttachmentController@download`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| hash | path | string | 예 | — | 대상 리소스의 해시 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 해시(12자)로 식별되는 첨부파일을 다운로드합니다. 이미지 파일은 캐싱 헤더와 함께 인라인으로 표시하고 그 외 파일은 다운로드 방식으로 제공합니다. 인증이 필요 없는 공개 라우트이지만 접근 권한은 AttachmentService가 로그인/비로그인 사용자 모두를 대상으로 하이브리드 방식으로 검사하며, 파일이 없으면 404, 권한이 없으면 403을 반환합니다. 게시글 첨부·상품 이미지 등 공개 리소스를 URL로 직접 내려받는 시나리오에 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
# Attachments API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Attachments 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### POST /api/admin/attachments
|
||||
<!-- @generated:start:api.admin.attachments.upload -->
|
||||
- **라우트명**: `api.admin.attachments.upload`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\AttachmentController@upload`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.attachments.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| file | body | file | 예 | max 10240 | 업로드 파일 |
|
||||
| attachmentable_type | body | string | 아니오 | max 255 | 첨부를 연결할 대상 모델의 다형성 타입 (attachmentable morph type, 예 User·Post 등 모델 클래스명). attachmentable_id와 짝을 이뤄 대상을 지정하며 미지정 시 미연결 상태로 저장 |
|
||||
| attachmentable_id | body | integer | 아니오 | min 1 | attachmentable 식별자 |
|
||||
| collection | body | string | 아니오 | max 100 | 첨부 컬렉션 그룹명 (첨부를 용도별로 묶는 키, 미지정 시 default) |
|
||||
| source_type | body | string | 아니오 | — | 첨부 생성 출처 구분 (AttachmentSourceType Enum — core: 코어 시스템, module: 모듈, plugin: 플러그인). 미지정 시 core로 기본 설정 |
|
||||
| source_identifier | body | string | 아니오 | max 255 | 출처 식별자 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.attachment.upload_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.attachments.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 단일 파일을 업로드해 첨부파일(Attachment) 레코드로 등록합니다. `attachmentable_type`/`attachmentable_id`로 대상 모델과의 다형성 연결을, `collection`으로 그룹을 지정하며 미지정 시 각각 미연결·`default` 컬렉션으로 저장됩니다. `core.attachments.create` 권한이 필요하며, 성공 시 201과 함께 생성된 첨부파일 리소스를 반환합니다. 확장은 `core.attachment.upload_validation_rules` 훅으로 검증 규칙을 추가할 수 있고, `source_type`/`source_identifier`로 업로드 출처(코어/확장)를 식별합니다.
|
||||
|
||||
|
||||
### POST /api/admin/attachments/batch
|
||||
<!-- @generated:start:api.admin.attachments.upload_batch -->
|
||||
- **라우트명**: `api.admin.attachments.upload_batch`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\AttachmentController@uploadBatch`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.attachments.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| files | body | array | 예 | min 1 | 업로드 파일 배열 |
|
||||
| attachmentable_type | body | string | 아니오 | max 255 | 첨부를 연결할 대상 모델의 다형성 타입 (attachmentable morph type, 예 User·Post 등 모델 클래스명). attachmentable_id와 짝을 이뤄 대상을 지정하며 미지정 시 미연결 상태로 저장 |
|
||||
| attachmentable_id | body | integer | 아니오 | min 1 | attachmentable 식별자 |
|
||||
| collection | body | string | 아니오 | max 100 | 첨부 컬렉션 그룹명 (첨부를 용도별로 묶는 키, 미지정 시 default) |
|
||||
| source_type | body | string | 아니오 | — | 첨부 생성 출처 구분 (AttachmentSourceType Enum — core: 코어 시스템, module: 모듈, plugin: 플러그인). 미지정 시 core로 기본 설정 |
|
||||
| source_identifier | body | string | 아니오 | max 255 | 출처 식별자 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.attachment.upload_batch_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.attachments.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 여러 파일을 한 번의 요청으로 일괄 업로드합니다. `files` 배열의 각 파일이 개별 첨부파일 레코드로 등록되며, `attachmentable_type`/`attachmentable_id`/`collection` 등의 옵션은 배치 전체에 공통 적용됩니다. `core.attachments.create` 권한이 필요하고, 성공 시 201과 함께 생성된 첨부파일 리소스 컬렉션을 반환합니다. 갤러리·다중 이미지 첨부처럼 한 대상에 여러 파일을 붙이는 시나리오에 사용합니다.
|
||||
|
||||
|
||||
### PATCH /api/admin/attachments/reorder
|
||||
<!-- @generated:start:api.admin.attachments.reorder -->
|
||||
- **라우트명**: `api.admin.attachments.reorder`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\AttachmentController@reorder`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.attachments.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order | body | array | 예 | min 1 | 재정렬 대상 목록. 각 원소는 `id`(기존 첨부파일 식별자)와 `order`(새 정렬 순서값, 0 이상 정수)를 가진 객체이며, 이 매핑대로 각 첨부의 정렬 값이 갱신됨 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.attachment.reorder_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.attachments.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 첨부파일의 표시 순서를 재정렬합니다. `order` 배열에 담긴 순서대로 각 첨부파일의 정렬 값이 갱신됩니다. `core.attachments.update` 권한이 필요합니다. 갤러리에서 드래그 앤 드롭으로 이미지 순서를 바꾸는 등 이미 등록된 첨부파일의 나열 순서만 변경할 때 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/admin/attachments/{attachment}
|
||||
<!-- @generated:start:api.admin.attachments.destroy -->
|
||||
- **라우트명**: `api.admin.attachments.destroy`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\AttachmentController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.attachments.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| attachment | path | string | 예 | — | 대상 attachment의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.attachments.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 지정한 첨부파일을 삭제합니다. 경로의 `{attachment}`는 라우트 모델 바인딩으로 첨부파일 ID를 받으며, 서비스가 DB 레코드와 실제 저장 파일을 함께 제거합니다. `core.attachments.delete` 권한이 필요합니다. 존재하지 않는 ID면 404가 반환됩니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,575 @@
|
||||
# Auth API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Auth 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### POST /api/admin/auth/logout
|
||||
<!-- @generated:start:api.admin.auth.logout -->
|
||||
- **라우트명**: `api.admin.auth.logout`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\AuthController@logout`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 관리자의 Sanctum 토큰을 폐기해 로그아웃한다. `AuthService::logout()` 이 3단계(토큰 삭제 → 세션 무효화 → `Auth::logout()`)를 수행하며, `data` 는 없고 `message` 만 `auth.logout_success` 로 내려온다. 프론트는 응답 후 저장된 Bearer 토큰을 폐기하고 로그인 화면으로 전환한다.
|
||||
|
||||
|
||||
### POST /api/admin/auth/refresh
|
||||
<!-- @generated:start:api.admin.auth.refresh -->
|
||||
- **라우트명**: `api.admin.auth.refresh`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\AuthController@refresh`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 관리자 토큰을 새 Sanctum 토큰으로 교체한다. `AuthService::refreshToken()` 이 기존 토큰을 폐기하고 새 토큰을 발급하며, `data` 에는 새 `token` 과 `user`(UserResource) 가 담긴다. 만료 임박 토큰을 재발급하는 용도로, 세션 만료로 재인증이 필요한 경우(토큰 무효)에는 `401 auth.unauthenticated` 를 반환한다.
|
||||
|
||||
|
||||
### GET /api/admin/auth/user
|
||||
<!-- @generated:start:api.admin.auth.user -->
|
||||
- **라우트명**: `api.admin.auth.user`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\AuthController@user`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a231747f-e82e-4cf2-9ae1-a261849dce40` | 외부 노출용 UUID (URL/API 식별자, 내부 id 비노출) |
|
||||
| name | string | `API 문서 샘플 사용자` | 사용자 이름 |
|
||||
| nickname | string | `gunwoo.oh` | 닉네임 |
|
||||
| email | string | `apidoc-sample-user@example.com` | 이메일 주소 |
|
||||
| avatar | null | `null` | 아바타 이미지 URL (User::getAvatarUrl() — 아바타 미설정 시 null) |
|
||||
| language | string | `ko` | 사용자 언어 설정 (ko: 한국어, en: 영어) |
|
||||
| language_label | string | `한국어` | 언어 코드의 현지화 라벨 (user.language.{code} 번역) |
|
||||
| country | string | `KR` | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| status | string | `active` | 계정 상태 (active: 활성, inactive: 비활성, blocked: 차단, withdrawn: 탈퇴) |
|
||||
| status_label | string | `활성` | 상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
|
||||
| status_variant | string | `success` | 상태 표시 색상/스타일 변형 키 (상태 Enum variant() 산물 — UI 배지용) |
|
||||
| is_admin | boolean | `true` | 관리자 역할 보유 여부 (User::isAdmin() — 역할 관계 기반 파생) |
|
||||
| homepage | string | `https://example.com` | 홈페이지 URL |
|
||||
| mobile | string | `010-9070-5662` | 휴대폰 번호 |
|
||||
| phone | string | `02-805-4759` | 전화번호 |
|
||||
| zipcode | string | `93153` | 우편번호 |
|
||||
| address | string | `대구광역시 북구 백제고분로 720` | 기본 주소 |
|
||||
| address_detail | string | `40동 835호` | 상세 주소 |
|
||||
| signature | string | `Ipsam rem amet expedita est.` | 서명 |
|
||||
| bio | string | `Tenetur omnis et amet omnis veniam to…` | 자기소개 |
|
||||
| last_login_at | string | `2026-07-05 19:15:16` | last login 일시 |
|
||||
| email_verified_at | string | `2026-07-06 19:15:16` | email verified 일시 |
|
||||
| timezone | string | `Asia/Seoul` | 사용자 시간대 (예: Asia/Seoul, UTC) |
|
||||
| roles | array | `[{"id":1,"identifier":"admin","name":"관리자"}]` | 사용자에게 부여된 역할 목록 (원소 id/identifier/name — roles 관계 파생, name 은 현지화 라벨) |
|
||||
| permissions | array | `[{"id":3,"identifier":"core.users.read","name":"사용자 조회"},…` | 연결된 권한 목록 (id/identifier/name — 역할 경유 권한 관계 파생) |
|
||||
| created_at | string | `2026-07-06 19:15:16` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-06 19:15:16` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":true,"can_create":true,"can_update":true,"can…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
관리자 레이아웃 전역 부트스트랩 엔드포인트. `_admin_base.json` 의 `data_source`(`current_user`)가 모든 관리자 페이지 진입 시 자동 호출해, 헤더/권한 게이트/is_admin 분기의 기준 사용자 정보를 채운다. 응답에는 `roles.permissions` 가 eager load 되어 `permissions` 배열이 함께 내려온다.
|
||||
|
||||
**인증 계약**: `auth:sanctum` 필요 — Bearer 토큰이 없거나 만료되면 `401` 을 반환한다(프론트 `data_source` 의 `auth_required: true` 에 대응). 이 계약이 프론트 소비의 SSoT 이므로 미들웨어 체인 변경 시 반드시 프론트 `auth_required`/`auth_mode` 와 함께 검토한다(이슈 #64).
|
||||
|
||||
|
||||
### POST /api/auth/admin/login
|
||||
<!-- @generated:start:api.auth.admin.login -->
|
||||
- **라우트명**: `api.auth.admin.login`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\AuthController@login`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| email | body | email | 예 | — | 이메일 주소 |
|
||||
| password | body | string | 예 | min 6 | 비밀번호 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.auth.login_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
관리자 로그인. `email`/`password` 검증 후 `AuthService::login()` 이 인증하고, 인증 사용자가 `isAdmin()` 이 아니면 `403 auth.admin_required` 로 거부한다. 성공 시 `data.token`(Sanctum Bearer) 과 `data.user`(UserResource) 를 반환한다. 계정 잠금 시 `AccountLockedException`, 자격 불일치 시 `422` 검증 오류를 반환한다. 이후 모든 관리자 API 호출은 이 토큰을 `Authorization: Bearer` 헤더로 실어야 한다.
|
||||
|
||||
|
||||
### POST /api/auth/forgot-password
|
||||
<!-- @generated:start:api.auth.forgot-password -->
|
||||
- **라우트명**: `api.auth.forgot-password`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\AuthController@forgotPassword`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| email | body | email | 예 | — | 이메일 주소 |
|
||||
| redirect_prefix | body | string | 아니오 | `admin` | 재설정 링크가 향할 화면 구분값 — `admin` 전달 시 관리자 재설정 화면, 미지정 시 사용자 화면 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.auth.forgot_password_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
비밀번호 재설정 메일 발송을 요청한다(공개). `email` 로 계정을 찾아 재설정 링크 메일을 보내고 `message: auth.password_reset_email_sent` 를 반환한다. `redirect_prefix` 는 재설정 링크가 향할 화면을 구분하는 값으로 관리자 흐름(`admin_forgot_password.json`)에서는 `admin` 을 전달해 링크가 관리자 재설정 화면을 가리키게 한다(미지정 시 사용자 화면). 계정 열거 방지를 위해 이메일 존재 여부와 무관하게 동일 응답을 주는 것이 원칙이다.
|
||||
|
||||
|
||||
### POST /api/auth/login
|
||||
<!-- @generated:start:api.auth.login -->
|
||||
- **라우트명**: `api.auth.login`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\AuthController@login`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| email | body | email | 예 | — | 이메일 주소 |
|
||||
| password | body | string | 예 | min 6 | 비밀번호 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.auth.login_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
일반 사용자 로그인(공개). 관리자 로그인과 달리 `isAdmin()` 검사가 없다. 성공 시 `data.token`(Sanctum Bearer) 과 `data.user` 를 반환하며 `message: auth.login_success`. 계정 잠금 시 `423 auth.account_locked` 를 잠금 해제까지 남은 정보와 함께 반환한다. 프론트 로그인 폼(`partials/auth/_register_form.json` 인접)에서 소비한다.
|
||||
|
||||
|
||||
### POST /api/auth/logout
|
||||
<!-- @generated:start:api.auth.logout -->
|
||||
- **라우트명**: `api.auth.logout`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\AuthController@logout`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 사용자 토큰을 폐기해 로그아웃한다(`message: auth.logout_success`). 현재 요청에 사용된 토큰만 폐기하며, 모든 기기에서 로그아웃하려면 `/api/user/auth/logout-all-devices` 를 사용한다.
|
||||
|
||||
|
||||
### POST /api/auth/register
|
||||
<!-- @generated:start:api.auth.register -->
|
||||
- **라우트명**: `api.auth.register`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\AuthController@register`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | string | 예 | max 255 | 대상의 이름/명칭 |
|
||||
| nickname | body | string | 아니오 | max 50 | 닉네임 |
|
||||
| email | body | string | 예 | max 255 | 이메일 주소 |
|
||||
| password | body | string | 예 | min 8 | 비밀번호 |
|
||||
| language | body | string | 아니오 | `ko`, `en`, `fr`, `ja` | 언어 코드 |
|
||||
| agree_terms | body | string | 아니오 | — | 이용약관 동의 (코어 필수 동의 — accepted 규칙, 미동의 시 가입 거부) |
|
||||
| agree_privacy | body | string | 아니오 | — | 개인정보 처리방침 동의 (코어 필수 동의 — accepted 규칙, 미동의 시 가입 거부) |
|
||||
| agree_email_subscription | body | boolean | 아니오 | — | 광고성 이메일 수신 동의 (marketing 플러그인 주입, 선택 항목) |
|
||||
| agree_marketing_consent | body | boolean | 아니오 | — | 마케팅 정보 수신 전체 동의 (marketing 플러그인 주입, 선택 항목) |
|
||||
| agree_third_party_consent | body | boolean | 아니오 | — | 제3자 정보 제공 동의 (marketing 플러그인 주입, 선택 항목) |
|
||||
| agree_info_disclosure | body | boolean | 아니오 | — | 개인정보 이용 안내 동의 (marketing 플러그인 주입, 선택 항목) |
|
||||
| preferred_currency | body | string | 아니오 | — | 선호 결제 통화 (ecommerce 모듈 주입, 가입 시 계정 기본 통화로 저장) |
|
||||
| preferred_shipping_country | body | string | 아니오 | — | 선호 배송 국가 코드 (ecommerce 모듈 주입, 가입 시 계정 기본 배송 국가로 저장) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.auth.register_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
회원가입(공개). 성공 시 `201 auth.register_success` 와 `data.token`/`data.user` 를 반환해 가입 직후 로그인 상태로 이어진다. `agree_*` 동의 파라미터(약관/개인정보/이메일수신/마케팅/제3자제공/정보공개)는 가입 시점의 동의 이력으로 기록된다 — 그중 `agree_email_subscription`/`agree_marketing_consent`/`agree_third_party_consent`/`agree_info_disclosure` 및 `preferred_currency`/`preferred_shipping_country` 는 marketing·ecommerce 확장이 훅(`core.auth.register_validation_rules`)으로 주입하는 파라미터로, 해당 확장 비활성 시 무시된다. 검증 실패 시 `422 auth.register_failed`.
|
||||
|
||||
|
||||
### POST /api/auth/reset-password
|
||||
<!-- @generated:start:api.auth.reset-password -->
|
||||
- **라우트명**: `api.auth.reset-password`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\AuthController@resetPassword`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| token | body | string | 예 | — | 인증/검증 토큰 |
|
||||
| email | body | email | 예 | — | 이메일 주소 |
|
||||
| password | body | string | 예 | min 8 | 비밀번호 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.auth.reset_password_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
비밀번호 재설정을 실제 반영한다(공개). 재설정 메일의 `token` 과 `email`, 새 `password` 를 받아 비밀번호를 갱신하고 `message: auth.password_reset_success`. 토큰 만료/불일치 등 검증 실패 시 `422 auth.password_reset_failed`. 반영 전 토큰 유효성만 먼저 확인하려면 `/api/auth/validate-reset-token` 을 사용한다.
|
||||
|
||||
|
||||
### GET /api/auth/user
|
||||
<!-- @generated:start:api.auth.user -->
|
||||
- **라우트명**: `api.auth.user`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\AuthController@user`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a231747f-e82e-4cf2-9ae1-a261849dce40` | 외부 노출용 UUID (URL/API 식별자, 내부 id 비노출) |
|
||||
| name | string | `API 문서 샘플 사용자` | 사용자 이름 |
|
||||
| nickname | string | `gunwoo.oh` | 닉네임 |
|
||||
| email | string | `apidoc-sample-user@example.com` | 이메일 주소 |
|
||||
| avatar | null | `null` | 아바타 이미지 URL (User::getAvatarUrl() — 아바타 미설정 시 null) |
|
||||
| language | string | `ko` | 사용자 언어 설정 (ko: 한국어, en: 영어) |
|
||||
| language_label | string | `한국어` | 언어 코드의 현지화 라벨 (user.language.{code} 번역) |
|
||||
| country | string | `KR` | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| status | string | `active` | 계정 상태 (active: 활성, inactive: 비활성, blocked: 차단, withdrawn: 탈퇴) |
|
||||
| status_label | string | `활성` | 상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
|
||||
| status_variant | string | `success` | 상태 표시 색상/스타일 변형 키 (상태 Enum variant() 산물 — UI 배지용) |
|
||||
| is_admin | boolean | `true` | 관리자 역할 보유 여부 (User::isAdmin() — 역할 관계 기반 파생) |
|
||||
| homepage | string | `https://example.com` | 홈페이지 URL |
|
||||
| mobile | string | `010-9070-5662` | 휴대폰 번호 |
|
||||
| phone | string | `02-805-4759` | 전화번호 |
|
||||
| zipcode | string | `93153` | 우편번호 |
|
||||
| address | string | `대구광역시 북구 백제고분로 720` | 기본 주소 |
|
||||
| address_detail | string | `40동 835호` | 상세 주소 |
|
||||
| signature | string | `Ipsam rem amet expedita est.` | 서명 |
|
||||
| bio | string | `Tenetur omnis et amet omnis veniam to…` | 자기소개 |
|
||||
| last_login_at | string | `2026-07-05 19:15:16` | last login 일시 |
|
||||
| email_verified_at | string | `2026-07-06 19:15:16` | email verified 일시 |
|
||||
| timezone | string | `Asia/Seoul` | 사용자 시간대 (예: Asia/Seoul, UTC) |
|
||||
| modules_count | array | `[]` | 접근 가능 모듈 수 (modules_count 속성이 로드된 경우에만 포함 — whenLoaded 성격의 조건부 필드) |
|
||||
| plugins_count | array | `[]` | 접근 가능 플러그인 수 (plugins_count 속성이 로드된 경우에만 포함) |
|
||||
| menus_count | array | `[]` | 접근 가능 메뉴 수 (menus_count 속성이 로드된 경우에만 포함) |
|
||||
| modules | array | `[]` | 접근 가능 모듈 목록 (원소 id/name/slug/is_active — modules 관계 로드 시에만 포함) |
|
||||
| plugins | array | `[]` | 접근 가능 플러그인 목록 (원소 id/name/slug/is_active — plugins 관계 로드 시에만 포함) |
|
||||
| menus | array | `[]` | 접근 가능 메뉴 목록 (원소 id/title/url/is_active — menus 관계 로드 시에만 포함) |
|
||||
| roles | array | `[{"id":1,"identifier":"admin","name":"관리자"}]` | 사용자에게 부여된 역할 목록 (원소 id/identifier/name — roles 관계 파생, name 은 현지화 라벨) |
|
||||
| permissions | array | `[{"id":3,"identifier":"core.users.read","name":"사용자 조회"},…` | 연결된 권한 목록 (id/identifier/name — 역할 경유 권한 관계 파생) |
|
||||
| consents | array | `[]` | 전체 약관 동의 이력 (원소 consent_type/agreed_at/revoked_at — consents 관계 로드 시 포함, 플러그인 참조용) |
|
||||
| terms_consent | array | `[]` | 이용약관 동의 정보 (agreed_at — ConsentType::Terms 동의 이력에서 파생, 미동의 시 null) |
|
||||
| privacy_consent | array | `[]` | 개인정보 처리방침 동의 정보 (agreed_at — ConsentType::Privacy 동의 이력에서 파생, 미동의 시 null) |
|
||||
| created_at | string | `2026-07-06 19:15:16` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-06 19:15:16` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":true,"can_create":true,"can_update":true,"can…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
| notify_post_complete | boolean | `false` | 게시판 새 글 작성 완료 알림 수신 설정 (marketing 플러그인 주입) |
|
||||
| notify_post_reply | boolean | `false` | 내 게시글에 답글 달림 알림 수신 설정 (marketing 플러그인 주입) |
|
||||
| notify_comment | boolean | `false` | 내 게시글에 댓글 달림 알림 수신 설정 (marketing 플러그인 주입) |
|
||||
| notify_reply_comment | boolean | `false` | 내 댓글에 답글 달림 알림 수신 설정 (marketing 플러그인 주입) |
|
||||
| email_subscription | boolean | `false` | 광고성 이메일 수신 동의 여부 (marketing 플러그인 주입) |
|
||||
| email_subscription_at | null | `null` | email subscription 일시 (광고성 이메일 수신 동의 시각, 미동의 시 null) |
|
||||
| marketing_consent | boolean | `false` | 마케팅 정보 수신 전체 동의 마스터 키 (marketing 플러그인 주입) |
|
||||
| marketing_consent_at | null | `null` | marketing consent 일시 (마케팅 정보 수신 동의 시각, 미동의 시 null) |
|
||||
| third_party_consent | boolean | `false` | 제3자 정보 제공 동의 여부 (법적 항목 — marketing 플러그인 주입) |
|
||||
| third_party_consent_at | null | `null` | third party consent 일시 (제3자 정보 제공 동의 시각, 미동의 시 null) |
|
||||
| info_disclosure | boolean | `false` | 개인정보 이용 안내 동의 여부 (법적 항목 — marketing 플러그인 주입) |
|
||||
| info_disclosure_at | null | `null` | info disclosure 일시 (개인정보 이용 안내 동의 시각, 미동의 시 null) |
|
||||
| marketing_consent_enabled | boolean | `true` | 마케팅 정보 수신 동의 항목 UI 노출 여부 (관리자 활성화 플래그) |
|
||||
| marketing_consent_terms_slug | string | `marketing-terms` | 마케팅 정보 수신 동의에 연결된 약관 slug (미설정 시 null) |
|
||||
| marketing_consent_terms_slug_set | boolean | `true` | 마케팅 정보 수신 약관 연결 존재 여부 (프론트 링크 표시 판정용) |
|
||||
| third_party_consent_enabled | boolean | `true` | 제3자 정보 제공 동의 항목 UI 노출 여부 (관리자 활성화 플래그) |
|
||||
| third_party_consent_terms_slug | null | `null` | 제3자 정보 제공 동의에 연결된 약관 slug (미설정 시 null) |
|
||||
| third_party_consent_terms_slug_set | boolean | `false` | 제3자 정보 제공 약관 연결 존재 여부 (프론트 링크 표시 판정용) |
|
||||
| info_disclosure_enabled | boolean | `true` | 개인정보 이용 안내 동의 항목 UI 노출 여부 (관리자 활성화 플래그) |
|
||||
| info_disclosure_terms_slug | null | `null` | 개인정보 이용 안내 동의에 연결된 약관 slug (미설정 시 null) |
|
||||
| info_disclosure_terms_slug_set | boolean | `false` | 개인정보 이용 안내 약관 연결 존재 여부 (프론트 링크 표시 판정용) |
|
||||
| email_subscription_enabled | boolean | `true` | 광고성 이메일 수신 동의 항목 UI 노출 여부 (관리자 활성화 플래그) |
|
||||
| email_subscription_terms_slug | null | `null` | 광고성 이메일 수신 동의에 연결된 약관 slug (미설정 시 null) |
|
||||
| email_subscription_terms_slug_set | boolean | `false` | 광고성 이메일 수신 약관 연결 존재 여부 (프론트 링크 표시 판정용) |
|
||||
| channels | array | `[{"key":"email_subscription","label":"광고성 이메일 수신","enable…` | 관리자 정의 전체 마케팅 채널 목록 (원소 key/label/enabled/terms_slug — marketing 플러그인 주입) |
|
||||
| consent_histories | array | `[]` | 동의 변경 이력 (원소 channel_key/action/source/created_at — marketing 플러그인 주입) |
|
||||
| ecommerce_mileage | object | `{"enabled":false}` | 마일리지 정보 (enabled/잔액 — ecommerce 모듈 주입, 모듈 비활성 시 enabled=false) |
|
||||
| ecommerce_preferred_currency | null | `null` | 선호 결제 통화 (ecommerce 모듈 주입, 미설정 시 null) |
|
||||
| ecommerce_preferred_shipping_country | null | `null` | 선호 배송 국가 코드 (ecommerce 모듈 주입, 미설정 시 null) |
|
||||
| ecommerce_preferred_shipping_country_name | null | `null` | 선호 배송 국가 이름 (국가 코드에서 현지화 파생 — ecommerce 모듈 주입, 미설정 시 null) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
프론트(사용자) 레이아웃 전역 부트스트랩 엔드포인트. `_user_base.json` 의 `current_user` data_source 가 모든 페이지 진입 시 호출한다. 관리자 `user` 와 달리 응답을 `UserResource::toAuthArray()` 로 만들어 `core.user.filter_resource_data` 필터를 적용하므로, marketing 플러그인·ecommerce 모듈이 훅으로 병합한 필드(`notify_*`, `marketing_consent*`, `channels`, `ecommerce_*` 등)가 함께 내려온다. 이 필드들은 확장 소유이므로 상세 설명은 각 확장 문서를 따른다. 로그인 시 이 응답이 계정 영속 통화를 덮어쓰는 계약(D-LOGIN-CUR)의 출처다.
|
||||
|
||||
**인증 계약**: 이 경로(`api.auth.user`)는 `auth:sanctum` 으로 인증이 필수다. 인증 여부와 무관하게 게스트 컨텍스트가 필요한 화면은 `optional.sanctum` 이 걸린 `/api/user/auth/user`(`api.user.auth.user`)를 사용해야 한다 — 프론트 `data_source` 의 `auth_mode: "optional"` 이 이 경로에 대응한다. 두 경로의 미들웨어 차이가 곧 `auth_required`/`auth_mode` 계약이므로 변경 시 프론트와 함께 검토한다(이슈 #64).
|
||||
|
||||
|
||||
### POST /api/auth/validate-reset-token
|
||||
<!-- @generated:start:api.auth.validate-reset-token -->
|
||||
- **라우트명**: `api.auth.validate-reset-token`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\AuthController@validateResetToken`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| token | body | string | 예 | — | 인증/검증 토큰 |
|
||||
| email | body | email | 예 | — | 이메일 주소 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.auth.validate_reset_token_rules`, `core.auth.validate_reset_token_messages`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
비밀번호 재설정 토큰의 유효성만 사전 확인한다(공개, 비밀번호 미변경). 재설정 화면(`admin_reset_password.json`/`auth/reset_password.json`) 진입 시 토큰/이메일이 유효한지 먼저 검사해, 만료·위조 링크면 즉시 오류 화면을 보이고 유효하면 새 비밀번호 입력 폼을 노출하는 용도다. 실제 반영은 `/api/auth/reset-password` 가 담당한다.
|
||||
|
||||
|
||||
### POST /api/user/auth/logout
|
||||
<!-- @generated:start:api.user.auth.logout -->
|
||||
- **라우트명**: `api.user.auth.logout`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\AuthController@logout`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.auth.logout`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.auth.logout`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
`/user` prefix 그룹의 사용자 로그아웃. 공용 경로 `/api/auth/logout` 과 동일하게 현재 토큰을 폐기하되, `permission:core.auth.logout` 권한 게이트를 추가로 통과해야 한다. 세션 시작(`start.api.session`)이 걸린 공용 경로와 달리 권한 기반 접근 제어가 필요한 흐름에서 사용한다.
|
||||
|
||||
|
||||
### POST /api/user/auth/logout-all-devices
|
||||
<!-- @generated:start:api.user.auth.logout-all-devices -->
|
||||
- **라우트명**: `api.user.auth.logout-all-devices`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\AuthController@logoutFromAllDevices`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.auth.logout`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.auth.logout`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 사용자의 **모든** Sanctum 토큰을 폐기해 전 기기에서 로그아웃한다(`message: auth.logout_all_devices_success`). 비밀번호 변경 후 기존 세션 무효화, 계정 도용 대응 등에 사용한다.
|
||||
|
||||
|
||||
### POST /api/user/auth/refresh
|
||||
<!-- @generated:start:api.user.auth.refresh -->
|
||||
- **라우트명**: `api.user.auth.refresh`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\AuthController@refresh`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.auth.refresh`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.auth.refresh`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
`/user` prefix 그룹의 토큰 갱신. 공용 `refresh` 와 동작은 같으나 `permission:core.auth.refresh` 권한 게이트를 추가로 통과해야 한다. 이 그룹(`routes/api.php:271`)은 `optional.sanctum` + `RefreshTokenExpiration` 미들웨어 아래 있어 토큰 만료 정책 갱신과 함께 동작한다.
|
||||
|
||||
|
||||
### GET /api/user/auth/user
|
||||
<!-- @generated:start:api.user.auth.user -->
|
||||
- **라우트명**: `api.user.auth.user`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\AuthController@user`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.auth.user`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.auth.user`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
`/user` prefix 그룹(`routes/api.php:271`)의 현재 사용자 정보. 이 그룹은 `optional.sanctum` 미들웨어 아래 있어 **비인증(게스트) 요청도 통과**하며, 게스트 컨텍스트가 필요한 프론트 화면의 `data_source`(`auth_mode: "optional"`)가 이 경로를 소비한다. 응답 필드는 인증된 경우 공용 `/api/auth/user` 와 동일 형태(`toAuthArray` 병합 포함)이며, 이 경로에는 추가로 `permission:core.auth.user` 권한 게이트가 걸린다. 실측이 `403` 으로 제외된 것은 샘플 사용자에 해당 권한이 없었기 때문으로, 응답 shape 은 공용 `user` 경로를 참조한다.
|
||||
|
||||
> **인증 계약 요약(이슈 #64)**: `api.auth.user`(`auth:sanctum`, 필수) ↔ `api.user.auth.user`(`optional.sanctum`, 선택). 프론트 `data_source` 의 `auth_required: true` 는 전자에, `auth_mode: "optional"` 은 후자에 대응한다. 어느 한쪽 미들웨어를 바꾸면 프론트 소비 계약이 침묵 속에서 깨지므로 반드시 양쪽 문서를 함께 갱신한다.
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
# Avatar API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Avatar 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### DELETE /api/me/avatar
|
||||
<!-- @generated:start:api.me.avatar.delete -->
|
||||
- **라우트명**: `api.me.avatar.delete`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\ProfileController@deleteAvatar`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 현재 인증 사용자의 아바타를 삭제합니다. 사용자에 연결된 아바타 첨부파일(Attachment) 레코드와 실제 파일을 함께 제거하며, 삭제 활동이 로그로 기록됩니다. 아바타가 없으면 404(`user.avatar_not_found`)를 반환합니다. `auth:sanctum` 인증만 필요하고 별도 권한은 없으며, 사용자가 자신의 프로필 사진을 기본값으로 되돌리는 시나리오에 사용합니다.
|
||||
|
||||
|
||||
### POST /api/me/avatar
|
||||
<!-- @generated:start:api.me.avatar.upload -->
|
||||
- **라우트명**: `api.me.avatar.upload`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\ProfileController@uploadAvatar`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| avatar | body | image | 예 | max 2048 | 아바타 이미지 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.user.upload_avatar_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 현재 인증 사용자의 아바타 이미지를 업로드합니다. 기존 아바타가 있으면 먼저 삭제한 뒤 새 이미지를 `avatar` 컬렉션의 다형성 첨부파일로 등록하고, 업로드 활동을 로그로 기록합니다. `auth:sanctum` 인증만 필요하고 별도 권한은 없으며, 이미지는 최대 2048KB로 제한됩니다. 확장은 `core.user.upload_avatar_rules` 훅으로 검증 규칙을 추가할 수 있습니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# Broadcasting API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Broadcasting 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### POST /api/broadcasting/auth
|
||||
<!-- @generated:start:api.broadcasting.auth -->
|
||||
- **라우트명**: `api.broadcasting.auth`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** WebSocket 프라이빗/프레즌스 채널 구독 시 Laravel Broadcast 채널 인증을 수행하는 엔드포인트입니다. `auth:sanctum` 토큰으로 인증하며, 웹소켓 사용이 OFF(`broadcasting.default === 'null'`)이면 채널 인증을 거부해 403을 반환합니다(reverb.key 무력화를 우회한 직접 연결 시도까지 차단). 컨트롤러 없이 라우트 클로저가 토글 가드를 적용한 뒤 `Broadcast::auth`에 위임하며, 실시간 이벤트 구독을 위해 클라이언트 브로드캐스팅 라이브러리가 자동 호출합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# Changelog API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Changelog 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/changelog
|
||||
<!-- @generated:start:api.admin.changelog -->
|
||||
- **라우트명**: `api.admin.changelog`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LicenseController@changelog`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| content | string | `# Changelog 이 프로젝트의 모든 주요 변경사항을 기록합니…` | 본문 내용 |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 코어의 `CHANGELOG.md` 파일 원문 텍스트를 `content`로 반환합니다. `auth:sanctum` 인증이 필요하며, 파일이 없으면 404(`common.not_found`)를 반환합니다. 관리자 화면에서 코어의 전체 변경 이력을 마크다운 원문 그대로 표시하는 용도로 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
# Core Update API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Core Update 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/core-update/changelog
|
||||
<!-- @generated:start:api.admin.core-update.changelog -->
|
||||
- **라우트명**: `api.admin.core-update.changelog`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\CoreUpdateController@changelog`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| source | query | string | 아니오 | `active`, `bundled`, `github` | 어느 위치의 CHANGELOG를 조회할지 지정 (active: 활성 설치본, bundled: 번들 원본, github: 원격 릴리스). 미지정 시 기본 조회 경로를 사용 |
|
||||
| from_version | query | string | 아니오 | — | 시작 버전 (범위 하한) |
|
||||
| to_version | query | string | 아니오 | — | 대상 버전 (범위 상한) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.extension.changelog_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| changelog | array | `[{"version":"7.0.2","date":"2026-07-05","categories":[{"n…` | 변경 이력 텍스트 (원격/파일 CHANGELOG 본문) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 코어의 버전별 변경사항(CHANGELOG)을 구조화된 배열로 조회합니다. `source`(active/bundled/github)로 어느 위치의 CHANGELOG를 읽을지, `from_version`/`to_version`으로 조회 범위를 지정합니다. `core.settings.read` 권한이 필요하며, 업데이트 안내 화면에서 새 버전에 무엇이 바뀌는지 보여줄 때 사용합니다. 확장은 `core.extension.changelog_rules` 훅으로 파라미터를 확장할 수 있습니다.
|
||||
|
||||
|
||||
### POST /api/admin/core-update/check
|
||||
<!-- @generated:start:api.admin.core-update.check -->
|
||||
- **라우트명**: `api.admin.core-update.check`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\CoreUpdateController@checkForUpdates`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 용도/설명 |
|
||||
| --- | --- | --- |
|
||||
| update_available | boolean | 업데이트 가능 여부 (최신 버전이 현재 버전보다 높으면 true) |
|
||||
| current_version | string | 현재 설치된 코어 버전 |
|
||||
| latest_version | string | GitHub 릴리스에서 확인한 최신 버전 (조회 실패 시 현재 버전으로 대체) |
|
||||
| github_url | string | 버전 확인 대상 GitHub 저장소 URL (`config('app.update.github_url')`) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** GitHub 릴리스를 기준으로 코어 업데이트 가능 여부를 확인합니다. 현재 버전과 최신 버전을 비교한 결과를 반환하며, 조회에 실패하면 실패 사유·현재 버전·github_url과 함께 422를 반환합니다. `core.settings.update` 권한이 필요하고, 관리자가 업데이트 확인 버튼을 눌러 새 버전 유무를 점검하는 시나리오에 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
# Dashboard API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Dashboard 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/dashboard/activities
|
||||
<!-- @generated:start:api.admin.dashboard.activities -->
|
||||
- **라우트명**: `api.admin.dashboard.activities`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\DashboardController@activities`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.dashboard.activities`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| type | string | `user` | 활동 분류 (log_type Enum 값 — admin: 관리자, user: 사용자, system: 시스템) |
|
||||
| icon | string | `circle-info` | 아이콘 식별자 (아이콘 클래스/이름) |
|
||||
| icon_color | string | `green` | 분류별 색상 (log_type Enum variant() 파생 — admin: blue, user: green, system: gray) |
|
||||
| title | string | `첨부파일 다운로드 (게시물: 237)` | 제목 |
|
||||
| description | string | `API 문서 샘플 사용자` | 설명 (다국어 필드는 로케일별 값 객체) |
|
||||
| time | string | `4시간 전` | 상대 시각 표시 (예: "24초 전" — diffForHumans() 산물) |
|
||||
| timestamp | string | `2026-07-07T10:00:47+09:00` | 활동 발생 절대 시각 (created_at 을 사용자 타임존으로 변환한 ISO 8601) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.dashboard.activities`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자 대시보드에 표시할 최근 활동 내역(사용자 등록, 모듈 활성화 등)을 조회합니다. 인증(`auth:sanctum`)과 `core.dashboard.activities` 권한이 필요합니다. 각 항목은 유형·아이콘·제목·설명과 상대 시간(`time`)·절대 시각(`timestamp`)을 포함하며, 대시보드 최근 활동 카드를 렌더링할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/admin/dashboard/alerts
|
||||
<!-- @generated:start:api.admin.dashboard.alerts -->
|
||||
- **라우트명**: `api.admin.dashboard.alerts`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\DashboardController@alerts`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.dashboard.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.dashboard.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 시스템 업데이트·경고 등 관리자에게 알릴 시스템 알림 목록을 조회합니다. 인증(`auth:sanctum`)과 `core.dashboard.read` 권한이 필요합니다. 알릴 항목이 없으면 빈 목록을 반환하며(위 실측이 빈 상태였던 이유), 대시보드 상단 시스템 알림 영역을 렌더링할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/admin/dashboard/recent-notifications
|
||||
<!-- @generated:start:api.admin.dashboard.recent-notifications -->
|
||||
- **라우트명**: `api.admin.dashboard.recent-notifications`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\DashboardController@recentNotifications`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.notification-logs.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `677` | 기본 키 (내부 식별자) |
|
||||
| type | string | `apidoc.sample.event` | 알림 유형 식별자 (notification_type — 발송을 유발한 알림 정의 키) |
|
||||
| channel | string | `mail` | 발송 채널 (mail: 이메일, database: 인앱, sms 등 알림이 전달된 매체) |
|
||||
| recipient | string | `API 문서 샘플 사용자` | 수신자 표시명 (recipientUser 관계의 name → recipient_name → recipient_identifier 순 폴백) |
|
||||
| subject | string | `API 문서 샘플 알림` | 알림 제목 (subject 를 50자로 절삭한 값) |
|
||||
| status | string | `sent` | 발송 상태 (status Enum 값 — sent: 발송 성공, failed: 발송 실패, skipped: 발송 건너뜀) |
|
||||
| time | string | `19시간 전` | 상대 시각 표시 (예: "24초 전" — diffForHumans() 산물) |
|
||||
| timestamp | string | `2026-07-06T18:20:23+09:00` | 발송 절대 시각 (sent_at, 없으면 created_at 을 사용자 타임존으로 변환한 ISO 8601) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.notification-logs.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 대시보드 "최근 알림" 카드에 표시할 최근 알림 발송 이력을 조회합니다. 인증(`auth:sanctum`)과 `core.notification-logs.read` 권한이 필요합니다. 각 항목은 알림 타입·채널·수신자·제목·상태와 상대 시간(`time`)·절대 시각(`timestamp`)을 포함하며, 전체 이력 목록(notification-logs)의 요약 뷰를 대시보드에 노출할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/admin/dashboard/resources
|
||||
<!-- @generated:start:api.admin.dashboard.resources -->
|
||||
- **라우트명**: `api.admin.dashboard.resources`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\DashboardController@resources`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.dashboard.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| cpu | object | `{"percentage":6,"color":"green"}` | CPU 사용률 정보 (percentage: 0~100 사용률, color: 임계 색상 — green<50, blue 50~69, yellow 70~89, red≥90) |
|
||||
| memory | object | `{"percentage":96,"used":"30.1 GB","total":"31.5 GB","colo…` | 메모리 사용량 정보 (percentage 사용률, used/total: 사용량·총량 형식화 문자열, color: 임계 색상). 수집 불가 시 percentage 0·"알 수 없음"·color gray 폴백 |
|
||||
| disk | object | `{"percentage":76,"used":"360.2 GB","total":"474.7 GB","co…` | 디스크 사용량 정보 (percentage 사용률, used/total: 사용량·총량 형식화 문자열, color: 임계 색상). 수집 불가 시 percentage 0·"알 수 없음"·color gray 폴백 |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.dashboard.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 서버의 CPU·메모리·디스크 사용량을 조회합니다. 인증(`auth:sanctum`)과 `core.dashboard.read` 권한이 필요합니다. 각 항목은 사용률(`percentage`)과 상태 색상(`color`), 메모리·디스크의 경우 사용량/총량 문자열을 포함하며, 대시보드 시스템 리소스 게이지를 렌더링할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/admin/dashboard/stats
|
||||
<!-- @generated:start:api.admin.dashboard.stats -->
|
||||
- **라우트명**: `api.admin.dashboard.stats`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\DashboardController@stats`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.dashboard.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| total_users | object | `{"count":156,"change_percent":15500,"change_display":"+15…` | 전체 사용자 수 (통계 객체는 count/추이 포함) |
|
||||
| installed_modules | object | `{"total":3,"active":3}` | 설치된 모듈 집계 객체 (total/active) |
|
||||
| active_plugins | object | `{"total":9,"active":9}` | 활성 플러그인 집계 객체 (total/active) |
|
||||
| installed_templates | object | `{"total":2,"active":2}` | 설치된 템플릿 집계 객체 (total/active) |
|
||||
| language_packs | object | `{"total":20,"active":16}` | 언어팩 집계 객체 (active: 현재 활성 언어팩 수, total: 활성 + 미설치 번들 팩 수) |
|
||||
| system_status | object | `{"status":"normal","label":"정상","all_services_running":true}` | 시스템 상태 객체 (status: normal 정상 / warning 경고, label: 상태 다국어 라벨, all_services_running: 전체 서비스 정상 동작 여부) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.dashboard.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 대시보드 상단 통계 카드에 표시할 집계 데이터를 조회합니다. 인증(`auth:sanctum`)과 `core.dashboard.read` 권한이 필요합니다. 총 사용자 수(증감률 포함), 설치/활성 모듈·플러그인·템플릿·언어팩 수, 시스템 상태를 객체 형태로 반환하며, 대시보드 진입 시 요약 지표를 렌더링할 때 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
# Extensions API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Extensions 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/extensions/auto-deactivated
|
||||
<!-- @generated:start:api.admin.extensions.auto-deactivated -->
|
||||
- **라우트명**: `api.admin.extensions.auto-deactivated`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ExtensionRecoveryController@autoDeactivated`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.activate`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| items | object | `{"plugins":[],"modules":[],"templates":[]}` | 코어 비호환으로 자동 비활성화된 확장을 타입별(`plugins`/`modules`/`templates`)로 묶은 목록. 각 원소는 식별자(`identifier`), 비호환 요구 버전(`incompatible_required_version`), 비활성화 시각(`deactivated_at`)을 가지며, 사용자가 dismiss했거나 hidden(학습용 샘플) 확장은 제외됨 |
|
||||
| current_core_version | string | `7.0.1` | 현재 설치된 코어 버전 |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.activate`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 코어 버전 비호환으로 자동 비활성화된 확장 목록을 타입별(`plugins`/`modules`/`templates`)로 반환합니다. 각 항목에는 식별자, 비호환 요구 버전, 비활성화 시각과 함께 현재 코어 버전이 담깁니다. 사용자가 dismiss한 알림과 hidden(학습용 샘플) 확장은 결과에서 제외됩니다. `core.plugins.activate` 권한이 필요하며, 상단 배너·대시보드 카드의 데이터 소스로 사용됩니다.
|
||||
|
||||
|
||||
### POST /api/admin/extensions/{type}/{identifier}/dismiss
|
||||
<!-- @generated:start:api.admin.extensions.dismiss -->
|
||||
- **라우트명**: `api.admin.extensions.dismiss`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ExtensionRecoveryController@dismiss`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.activate`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| type | path | string | 예 | module, plugin, template | 대상 확장의 타입 (module: 모듈, plugin: 플러그인, template: 템플릿). 타입에 맞는 Repository/Manager를 해석하는 데 사용되며 그 외 값은 422 |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.activate`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 확장의 호환성 알림을 현재 사용자 기준으로 dismiss(닫기) 처리합니다. 경로의 `{type}`(module|plugin|template)과 `{identifier}`로 대상을 지정하며, 해당 확장의 자동 비활성화 알림과 재호환 알림을 함께 dismiss합니다. `core.plugins.activate` 권한이 필요합니다. dismiss는 사용자별로 저장되므로, 캐시 만료나 감지 갱신 시 재호환 상태가 바뀌면 다시 노출될 수 있습니다.
|
||||
|
||||
|
||||
### POST /api/admin/extensions/{type}/{identifier}/recover
|
||||
<!-- @generated:start:api.admin.extensions.recover -->
|
||||
- **라우트명**: `api.admin.extensions.recover`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ExtensionRecoveryController@recover`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.activate`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| type | path | string | 예 | module, plugin, template | 대상 확장의 타입 (module: 모듈, plugin: 플러그인, template: 템플릿). 타입에 맞는 Repository/Manager를 해석하는 데 사용되며 그 외 값은 422 |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.activate`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 코어와 재호환된 확장을 원클릭으로 복구(재활성화)합니다. 경로의 `{type}`/`{identifier}`로 대상을 지정하며, 대상이 `IncompatibleCore` 사유로 자동 비활성화된 상태인지 검증한 뒤 코어 버전 재검증을 거쳐 활성화합니다. 잘못된 타입은 422, 미존재 확장은 404, hidden 확장이나 자동 비활성화가 아닌 경우는 error_code와 함께 422를 반환하고, 재검증 실패 시 글로벌 핸들러가 core_version_mismatch로 변환합니다. `core.plugins.activate` 권한이 필요합니다.
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,500 @@
|
||||
# Language Packs API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Language Packs 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/language-packs
|
||||
<!-- @generated:start:api.admin.language-packs.index -->
|
||||
- **라우트명**: `api.admin.language-packs.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| scope | query | string | 아니오 | — | 조회 범위 한정 키 |
|
||||
| target_identifier | query | string | 아니오 | max 150 | 대상 확장 식별자 |
|
||||
| locale | query | string | 아니오 | max 20 | 로케일 코드 (표시 언어/지역) |
|
||||
| status | query | string | 아니오 | — | 상태 필터 (해당 상태의 항목만 조회) |
|
||||
| vendor | query | string | 아니오 | max 100 | 벤더명 (확장 제작자 식별자) |
|
||||
| search | query | string | 아니오 | max 150 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
|
||||
| exclude_protected | query | boolean | 아니오 | — | 보호 항목 제외 여부 |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `16` | 기본 키 (내부 식별자) |
|
||||
| identifier | string | `g7-core-en` | 언어팩 고유 식별자 ({vendor}-{scope}-{target?}-{locale}) |
|
||||
| vendor | string | `g7` | 언어팩 제작자 식별자 |
|
||||
| scope | string | `core` | 적용 대상 분류 |
|
||||
| target_identifier | string | `gnuboard7-hello_module` | 대상 확장 식별자 (scope=core일 때 null) |
|
||||
| locale | string | `en` | IETF BCP-47 locale 태그 |
|
||||
| locale_name | string | `EN` | 영문 언어명 |
|
||||
| locale_native_name | string | `English` | 원어 언어명 |
|
||||
| text_direction | string | `ltr` | 텍스트 방향 |
|
||||
| version | string | `7.0.1` | 언어팩 버전 |
|
||||
| latest_version | string | `1.0.0` | 감지된 최신 배포 버전 |
|
||||
| target_version_constraint | null | `null` | 대상 확장 버전 제약 (semver) |
|
||||
| target_version_mismatch | boolean | `false` | 대상 버전 불일치 경고 플래그 |
|
||||
| name | string | `API 문서 샘플 언어팩` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| license | string | `MIT` | 라이선스 |
|
||||
| description | string | `문서 실측용 언어팩` | 언어팩 설명 (다국어) |
|
||||
| status | string | `active` | 언어팩 상태 |
|
||||
| is_protected | boolean | `true` | protected 여부 |
|
||||
| source_type | string | `built_in` | 설치 소스 유형 (zip/github/url/bundled/bundled_with_extension) |
|
||||
| origin | string | `built_in` | 출처 (설치/등록 원천 구분 값) |
|
||||
| source_url | string | `lang/en` | 설치 소스 URL 또는 경로 |
|
||||
| github_url | null | `null` | GitHub 저장소 URL (manifest 파생) |
|
||||
| github_changelog_url | null | `null` | GitHub 변경 이력(CHANGELOG) URL (manifest 파생) |
|
||||
| bundled_identifier | string | `g7-module-gnuboard7-hello_module-ja` | 대응하는 번들 확장 식별자 (번들 원본 매칭용) |
|
||||
| install_blocked_reason | string | `target_not_installed` | 설치가 차단된 사유 (차단 없으면 null) |
|
||||
| target_name | string | `게시판` | 대상 확장의 표시 이름 (scope+target_identifier 로 해석) |
|
||||
| installed_at | string | `2026-07-03 19:20:23` | installed 일시 |
|
||||
| activated_at | string | `2026-07-03 19:20:23` | activated 일시 |
|
||||
| created_at | string | `2026-07-06 19:20:23` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-06 19:20:23` | 최종 수정 일시 |
|
||||
| has_update | boolean | `false` | update 여부 |
|
||||
| abilities | object | `{"can_activate":true,"can_deactivate":true,"can_uninstall…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 설치된 언어팩과 번들 소스로부터 노출되는 언어팩 목록을 페이지네이션으로 조회합니다. `core.language_packs.read` 권한이 필요합니다. `scope`/`locale`/`status`/`vendor`/`search` 등으로 필터링하고 `exclude_protected` 로 보호(protected) 팩을 제외할 수 있습니다. 관리자 언어팩 관리 화면의 목록/필터 표시에 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/language-packs/bulk-activate
|
||||
<!-- @generated:start:api.admin.language-packs.bulk-activate -->
|
||||
- **라우트명**: `api.admin.language-packs.bulk-activate`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@bulkActivate`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.language_packs.bulk_activate_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.manage`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 전달된 `ids` 배열의 언어팩을 일괄 활성화합니다. `core.language_packs.manage` 권한이 필요합니다. 성공/실패를 분리한 결과를 반환하므로 일부만 실패해도 전체가 롤백되지 않습니다. 비활성 팩을 한 번에 재활성화하는 reactivate 모달의 "활성화" 동작에 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/language-packs/check-updates
|
||||
<!-- @generated:start:api.admin.language-packs.check-updates -->
|
||||
- **라우트명**: `api.admin.language-packs.check-updates`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@checkUpdates`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.update`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** GitHub 소스로 설치된 언어팩들의 원격 최신 버전을 조회해 업데이트 가능 여부를 확인합니다. `core.language_packs.update` 권한이 필요합니다. 실제 업데이트를 수행하지 않고 검사 결과(checked, updates, details)만 반환하며, 외부 GitHub 호출을 동반합니다. 언어팩 목록의 업데이트 배지 표시에 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/language-packs/install-from-bundled
|
||||
<!-- @generated:start:api.admin.language-packs.install-from-bundled -->
|
||||
- **라우트명**: `api.admin.language-packs.install-from-bundled`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@installFromBundled`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | body | string | 예 | max 200 | 대상 확장/리소스의 식별자 |
|
||||
| auto_activate | body | boolean | 아니오 | — | 설치 후 자동 활성화 여부 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** `lang-packs/_bundled/{identifier}` 디렉토리의 번들 소스에서 언어팩을 설치(또는 재설치)합니다. `core.language_packs.install` 권한이 필요합니다. `auto_activate` 가 true면 설치 후 곧바로 활성화합니다. 코어/확장에 선탑재된 번들 언어팩을 DB에 등록할 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/language-packs/install-from-file
|
||||
<!-- @generated:start:api.admin.language-packs.install-from-file -->
|
||||
- **라우트명**: `api.admin.language-packs.install-from-file`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@installFromFile`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| file | body | file | 예 | max 10240 | 업로드 파일 |
|
||||
| auto_activate | body | boolean | 아니오 | — | 설치 후 자동 활성화 여부 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 업로드된 ZIP 파일에서 언어팩을 설치합니다. `core.language_packs.install` 권한이 필요합니다. manifest 검증에 실패하면 422로 응답하며, `auto_activate` 가 true면 설치 후 즉시 활성화합니다. 관리자가 로컬 ZIP 파일을 직접 업로드해 언어팩을 추가하는 화면에 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/language-packs/install-from-github
|
||||
<!-- @generated:start:api.admin.language-packs.install-from-github -->
|
||||
- **라우트명**: `api.admin.language-packs.install-from-github`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@installFromGithub`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| github_url | body | string | 예 | — | GitHub 저장소 URL |
|
||||
| auto_activate | body | boolean | 아니오 | — | 설치 후 자동 활성화 여부 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** GitHub 저장소 URL에서 언어팩을 다운로드해 설치합니다. `core.language_packs.install` 권한이 필요합니다. 외부 GitHub 호출을 동반하며 manifest 검증 실패 시 422로 응답합니다. `auto_activate` 가 true면 설치 후 즉시 활성화합니다. GitHub로 배포되는 언어팩을 URL 만으로 설치할 때 사용하며, 이후 check-updates/update 로 갱신을 추적할 수 있습니다.
|
||||
|
||||
|
||||
### POST /api/admin/language-packs/install-from-url
|
||||
<!-- @generated:start:api.admin.language-packs.install-from-url -->
|
||||
- **라우트명**: `api.admin.language-packs.install-from-url`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@installFromUrl`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| url | body | string | 예 | max 500 | URL |
|
||||
| checksum | body | string | 아니오 | — | 무결성 검증 체크섬 (SHA-256) |
|
||||
| auto_activate | body | boolean | 아니오 | — | 설치 후 자동 활성화 여부 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 임의의 URL에서 언어팩 ZIP을 내려받아 설치합니다. `core.language_packs.install` 권한이 필요합니다. `checksum` 을 함께 전달하면 다운로드 무결성을 검증하며, manifest 검증 실패 시 422로 응답합니다. `auto_activate` 가 true면 설치 후 즉시 활성화합니다. GitHub 외 임의 호스팅에 배포된 언어팩을 설치할 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/language-packs/manifest-preview
|
||||
<!-- @generated:start:api.admin.language-packs.manifest-preview -->
|
||||
- **라우트명**: `api.admin.language-packs.manifest-preview`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@manifestPreview`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| file | body | file | 예 | max 5120 | 업로드 파일 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 업로드된 ZIP을 실제로 설치하지 않고 manifest 와 검증 결과만 미리 조회합니다. `core.language_packs.install` 권한이 필요합니다. 부수 효과 없이 읽기만 수행하며 검증 실패 시 422로 응답합니다. 설치 확인 모달에서 대상 언어팩의 메타데이터와 유효성을 미리 보여줄 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/language-packs/refresh-cache
|
||||
<!-- @generated:start:api.admin.language-packs.refresh-cache -->
|
||||
- **라우트명**: `api.admin.language-packs.refresh-cache`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@refreshCache`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.manage`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 번역/레지스트리/템플릿 언어 캐시를 무효화합니다. `core.language_packs.manage` 권한이 필요합니다. 언어팩 파일을 직접 수정했거나 활성 상태가 프론트에 반영되지 않을 때 캐시를 강제로 갱신하는 용도로 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/admin/language-packs/{id}
|
||||
<!-- @generated:start:api.admin.language-packs.uninstall -->
|
||||
- **라우트명**: `api.admin.language-packs.uninstall`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@uninstall`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| cascade | query | boolean | 아니오 | — | 연쇄 처리 여부 (의존 항목 함께 처리) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.manage`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 언어팩을 제거하고 설치된 파일을 삭제합니다. `core.language_packs.manage` 권한이 필요합니다. `cascade` 가 true면 연관 자원까지 함께 제거합니다. 대상이 존재하지 않으면 404로 응답합니다. 관리자 언어팩 관리 화면의 삭제(제거) 동작에 사용합니다.
|
||||
|
||||
|
||||
### GET /api/admin/language-packs/{id}
|
||||
<!-- @generated:start:api.admin.language-packs.show -->
|
||||
- **라우트명**: `api.admin.language-packs.show`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 단일 언어팩의 상세 정보를 조회합니다. `core.language_packs.read` 권한이 필요합니다. `{id}` 가 정수면 DB 레코드를, 문자열(번들 식별자)이면 `lang-packs/_bundled/{id}` manifest 로 합성된 가상 행을 반환합니다. 미설치 번들 언어팩까지 상세 모달로 열람할 수 있도록 하며, 없으면 404로 응답합니다.
|
||||
|
||||
|
||||
### POST /api/admin/language-packs/{id}/activate
|
||||
<!-- @generated:start:api.admin.language-packs.activate -->
|
||||
- **라우트명**: `api.admin.language-packs.activate`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@activate`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.manage`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 언어팩을 활성화합니다(슬롯 스위칭). `core.language_packs.manage` 권한이 필요합니다. 동일 슬롯(scope·target·locale)에 이미 다른 활성 팩이 있으면 409(slot_conflict)로 현재/대상 팩을 함께 반환하며, 프론트는 확인 모달을 띄운 뒤 `force=true` 로 재호출해 교체합니다. 대상이 없으면 404로 응답합니다.
|
||||
|
||||
|
||||
### GET /api/admin/language-packs/{id}/changelog
|
||||
<!-- @generated:start:api.admin.language-packs.changelog -->
|
||||
- **라우트명**: `api.admin.language-packs.changelog`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@changelog`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 언어팩의 CHANGELOG.md 내용을 반환합니다. `core.language_packs.read` 권한이 필요합니다. `{id}` 가 정수면 DB 레코드를, 문자열이면 번들 가상 행을 사용합니다. 파싱된 항목(entries), 원문(changelog), 존재 여부(has_changelog)를 함께 반환하며, CHANGELOG 파일이 없어도 빈 값으로 정상 응답합니다. 상세 모달의 변경 이력 탭에 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/language-packs/{id}/deactivate
|
||||
<!-- @generated:start:api.admin.language-packs.deactivate -->
|
||||
- **라우트명**: `api.admin.language-packs.deactivate`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@deactivate`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.manage`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 활성 언어팩을 비활성화합니다. `core.language_packs.manage` 권한이 필요합니다. 해당 슬롯의 번역 적용이 해제되며, 대상이 없으면 404로 응답합니다. 관리자 언어팩 관리 화면에서 활성 팩을 끄는 동작에 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/language-packs/{id}/update
|
||||
<!-- @generated:start:api.admin.language-packs.update -->
|
||||
- **라우트명**: `api.admin.language-packs.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LanguagePackController@performUpdate`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.language_packs.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.language_packs.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** GitHub 소스 언어팩을 최신 버전으로 다시 내려받아 적용합니다. `core.language_packs.update` 권한이 필요합니다. 외부 GitHub 재다운로드와 파일 교체를 동반하며, 갱신된 언어팩 정보를 반환합니다. 대상이 없으면 404로 응답합니다. check-updates 로 업데이트가 감지된 팩을 실제로 갱신할 때 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
# Layouts API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Layouts 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/layouts/preview/{token}.json
|
||||
<!-- @generated:start:api.public.layouts.preview.serve -->
|
||||
- **라우트명**: `api.public.layouts.preview.serve`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\LayoutPreviewController@serve`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| token | path | string | 예 | — | 인증/검증 토큰 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 편집 중인 레이아웃을 미리보기 토큰(UUID)으로 조회해 JSON으로 서빙합니다. 토큰으로 대상 레이아웃을 찾은 뒤 상속 병합과 확장(extension) 적용까지 마친 결과를 반환하며, 토큰이 유효하지 않으면 404를 반환합니다. 인증 미들웨어가 적용되지만 실질적 보안 메커니즘은 토큰 자체이며, 레이아웃 편집기에서 저장 전 변경분을 실제 렌더링으로 확인하는 용도입니다.
|
||||
|
||||
|
||||
### GET /api/layouts/{templateIdentifier}/{layoutName}.json
|
||||
<!-- @generated:start:api.public.layouts.serve -->
|
||||
- **라우트명**: `api.public.layouts.serve`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicLayoutController@serve`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| templateIdentifier | path | string | 예 | — | 대상 template의 식별자 |
|
||||
| layoutName | path | string | 예 | — | 대상 layout의 이름 (식별자) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 활성 템플릿의 병합된 레이아웃 JSON을 프론트엔드에 서빙합니다. 템플릿이 존재하고 활성 상태여야 하며, 상속 병합·확장 적용을 마친 결과를 ETag·Cache-Control 헤더와 함께 반환하고 미변경 시 304로 응답합니다. 레이아웃의 `permissions`에 따라 접근을 제한하고(비회원 401, 권한 부족 403), 컴포넌트 단위 권한 필터링을 사용자별로 적용합니다. 쿼리 `v`(정수 캐시 버전)로 캐시를 구분하며, `with_source_meta=1`은 `core.templates.layouts.edit` 권한이 있어야 노드별 출처 메타(편집기 전용)를 포함해 반환합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# License API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 License 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/license
|
||||
<!-- @generated:start:api.admin.license -->
|
||||
- **라우트명**: `api.admin.license`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\LicenseController@core`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| content | string | `프로그램 명칭 : 그누보드7 (Gnuboard7) 저작자 : (주…` | 본문 내용 |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 코어 라이선스 파일의 원문 텍스트를 `content`로 반환합니다. `auth:sanctum` 인증이 필요하며, 라이선스 파일이 없으면 404(`common.not_found`)를 반환합니다. 관리자 화면에서 코어 저작권·라이선스 고지를 표시하는 용도로 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# Locales API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Locales 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/locales/active
|
||||
<!-- @generated:start:api.public.locales.active -->
|
||||
- **라우트명**: `api.public.locales.active`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\LocaleController@active`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| locales | array | `["ko","en","fr","ja"]` | 활성 로케일 코드 배열 |
|
||||
| locale_names | object | `{"ko":"한국어","en":"English","ja":"日本語","fr":"Français"}` | 로케일 코드별 표시명 맵 (config app.locale_names) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). 인증·권한 미요구 엔드포인트로 도메인 특이 에러를 반환하지 않습니다._
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 현재 사이트가 즉시 노출 가능한 활성 로케일 목록과 로케일별 표시명(`locale_names`) 매핑을 반환합니다. 활성 코어 언어팩을 기준으로 산출되며 인증이 필요 없는 공개 엔드포인트입니다. 언어팩 설치·활성화 직후 사용자 언어 셀렉터를 새로고침 없이 갱신하는 시나리오에 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
# Me API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Me 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### DELETE /api/me
|
||||
<!-- @generated:start:api.me.destroy -->
|
||||
- **라우트명**: `api.me.destroy`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\ProfileController@destroy`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 로그인한 사용자가 자신의 계정을 탈퇴한다. 프론트의 회원 탈퇴 모달(`_modal_withdraw.json`)이 호출한다. 별도 요청 파라미터 없이 인증 토큰의 사용자를 대상으로 하며, `UserService::withdrawUser()` 가 아바타·토큰 삭제와 개인정보 익명화를 수행한다. 되돌릴 수 없는 작업이므로 호출 전 사용자 확인 절차를 두는 것을 권장한다.
|
||||
|
||||
|
||||
### GET /api/me
|
||||
<!-- @generated:start:api.me.show -->
|
||||
- **라우트명**: `api.me.show`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\ProfileController@show`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a231747f-e82e-4cf2-9ae1-a261849dce40` | 외부 노출용 UUID (URL/API 식별자, 내부 id 비노출) |
|
||||
| name | string | `API 문서 샘플 사용자` | 사용자 이름 |
|
||||
| nickname | string | `gunwoo.oh` | 닉네임 |
|
||||
| email | string | `apidoc-sample-user@example.com` | 이메일 주소 |
|
||||
| avatar | null | `null` | 아바타 이미지 URL (User::getAvatarUrl() 산물, 미등록 시 null) |
|
||||
| language | string | `ko` | 사용자 언어 설정 (ko: 한국어, en: 영어) |
|
||||
| timezone | string | `Asia/Seoul` | 사용자 시간대 (예: Asia/Seoul, UTC) |
|
||||
| country | string | `KR` | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| status | string | `active` | 계정 상태 (active: 활성, inactive: 비활성, blocked: 차단, withdrawn: 탈퇴) |
|
||||
| status_label | string | `활성` | 상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
|
||||
| status_variant | string | `success` | 상태 표시 색상/스타일 변형 키 (상태 Enum variant() 산물 — UI 배지용) |
|
||||
| homepage | string | `https://example.com` | 홈페이지 URL |
|
||||
| mobile | string | `010-9070-5662` | 휴대폰 번호 |
|
||||
| phone | string | `02-805-4759` | 전화번호 |
|
||||
| zipcode | string | `93153` | 우편번호 |
|
||||
| address | string | `대구광역시 북구 백제고분로 720` | 기본 주소 |
|
||||
| address_detail | string | `40동 835호` | 상세 주소 |
|
||||
| signature | string | `Ipsam rem amet expedita est.` | 서명 |
|
||||
| bio | string | `Tenetur omnis et amet omnis veniam to…` | 자기소개 |
|
||||
| is_super | boolean | `false` | super 여부 |
|
||||
| is_admin | boolean | `true` | 관리자 역할 보유 여부 (User::isAdmin() — 역할 관계 기반 파생) |
|
||||
| withdrawn_at | null | `null` | withdrawn 일시 |
|
||||
| last_login_at | string | `2026-07-05 19:15:16` | last login 일시 |
|
||||
| last_login_human | string | `1일 전` | 마지막 로그인 시각의 상대 표현 (diffForHumans() 산물, 사용자 시간대 기준) |
|
||||
| created_at | string | `2026-07-06 19:15:16` | 생성 일시 |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| notify_post_complete | boolean | `false` | 게시글 작성 완료 알림 수신 설정 (게시판 모듈 주입) |
|
||||
| notify_post_reply | boolean | `false` | 내 게시글에 대한 답글 알림 수신 설정 (게시판 모듈 주입) |
|
||||
| notify_comment | boolean | `false` | 내 게시글에 대한 댓글 알림 수신 설정 (게시판 모듈 주입) |
|
||||
| notify_reply_comment | boolean | `false` | 내 댓글에 대한 대댓글 알림 수신 설정 (게시판 모듈 주입) |
|
||||
| email_subscription | boolean | `false` | 광고성 이메일 수신 동의 여부 (마케팅 플러그인 주입, 채널) |
|
||||
| email_subscription_at | null | `null` | email subscription 일시 |
|
||||
| marketing_consent | boolean | `false` | 마케팅 정보 수신 전체 동의 마스터 키 (마케팅 플러그인 주입) |
|
||||
| marketing_consent_at | null | `null` | marketing consent 일시 |
|
||||
| third_party_consent | boolean | `false` | 제3자 정보 제공 동의 여부 (법적 항목, 마케팅 플러그인 주입) |
|
||||
| third_party_consent_at | null | `null` | third party consent 일시 |
|
||||
| info_disclosure | boolean | `false` | 개인정보 이용 안내 동의 여부 (법적 항목, 마케팅 플러그인 주입) |
|
||||
| info_disclosure_at | null | `null` | info disclosure 일시 |
|
||||
| marketing_consent_enabled | boolean | `true` | 마케팅 동의 항목 UI 노출 여부 (활성화 플래그) |
|
||||
| marketing_consent_terms_slug | string | `marketing-terms` | 마케팅 동의에 연결된 약관 slug (미설정 시 null) |
|
||||
| marketing_consent_terms_slug_set | boolean | `true` | 마케팅 동의 약관 연결 존재 여부 (프론트 링크 표시 판정용) |
|
||||
| third_party_consent_enabled | boolean | `true` | 제3자 제공 동의 항목 UI 노출 여부 (활성화 플래그) |
|
||||
| third_party_consent_terms_slug | null | `null` | 제3자 제공 동의에 연결된 약관 slug (미설정 시 null) |
|
||||
| third_party_consent_terms_slug_set | boolean | `false` | 제3자 제공 동의 약관 연결 존재 여부 (프론트 링크 표시 판정용) |
|
||||
| info_disclosure_enabled | boolean | `true` | 개인정보 이용 안내 동의 항목 UI 노출 여부 (활성화 플래그) |
|
||||
| info_disclosure_terms_slug | null | `null` | 개인정보 이용 안내 동의에 연결된 약관 slug (미설정 시 null) |
|
||||
| info_disclosure_terms_slug_set | boolean | `false` | 개인정보 이용 안내 동의 약관 연결 존재 여부 (프론트 링크 표시 판정용) |
|
||||
| email_subscription_enabled | boolean | `true` | 이메일 수신 동의 항목 UI 노출 여부 (활성화 플래그) |
|
||||
| email_subscription_terms_slug | null | `null` | 이메일 수신 동의에 연결된 약관 slug (미설정 시 null) |
|
||||
| email_subscription_terms_slug_set | boolean | `false` | 이메일 수신 동의 약관 연결 존재 여부 (프론트 링크 표시 판정용) |
|
||||
| channels | array | `[{"key":"email_subscription","label":"광고성 이메일 수신","enable…` | 관리자 정의 전체 마케팅 채널 목록 (원소 key/label/enabled/terms_slug, 마케팅 플러그인 주입) |
|
||||
| consent_histories | array | `[]` | 동의 변경 이력 (원소 channel_key/action/source/created_at, 마케팅 플러그인 주입) |
|
||||
| ecommerce_mileage | object | `{"enabled":false}` | 마일리지 정보 (enabled: 기능 활성 여부, 잔액, 이커머스 모듈 주입) |
|
||||
| ecommerce_preferred_currency | null | `null` | 선호 결제 통화 (이커머스 모듈 주입, 미설정 시 null) |
|
||||
| ecommerce_preferred_shipping_country | null | `null` | 선호 배송 국가 코드 (이커머스 모듈 주입, 미설정 시 null) |
|
||||
| ecommerce_preferred_shipping_country_name | null | `null` | 선호 배송 국가 이름 (코드 파생, 이커머스 모듈 주입, 미설정 시 null) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 로그인한 사용자의 프로필 정보를 조회한다. 프론트의 마이페이지(`mypage/profile.json`)와 프로필 수정 화면(`mypage/profile-edit.json`)이 소비한다. 응답은 `UserResource::toProfileArray()` 산물로, 비밀번호 등 민감 필드는 제외된다. 표의 `notify_*`(게시판 모듈)·`marketing_consent*`/`email_subscription*`/`third_party_consent*`/`info_disclosure*`/`channels`/`consent_histories`(마케팅 플러그인)·`ecommerce_*`(이커머스 모듈) 필드는 코어가 아니라 각 확장이 `core.user.filter_resource_data` 훅으로 병합하는 확장 소유 필드이며, 해당 확장이 비활성인 환경에서는 응답에 나타나지 않는다.
|
||||
|
||||
|
||||
### PUT /api/me
|
||||
<!-- @generated:start:api.me.update -->
|
||||
- **라우트명**: `api.me.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\ProfileController@update`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | string | 예 | max 255 | 대상의 이름/명칭 |
|
||||
| nickname | body | string | 아니오 | max 50 | 닉네임 |
|
||||
| email | body | email | 예 | max 255 | 이메일 주소 |
|
||||
| password | body | string | 아니오 | — | 비밀번호 |
|
||||
| current_password | body | string | 아니오 | — | 현재 비밀번호 (변경 전 확인용) |
|
||||
| language | body | string | 아니오 | — | 언어 코드 |
|
||||
| country | body | string | 아니오 | — | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| timezone | body | string | 아니오 | — | 타임존 식별자 |
|
||||
| homepage | body | string | 아니오 | max 255 | 홈페이지 URL |
|
||||
| mobile | body | string | 아니오 | max 20 | 휴대전화 번호 |
|
||||
| phone | body | string | 아니오 | max 20 | 전화번호 |
|
||||
| zipcode | body | string | 아니오 | max 10 | 우편번호 |
|
||||
| address | body | string | 아니오 | max 255 | 기본 주소 |
|
||||
| address_detail | body | string | 아니오 | max 255 | 상세 주소 |
|
||||
| signature | body | string | 아니오 | max 1000 | 서명 |
|
||||
| bio | body | string | 아니오 | max 5000 | 자기소개 |
|
||||
| notify_post_complete | body | boolean | 아니오 | — | 게시글 작성 완료 알림 수신 설정 (게시판 모듈 추가) |
|
||||
| notify_post_reply | body | boolean | 아니오 | — | 내 게시글에 대한 답글 알림 수신 설정 (게시판 모듈 추가) |
|
||||
| notify_comment | body | boolean | 아니오 | — | 내 게시글에 대한 댓글 알림 수신 설정 (게시판 모듈 추가) |
|
||||
| notify_reply_comment | body | boolean | 아니오 | — | 내 댓글에 대한 대댓글 알림 수신 설정 (게시판 모듈 추가) |
|
||||
| email_subscription | body | boolean | 아니오 | — | 광고성 이메일 수신 동의 (마케팅 플러그인 추가, 채널) |
|
||||
| marketing_consent | body | boolean | 아니오 | — | 마케팅 정보 수신 전체 동의 마스터 키 (마케팅 플러그인 추가) |
|
||||
| third_party_consent | body | boolean | 아니오 | — | 제3자 정보 제공 동의 (법적 항목, 마케팅 플러그인 추가) |
|
||||
| info_disclosure | body | boolean | 아니오 | — | 개인정보 이용 안내 동의 (법적 항목, 마케팅 플러그인 추가) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.user.update_profile_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 로그인한 사용자가 자신의 프로필을 수정한다. 프론트의 프로필 수정 화면(`partials/mypage/profile/_edit.json`)이 사용한다. `name`·`email` 은 필수이며 `email` 은 본인을 제외한 중복이 허용되지 않는다. 비밀번호를 함께 변경하려면 `password`(+ `password_confirmation`)와 현재 비밀번호(`current_password`)를 함께 보내야 하며, `password` 가 빈 문자열이면 비밀번호 미변경으로 처리된다. `notify_*`·`marketing_consent`·`email_subscription` 등 확장 소유 파라미터는 게시판 모듈·마케팅 플러그인이 `core.user.update_profile_validation_rules` 훅으로 추가하며, 해당 확장이 비활성인 환경에서는 수용되지 않는다. 성공 시 갱신된 프로필이 `UserResource` 형태로 반환된다.
|
||||
|
||||
|
||||
@@ -0,0 +1,418 @@
|
||||
# Menus API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Menus 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/menus
|
||||
<!-- @generated:start:api.admin.menus.index -->
|
||||
- **라우트명**: `api.admin.menus.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\MenuController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.menus.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| is_active | query | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| filters | query | array | 아니오 | max 10 | 추가 필터 조건 맵 (필드별 조건) |
|
||||
| sort_by | query | string | 아니오 | `created_at`, `name`, `slug`, `order` | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.menu.list_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"대시보드","en":"Dashboard","ja":"ダッシュボード"}` | 메뉴 이름 (다국어 JSON) |
|
||||
| slug | string | `admin-dashboard` | 메뉴 슬러그 |
|
||||
| url | string | `/admin/dashboard` | 메뉴 URL |
|
||||
| icon | string | `fas fa-tachometer-alt` | 메뉴 아이콘 |
|
||||
| order | integer | `1` | 메뉴 순서 |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| parent_id | null | `null` | 상위 메뉴 ID |
|
||||
| extension_type | string | `core` | 확장 소유 타입: core(코어), module(모듈), plugin(플러그인), NULL(사용자 정의) |
|
||||
| extension_identifier | string | `core` | 확장 식별자 (예: core, sirsoft-board, sirsoft-payment) |
|
||||
| children | array | `[]` | 하위 항목 배열 (계층 트리 — children 관계 파생) |
|
||||
| creator | null | `null` | 생성자 정보 객체 (uuid/name/email — creator 관계 파생) |
|
||||
| roles | array | `[{"id":1,"name":{"ko":"관리자","en":"Administrator"},"permis…` | 이 메뉴 노출이 허용된 역할 목록 (원소 id/name/permission_type — roles 관계 파생, permission_type 은 pivot 의 노출 권한 유형) |
|
||||
| created_at | string | `2026-05-27 15:20:18` | 생성 일시 |
|
||||
| updated_at | string | `2026-05-27 15:21:38` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `false` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.menus.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
관리자 메뉴 관리 화면(`partials/admin_menu_list/*`)의 목록 표시 기준 엔드포인트. `is_active` 또는 `filters` 가 있으면 필터링된 관리용 메뉴를, 없으면 최상위 메뉴 전체를 반환한다. `filters` 는 `field`(name/slug/url/all)·`value`·`operator`(like/eq/starts_with/ends_with) 조합의 배열이며 최대 10개까지 허용된다. `name` 은 다국어 JSON 객체로 내려오고, 각 항목에 `children`/`creator`/`roles` 관계와 `abilities`(현재 사용자의 수정/삭제 가능 여부)가 포함된다. 인증 계약: `auth:sanctum` + `permission:core.menus.read`.
|
||||
|
||||
|
||||
### POST /api/admin/menus
|
||||
<!-- @generated:start:api.admin.menus.store -->
|
||||
- **라우트명**: `api.admin.menus.store`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\MenuController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.menus.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | string | 예 | — | 대상의 이름/명칭 |
|
||||
| slug | body | string | 예 | max 255 | URL 친화 식별자 (slug) |
|
||||
| url | body | string | 아니오 | max 500 | URL |
|
||||
| icon | body | string | 아니오 | max 100 | 아이콘 |
|
||||
| parent_id | body | integer | 아니오 | — | parent 식별자 |
|
||||
| order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| extension_type | body | string | 아니오 | `core`, `module`, `plugin` | 확장 유형 (core/module/plugin/template) |
|
||||
| extension_identifier | body | string | 아니오 | max 255 | 확장 식별자 |
|
||||
| roles | body | array | 아니오 | — | 이 메뉴 노출을 허용할 역할 ID 배열 (각 원소는 존재하는 role id — 지정 시 노출 허용 역할 목록으로 설정/교체) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.menu.create_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.menus.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
새 메뉴를 생성한다. `name` 은 다국어 값(문자열로 보내면 지원 로케일 전체에 동일 값으로 자동 확장)이며 `slug` 는 `menus` 테이블 내 유일해야 한다. `parent_id` 로 하위 메뉴를 만들 수 있고, `roles` 배열로 이 메뉴 노출을 허용할 역할 ID 를 지정한다. 성공 시 `201` 과 함께 생성된 메뉴(관계 eager-load 포함)를 `MenuResource` 로 반환한다. 관리자 메뉴 관리 화면의 메뉴 추가 폼에서 소비된다. 인증 계약: `auth:sanctum` + `permission:core.menus.create`.
|
||||
|
||||
|
||||
### GET /api/admin/menus/active
|
||||
<!-- @generated:start:api.admin.menus.active -->
|
||||
- **라우트명**: `api.admin.menus.active`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\MenuController@active`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.menus.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"대시보드","en":"Dashboard","ja":"ダッシュボード"}` | 메뉴 이름 (다국어 JSON) |
|
||||
| slug | string | `admin-dashboard` | 메뉴 슬러그 |
|
||||
| url | string | `/admin/dashboard` | 메뉴 URL |
|
||||
| icon | string | `fas fa-tachometer-alt` | 메뉴 아이콘 |
|
||||
| order | integer | `1` | 메뉴 순서 |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| children | array | `[]` | 하위 항목 배열 (계층 트리 — children 관계 파생) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.menus.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
관리자 레이아웃 전역 부트스트랩 엔드포인트. `sirsoft-admin_basic/layouts/_admin_base.json` 의 `admin_menu` `data_source`(`/api/admin/menus/active`)가 모든 관리자 페이지 진입 시 자동 호출해, 사이드바 메뉴 트리를 채운다. 인증 사용자의 역할 기준으로 접근 가능한 활성 메뉴만 계층 구조(`children` 중첩)로 반환하며, `data` 는 최상위 메뉴 배열이다. 사용자 정보가 없을 때는 모든 활성 메뉴를 fallback 으로 반환한다. 인증 계약: `auth:sanctum` + `permission:core.menus.read`.
|
||||
|
||||
|
||||
### GET /api/admin/menus/extension/{type}/{identifier}
|
||||
<!-- @generated:start:api.admin.menus.by-extension -->
|
||||
- **라우트명**: `api.admin.menus.by-extension`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\MenuController@getByExtension`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.menus.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| type | path | string | 예 | — | 확장 소유 타입 (ExtensionOwnerType 으로 파싱 — module: 모듈, plugin: 플러그인. 미유효 값이면 422 menu.invalid_extension_type) |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.menus.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
특정 확장이 소유한 메뉴 목록을 조회한다. `type` 은 `ExtensionOwnerType`(module, plugin)으로 파싱되며, 유효하지 않은 값이면 `422 menu.invalid_extension_type` 을 반환한다. `identifier` 는 확장 식별자(예: `sirsoft-board`)로, 해당 확장이 등록한 메뉴만 `MenuCollection` 으로 내려준다. 확장 설치/제거 시 그 확장 소유 메뉴를 확인·정리하는 관리 흐름에서 사용된다. 인증 계약: `auth:sanctum` + `permission:core.menus.read`.
|
||||
|
||||
|
||||
### GET /api/admin/menus/hierarchy
|
||||
<!-- @generated:start:api.admin.menus.hierarchy -->
|
||||
- **라우트명**: `api.admin.menus.hierarchy`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\MenuController@hierarchy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.menus.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"대시보드","en":"Dashboard","ja":"ダッシュボード"}` | 메뉴 이름 (다국어 JSON) |
|
||||
| slug | string | `admin-dashboard` | 메뉴 슬러그 |
|
||||
| url | string | `/admin/dashboard` | 메뉴 URL |
|
||||
| icon | string | `fas fa-tachometer-alt` | 메뉴 아이콘 |
|
||||
| order | integer | `1` | 메뉴 순서 |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| children | array | `[]` | 하위 항목 배열 (계층 트리 — children 관계 파생) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.menus.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
전체 메뉴를 계층 구조로 반환한다. `MenuService::getMenuHierarchy()` 로 조회한 메뉴를 `MenuCollection::toNavigationArray()` 로 변환해 최상위 메뉴 + `children` 중첩 형태로 내려준다. `active` 와 달리 사용자 역할 기반 접근 필터 없이 메뉴 트리 전체를 노출하므로, 관리자 메뉴 관리 화면의 트리 표현·순서 편집 기준 데이터로 사용된다. 인증 계약: `auth:sanctum` + `permission:core.menus.read`.
|
||||
|
||||
|
||||
### PUT /api/admin/menus/order
|
||||
<!-- @generated:start:api.admin.menus.update-order -->
|
||||
- **라우트명**: `api.admin.menus.update-order`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\MenuController@updateOrder`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.menus.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| parent_menus | body | array | 예 | min 1 | 최상위 메뉴의 새 순서 목록 (원소 `{id, order}` — id: 대상 메뉴, order: 1 이상 표시 순번) |
|
||||
| child_menus | body | array | 아니오 | — | 부모별 하위 메뉴의 새 순서 목록 (부모 그룹핑된 2차원 배열, 각 원소 `{id, order}` — id: 하위 메뉴, order: 1 이상 표시 순번) |
|
||||
| moved_items | body | array | 아니오 | — | 부모가 바뀐 항목 목록 (원소 `{id, new_parent_id}` — new_parent_id 는 새 부모 메뉴 ID 또는 null(최상위 이동), 순환 참조(자기 자신·자손 지정) 시 거부) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.menu.update_order_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.menus.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
관리자 메뉴 관리 화면의 드래그 앤 드롭 순서 변경을 반영한다. `parent_menus` 는 `{id, order}` 배열로 최상위 메뉴 순서를, `child_menus` 는 부모별 하위 메뉴 순서를, `moved_items` 는 부모가 바뀐 항목(`{id, new_parent_id}`)을 전달한다. `moved_items` 의 `new_parent_id` 에는 순환 참조 방지(`NotCircularParent`) 검증이 적용되어, 자기 자신이나 자손을 부모로 지정하면 거부된다. 각 id/parent_id 는 실제 메뉴로 존재해야 한다. 응답은 성공 메시지만 반환한다. 인증 계약: `auth:sanctum` + `permission:core.menus.update`.
|
||||
|
||||
|
||||
### DELETE /api/admin/menus/{menu}
|
||||
<!-- @generated:start:api.admin.menus.destroy -->
|
||||
- **라우트명**: `api.admin.menus.destroy`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\MenuController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.menus.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| menu | path | string | 예 | — | 대상 menu의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.menus.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
지정한 메뉴를 삭제한다. `{menu}` 는 라우트 모델 바인딩으로 해석되며, 삭제는 `MenuService::deleteMenu()` 가 수행한다. 성공 시 `menu.delete_success` 메시지만 반환하고, 삭제 불가 조건은 `422 menu.delete_failed` 로 내려온다. 관리자 메뉴 관리 화면의 메뉴 삭제 동작에서 소비된다. 인증 계약: `auth:sanctum` + `permission:core.menus.delete`.
|
||||
|
||||
|
||||
### GET /api/admin/menus/{menu}
|
||||
<!-- @generated:start:api.admin.menus.show -->
|
||||
- **라우트명**: `api.admin.menus.show`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\MenuController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.menus.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| menu | path | string | 예 | — | 대상 menu의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `33` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"API 문서 샘플 메뉴","en":"API Doc Sample Menu"}` | 메뉴 이름 (다국어 JSON) |
|
||||
| slug | string | `apidoc-sample-menu` | 메뉴 슬러그 |
|
||||
| url | string | `/admin/apidoc-sample` | 메뉴 URL |
|
||||
| icon | string | `fas fa-book` | 메뉴 아이콘 |
|
||||
| order | integer | `28` | 메뉴 순서 |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| parent_id | null | `null` | 상위 메뉴 ID |
|
||||
| extension_type | null | `null` | 확장 소유 타입: core(코어), module(모듈), plugin(플러그인), NULL(사용자 정의) |
|
||||
| extension_identifier | null | `null` | 확장 식별자 (예: core, sirsoft-board, sirsoft-payment) |
|
||||
| parent | null | `null` | 상위 항목 객체 (parent 관계 파생) |
|
||||
| children | array | `[{"id":34,"name":{"ko":"하위 메뉴","en":"Child Menu"},"slug":…` | 하위 항목 배열 (계층 트리 — children 관계 파생) |
|
||||
| creator | object | `{"uuid":"a231747f-e82e-4cf2-9ae1-a261849dce40","name":"AP…` | 생성자 정보 객체 (uuid/name/email — creator 관계 파생) |
|
||||
| roles | array | `[]` | 이 메뉴 노출이 허용된 역할 목록 (원소 id/name/permission_type — roles 관계 파생, permission_type 은 pivot 의 노출 권한 유형) |
|
||||
| created_at | string | `2026-07-06 19:15:16` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-06 19:15:16` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.menus.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
단일 메뉴의 상세 정보를 조회한다. `{menu}` 는 라우트 모델 바인딩으로 해석되며, `creator`/`parent`/`children`/`roles` 관계를 eager-load 해 함께 반환한다. `children` 에는 하위 메뉴가 order 오름차순으로, 각 하위 메뉴의 `roles` 까지 포함된다. 관리자 메뉴 관리 화면의 메뉴 편집 폼 초기값 로딩에 사용된다. 인증 계약: `auth:sanctum` + `permission:core.menus.read`.
|
||||
|
||||
|
||||
### PUT /api/admin/menus/{menu}
|
||||
<!-- @generated:start:api.admin.menus.update -->
|
||||
- **라우트명**: `api.admin.menus.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\MenuController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.menus.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| menu | path | string | 예 | — | 대상 menu의 식별자 |
|
||||
| name | body | string | 아니오 | — | 대상의 이름/명칭 |
|
||||
| slug | body | string | 예 | max 255 | URL 친화 식별자 (slug) |
|
||||
| url | body | string | 아니오 | max 500 | URL |
|
||||
| icon | body | string | 아니오 | max 100 | 아이콘 |
|
||||
| parent_id | body | integer | 아니오 | — | parent 식별자 |
|
||||
| order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| extension_type | body | string | 아니오 | `core`, `module`, `plugin` | 확장 유형 (core/module/plugin/template) |
|
||||
| extension_identifier | body | string | 아니오 | max 255 | 확장 식별자 |
|
||||
| roles | body | array | 아니오 | — | 이 메뉴 노출을 허용할 역할 ID 배열 (각 원소는 존재하는 role id — 지정 시 노출 허용 역할 목록으로 설정/교체) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.menu.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.menus.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
기존 메뉴 정보를 수정한다. `{menu}` 는 라우트 모델 바인딩으로 해석되며, 전달된 필드만 갱신한다. `slug` 는 여전히 유일해야 하고, `roles` 배열을 보내면 이 메뉴 노출이 허용된 역할 목록을 교체한다. 성공 시 갱신된 메뉴를 관계 eager-load 포함해 `MenuResource` 로 반환하고, 실패 시 `menu.update_failed`(422 검증 오류 포함)를 반환한다. 관리자 메뉴 관리 화면의 메뉴 편집 폼 저장에서 소비된다. 인증 계약: `auth:sanctum` + `permission:core.menus.update`.
|
||||
|
||||
|
||||
### PATCH /api/admin/menus/{menu}/toggle-status
|
||||
<!-- @generated:start:api.admin.menus.toggle-status -->
|
||||
- **라우트명**: `api.admin.menus.toggle-status`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\MenuController@toggleStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.menus.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| menu | path | string | 예 | — | 대상 menu의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.menus.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
지정한 메뉴의 활성화 상태(`is_active`)를 반대 값으로 토글한다. `{menu}` 는 라우트 모델 바인딩으로 해석되며, 본문 파라미터 없이 현재 상태를 뒤집는다. 성공 시 갱신된 메뉴를 `MenuResource` 로 반환한다. 관리자 메뉴 관리 화면의 활성/비활성 스위치에서 소비된다. 인증 계약: `auth:sanctum` + `permission:core.menus.update`.
|
||||
|
||||
|
||||
@@ -0,0 +1,829 @@
|
||||
# Modules API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Modules 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/modules
|
||||
<!-- @generated:start:api.admin.modules.index -->
|
||||
- **라우트명**: `api.admin.modules.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.read|core.menus.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| search | query | string | 아니오 | max 255 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
|
||||
| filters | query | array | 아니오 | max 10 | 추가 필터 조건 맵 (필드별 조건) |
|
||||
| status | query | string | 아니오 | `installed`, `not_installed`, `active`, `inactive` | 상태 필터 (해당 상태의 항목만 조회) |
|
||||
| with | query | array | 아니오 | max 5 | 함께 포함할 추가 데이터 옵션 목록 (허용값 `custom_menus` — 각 모듈의 커스텀 메뉴 데이터 포함) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
| include_hidden | query | boolean | 아니오 | — | manifest `hidden=true` 로 표시된 숨김 확장까지 목록에 포함할지 여부 (기본 제외) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.module.index_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| identifier | string | `sirsoft-board` | 모듈 고유 식별자 (vendor-module 형식) |
|
||||
| vendor | string | `sirsoft` | 벤더/개발자명 |
|
||||
| name | string | `게시판` | 모듈 이름 (다국어 JSON) |
|
||||
| version | string | `1.0.0` | 모듈 버전 |
|
||||
| description | string | `게시판 관리를 위한 모듈` | 모듈 설명 (다국어 JSON) |
|
||||
| dependencies | array | `[]` | 의존하는 확장 맵 (manifest 파생 — {modules, plugins}) |
|
||||
| status | string | `active` | 상태 (active: 활성화, inactive: 비활성화, installing: 설치 중, uninstalling: 제거 중, updating: 업데이트 중) |
|
||||
| assets | object | `{"js":"\/api\/modules\/assets\/sirsoft-ecommerce\/dist\/j…` | 프론트엔드 에셋 매니페스트 (manifest 파생 — js/css 진입점·로딩 전략) |
|
||||
| update_available | boolean | `false` | 최신 버전 대비 업데이트 가능 여부 |
|
||||
| update_source | null | `null` | 업데이트 감지 출처 (github, bundled 등) |
|
||||
| latest_version | string | `1.0.0` | 감지된 최신 배포 버전 |
|
||||
| file_version | string | `1.0.0` | 설치된 파일의 manifest 버전 |
|
||||
| github_url | string | `https://github.com/gnuboard/g7-module…` | GitHub 저장소 URL |
|
||||
| github_changelog_url | string | `https://github.com/gnuboard/g7-module…` | GitHub 변경 내역 URL |
|
||||
| is_pending | boolean | `false` | _pending 대기소에 있어 설치 대기 중인지 여부 |
|
||||
| is_bundled | boolean | `false` | 코어에 선탑재된 번들 확장인지 여부 |
|
||||
| deactivated_reason | null | `null` | 비활성화 사유: manual(사용자 수동) \| incompatible_core(코어 버전 호환성) \| null(active) |
|
||||
| deactivated_at | null | `null` | deactivated 일시 |
|
||||
| incompatible_required_version | null | `null` | 요구 코어 버전 미충족 시 필요한 버전 (호환되면 null) |
|
||||
| abilities | object | `{"can_install":true,"can_activate":true,"can_uninstall":t…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.read|core.menus.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 설치된 모듈과 미설치 모듈을 모두 포함한 전체 모듈 목록을 페이지네이션으로 조회합니다. `search` 는 이름·식별자·설명·벤더에 대한 OR 검색이고 `filters` 는 AND 조건으로 적용되며, `with[]` 에 `custom_menus` 를 지정하면 커스텀 메뉴 데이터를 함께 포함합니다. `core.modules.read` 또는 `core.menus.read` 권한 중 하나가 필요하고, 응답의 `abilities` 는 현재 사용자의 수행 가능 작업 맵을 담습니다. 관리자 모듈 관리 화면의 목록 그리드를 구성하는 기본 엔드포인트입니다.
|
||||
|
||||
|
||||
### POST /api/admin/modules/activate
|
||||
<!-- @generated:start:api.admin.modules.activate -->
|
||||
- **라우트명**: `api.admin.modules.activate`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@activate`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.activate`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| module_name | body | string | 예 | max 255 | module 이름 (식별자) |
|
||||
| force | body | boolean | 아니오 | — | 강제 실행 여부 (안전 확인/선행 검사 우회) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.module.activate_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.activate`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 설치된 모듈을 활성화합니다. `core.modules.activate` 권한이 필요합니다. `force` 없이 호출했을 때 필요한 의존 확장이 충족되지 않으면 409 응답으로 `missing_modules`·`missing_plugins` 목록과 함께 경고를 반환하므로, 사용자 확인 후 `force: true` 로 재요청해야 합니다. 재활성화 시 cascade 로 함께 비활성화됐던 번들 언어팩 목록이 `pending_language_packs` 로 응답에 포함됩니다.
|
||||
|
||||
|
||||
### POST /api/admin/modules/check-updates
|
||||
<!-- @generated:start:api.admin.modules.check-updates -->
|
||||
- **라우트명**: `api.admin.modules.check-updates`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@checkUpdates`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.install`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 설치된 모든 모듈에 대해 GitHub·번들 소스를 조회하여 새 버전 배포 여부를 일괄 확인합니다. `core.modules.install` 권한이 필요합니다. 파라미터 없이 호출하며, 각 모듈의 업데이트 가능 여부와 감지된 최신 버전 정보를 반환합니다. 모듈 목록 화면 진입 시 업데이트 뱃지를 갱신하는 용도로 사용됩니다.
|
||||
|
||||
|
||||
### POST /api/admin/modules/deactivate
|
||||
<!-- @generated:start:api.admin.modules.deactivate -->
|
||||
- **라우트명**: `api.admin.modules.deactivate`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@deactivate`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.activate`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| module_name | body | string | 예 | max 255 | module 이름 (식별자) |
|
||||
| force | body | boolean | 아니오 | — | 강제 실행 여부 (안전 확인/선행 검사 우회) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.module.deactivate_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.activate`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 활성 모듈을 비활성화합니다. `core.modules.activate` 권한이 필요합니다. `force` 없이 호출했을 때 이 모듈에 의존하는 템플릿·모듈·플러그인이 있으면 409 응답으로 `dependent_templates`·`dependent_modules`·`dependent_plugins` 목록과 함께 경고를 반환합니다. 의존 관계 확인 후 `force: true` 로 강제 비활성화할 수 있습니다.
|
||||
|
||||
|
||||
### POST /api/admin/modules/install
|
||||
<!-- @generated:start:api.admin.modules.install -->
|
||||
- **라우트명**: `api.admin.modules.install`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@install`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| module_name | body | string | 예 | max 255 | module 이름 (식별자) |
|
||||
| vendor_mode | body | string | 아니오 | `auto`, `composer`, `bundled` | 벤더 설치 모드 (auto/composer/bundled) |
|
||||
| dependencies | body | array | 아니오 | — | 함께 설치할 의존 확장 목록 (cascade 1단계). 각 원소는 `type`(module\|plugin)·`identifier` 로 구성하며, install-preview 응답에서 사용자가 선택한 항목 |
|
||||
| language_packs | body | array | 아니오 | — | 함께 설치할 번들 언어팩 식별자 목록 (cascade 2단계, best-effort). 원소는 언어팩 식별자 문자열 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.module.install_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** `_pending`·`_bundled` 대기소에 있는 모듈을 활성 디렉토리로 설치합니다. `core.modules.install` 권한이 필요합니다. `vendor_mode` 로 Composer 의존성 설치 방식을(auto/composer/bundled) 지정하며, 요청 본문의 `dependencies` 로 선택한 의존 확장을 먼저 설치(cascade 1단계, 실패 시 전체 중단)한 뒤 `language_packs` 로 지정한 번들 언어팩을 best-effort 로 함께 설치합니다(cascade 2단계). 성공 시 201 상태로 반환하고, 언어팩 설치 실패는 응답의 `language_pack_failures` 에 담깁니다.
|
||||
|
||||
|
||||
### POST /api/admin/modules/install-from-file
|
||||
<!-- @generated:start:api.admin.modules.install-from-file -->
|
||||
- **라우트명**: `api.admin.modules.install-from-file`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@installFromFile`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| file | body | file | 예 | max 51200 | 업로드 파일 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.module.install_from_file_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 업로드된 ZIP 파일에서 모듈을 설치합니다. `core.modules.install` 권한이 필요하며, 파일은 최대 50MB(51200KB)까지 허용됩니다. ZIP 압축 해제 후 module.json 검증을 거쳐 설치하며, 성공 시 201 상태로 설치된 모듈 정보를 반환합니다. 설치 전 manifest 만 미리 확인하려면 `manifest-preview` 를 먼저 호출하는 것이 안전합니다.
|
||||
|
||||
|
||||
### POST /api/admin/modules/install-from-github
|
||||
<!-- @generated:start:api.admin.modules.install-from-github -->
|
||||
- **라우트명**: `api.admin.modules.install-from-github`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@installFromGithub`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| github_url | body | string | 예 | — | GitHub 저장소 URL |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.module.install_from_github_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** GitHub 저장소 URL 에서 모듈을 내려받아 설치합니다. `core.modules.install` 권한이 필요합니다. `github_url` 로 지정한 공개 저장소의 릴리스/소스를 받아 압축 해제·검증 후 설치하며, 성공 시 201 상태로 설치된 모듈 정보를 반환합니다.
|
||||
|
||||
|
||||
### GET /api/admin/modules/installed
|
||||
<!-- @generated:start:api.admin.modules.installed -->
|
||||
- **라우트명**: `api.admin.modules.installed`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@installed`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| identifier | string | `sirsoft-board` | 모듈 고유 식별자 (vendor-module 형식) |
|
||||
| vendor | string | `sirsoft` | 벤더/개발자명 |
|
||||
| name | string | `게시판` | 모듈 이름 (다국어 JSON) |
|
||||
| version | string | `1.0.0` | 모듈 버전 |
|
||||
| description | string | `게시판 관리를 위한 모듈` | 모듈 설명 (다국어 JSON) |
|
||||
| dependencies | array | `[]` | 의존하는 확장 맵 (manifest 파생 — {modules, plugins}) |
|
||||
| status | string | `active` | 상태 (active: 활성화, inactive: 비활성화, installing: 설치 중, uninstalling: 제거 중, updating: 업데이트 중) |
|
||||
| assets | object | `{"js":"\/api\/modules\/assets\/sirsoft-ecommerce\/dist\/j…` | 프론트엔드 에셋 매니페스트 (manifest 파생 — js/css 진입점·로딩 전략) |
|
||||
| update_available | boolean | `false` | 최신 버전 대비 업데이트 가능 여부 |
|
||||
| update_source | null | `null` | 업데이트 감지 출처 (github, bundled 등) |
|
||||
| latest_version | string | `1.0.0` | 감지된 최신 배포 버전 |
|
||||
| file_version | string | `1.0.0` | 설치된 파일의 manifest 버전 |
|
||||
| github_url | string | `https://github.com/gnuboard/g7-module…` | GitHub 저장소 URL |
|
||||
| github_changelog_url | string | `https://github.com/gnuboard/g7-module…` | GitHub 변경 내역 URL |
|
||||
| is_pending | boolean | `false` | _pending 대기소에 있어 설치 대기 중인지 여부 |
|
||||
| is_bundled | boolean | `false` | 코어에 선탑재된 번들 확장인지 여부 |
|
||||
| deactivated_reason | null | `null` | 비활성화 사유: manual(사용자 수동) \| incompatible_core(코어 버전 호환성) \| null(active) |
|
||||
| deactivated_at | null | `null` | deactivated 일시 |
|
||||
| incompatible_required_version | null | `null` | 요구 코어 버전 미충족 시 필요한 버전 (호환되면 null) |
|
||||
| abilities | object | `{"can_install":true,"can_activate":true,"can_uninstall":t…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 현재 설치된 모듈만 조회합니다(미설치 항목 제외). 이 엔드포인트는 세부 권한 미들웨어 없이 `auth:sanctum` 인증만 요구하므로, 다른 화면이 활성/설치된 모듈 목록을 참조할 때 사용하는 경량 조회 API 입니다. 페이지네이션 없이 설치된 항목 배열을 반환합니다.
|
||||
|
||||
|
||||
### POST /api/admin/modules/manifest-preview
|
||||
<!-- @generated:start:api.admin.modules.manifest-preview -->
|
||||
- **라우트명**: `api.admin.modules.manifest-preview`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@manifestPreview`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| file | body | file | 예 | max 51200 | 업로드 파일 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 업로드된 ZIP 파일의 module.json manifest 와 검증 결과만 추출합니다(실제 설치는 수행하지 않음). `core.modules.install` 권한이 필요하며 파일은 최대 50MB 까지 허용됩니다. 설치 모달에서 사용자가 파일 선택 직후 manifest 유효성과 검증 실패 사유를 미리 확인하는 용도이며, 검증 오류 시 422 로 사유를 반환합니다.
|
||||
|
||||
|
||||
### POST /api/admin/modules/refresh-layouts
|
||||
<!-- @generated:start:api.admin.modules.refresh-layouts -->
|
||||
- **라우트명**: `api.admin.modules.refresh-layouts`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@refreshLayouts`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.activate`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| module_name | body | string | 예 | max 255 | module 이름 (식별자) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.module.refresh_layouts_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.activate`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 모듈의 레이아웃 파일을 파일에서 다시 읽어 DB 에 동기화합니다. `core.modules.activate` 권한이 필요합니다. 파일에서 변경된 레이아웃은 갱신되고 삭제된 레이아웃은 DB 에서도 제거되며, 갱신된 모듈 정보를 반환합니다. 모듈의 `_bundled` 레이아웃 JSON 을 수정한 뒤 재빌드 없이 반영할 때 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/admin/modules/uninstall
|
||||
<!-- @generated:start:api.admin.modules.uninstall -->
|
||||
- **라우트명**: `api.admin.modules.uninstall`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@uninstall`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.uninstall`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| module_name | query | string | 예 | max 255 | module 이름 (식별자) |
|
||||
| delete_data | query | boolean | 아니오 | — | 제거 시 모듈이 생성한 DB 데이터까지 함께 삭제할지 여부 (기본 false — 데이터 보존) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.module.uninstall_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.uninstall`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 모듈을 시스템에서 제거합니다. `core.modules.uninstall` 권한이 필요합니다. 활성 디렉토리만 삭제하고 `_bundled` 원본은 보존합니다. `delete_data: true` 인 경우 모듈이 생성한 DB 데이터까지 함께 삭제하며, 기본값은 데이터 보존입니다. 삭제될 데이터 범위는 사전에 `uninstall-info` 로 확인할 수 있습니다.
|
||||
|
||||
|
||||
### GET /api/admin/modules/uninstalled
|
||||
<!-- @generated:start:api.admin.modules.uninstalled -->
|
||||
- **라우트명**: `api.admin.modules.uninstalled`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@uninstalled`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| identifier | string | `gnuboard7-hello_module` | 모듈 고유 식별자 (vendor-module 형식) |
|
||||
| vendor | string | `gnuboard7` | 벤더/개발자명 |
|
||||
| name | string | `Hello 모듈` | 모듈 이름 (다국어 JSON) |
|
||||
| version | string | `0.1.0` | 모듈 버전 |
|
||||
| description | string | `학습용 최소 샘플 모듈 (Memo CRUD)` | 모듈 설명 (다국어 JSON) |
|
||||
| dependencies | array | `[]` | 의존하는 확장 맵 (manifest 파생 — {modules, plugins}) |
|
||||
| status | string | `uninstalled` | 상태 (active: 활성화, inactive: 비활성화, installing: 설치 중, uninstalling: 제거 중, updating: 업데이트 중) |
|
||||
| assets | null | `null` | 프론트엔드 에셋 매니페스트 (manifest 파생 — js/css 진입점·로딩 전략) |
|
||||
| update_available | boolean | `false` | 최신 버전 대비 업데이트 가능 여부 |
|
||||
| update_source | null | `null` | 업데이트 감지 출처 (github, bundled 등) |
|
||||
| latest_version | null | `null` | 감지된 최신 배포 버전 |
|
||||
| file_version | null | `null` | 설치된 파일의 manifest 버전 |
|
||||
| github_url | null | `null` | GitHub 저장소 URL |
|
||||
| github_changelog_url | null | `null` | GitHub 변경 내역 URL |
|
||||
| is_pending | boolean | `false` | _pending 대기소에 있어 설치 대기 중인지 여부 |
|
||||
| is_bundled | boolean | `true` | 코어에 선탑재된 번들 확장인지 여부 |
|
||||
| deactivated_reason | null | `null` | 비활성화 사유: manual(사용자 수동) \| incompatible_core(코어 버전 호환성) \| null(active) |
|
||||
| deactivated_at | null | `null` | deactivated 일시 |
|
||||
| incompatible_required_version | null | `null` | 요구 코어 버전 미충족 시 필요한 버전 (호환되면 null) |
|
||||
| abilities | object | `{"can_install":true,"can_activate":true,"can_uninstall":t…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 아직 설치되지 않은 모듈만 조회합니다(예: 번들로 제공되나 미설치 상태인 샘플 모듈). `core.modules.read` 권한이 필요합니다. 설치 가능한 모듈을 사용자에게 노출하는 화면에서 사용하며, 미설치 항목은 assets·latest_version 등 설치 후에만 채워지는 필드가 null 로 반환됩니다.
|
||||
|
||||
|
||||
### GET /api/admin/modules/{identifier}/changelog
|
||||
<!-- @generated:start:api.admin.modules.changelog -->
|
||||
- **라우트명**: `api.admin.modules.changelog`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@changelog`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| source | query | string | 아니오 | `active`, `bundled`, `github` | 변경 내역 조회 출처 (active: 활성 설치본, bundled: 번들 원본, github: 원격 저장소) |
|
||||
| from_version | query | string | 아니오 | — | 시작 버전 (범위 하한) |
|
||||
| to_version | query | string | 아니오 | — | 대상 버전 (범위 상한) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.extension.changelog_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 모듈의 변경 내역(CHANGELOG)을 조회합니다. `core.modules.read` 권한이 필요합니다. `source` 로 조회 출처를(active: 활성 설치본, bundled: 번들 원본, github: 원격 저장소) 선택하고, `from_version`·`to_version` 으로 버전 구간을 좁힐 수 있습니다. 업데이트 전 사용자에게 변경 사항을 안내하는 데 사용됩니다.
|
||||
|
||||
|
||||
### GET /api/admin/modules/{identifier}/dependent-templates
|
||||
<!-- @generated:start:api.admin.modules.dependent-templates -->
|
||||
- **라우트명**: `api.admin.modules.dependent-templates`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@dependentTemplates`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 이 모듈에 의존하는 템플릿 목록을 조회합니다. `core.modules.read` 권한이 필요합니다. 응답으로 의존 템플릿 배열과 총 개수를 반환하며, 모듈 비활성화·제거 전 영향을 받는 템플릿을 사용자에게 미리 알리는 데 사용됩니다.
|
||||
|
||||
|
||||
### GET /api/admin/modules/{identifier}/license
|
||||
<!-- @generated:start:api.admin.modules.license -->
|
||||
- **라우트명**: `api.admin.modules.license`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@license`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 모듈에 포함된 라이선스 파일의 원문 내용을 반환합니다. `core.modules.read` 권한이 필요합니다. `identifier` 는 소문자·숫자·하이픈·언더스코어 형식만 허용되며 형식에 맞지 않거나 라이선스 파일이 없으면 404 를 반환합니다. 라이선스 고지 화면에 전문을 표시하는 용도입니다.
|
||||
|
||||
|
||||
### GET /api/admin/modules/{moduleName}
|
||||
<!-- @generated:start:api.admin.modules.show -->
|
||||
- **라우트명**: `api.admin.modules.show`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| moduleName | path | string | 예 | — | 대상 module의 이름 (식별자) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 모듈의 상세 정보를 조회합니다. `core.modules.read` 권한이 필요합니다. 목록보다 자세한 `toDetailArray()` 형태를 반환하며, 이 모듈이 지원하는 번들 언어팩 정보가 함께 주입됩니다. 모듈을 찾을 수 없으면 404 를 반환합니다.
|
||||
|
||||
|
||||
### GET /api/admin/modules/{moduleName}/check-modified-layouts
|
||||
<!-- @generated:start:api.admin.modules.check-modified-layouts -->
|
||||
- **라우트명**: `api.admin.modules.check-modified-layouts`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@checkModifiedLayouts`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| moduleName | path | string | 예 | — | 대상 module의 이름 (식별자) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 모듈에서 사용자가 수정한 레이아웃이 있는지 확인합니다. `core.modules.read` 권한이 필요합니다. 업데이트 실행 전 이 정보를 조회하여 레이아웃 전략(overwrite: 새 버전으로 교체, keep: 사용자 수정본 유지) 선택을 안내하는 데 사용됩니다.
|
||||
|
||||
|
||||
### GET /api/admin/modules/{moduleName}/install-preview
|
||||
<!-- @generated:start:api.admin.modules.install-preview -->
|
||||
- **라우트명**: `api.admin.modules.install-preview`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@installPreview`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| moduleName | path | string | 예 | — | 대상 module의 이름 (식별자) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.install`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 모듈 설치 시 함께 처리될 cascade 후보(의존 확장 + 동반 가능한 번들 언어팩) 트리를 반환합니다. `core.modules.install` 권한이 필요합니다. 설치 모달 오픈 시 호출되어 사용자가 함께 설치할 항목을 선택하도록 노출하며, ZIP 업로드 기반의 `manifest-preview` 와 달리 이미 알려진 식별자에 대한 GET 조회입니다.
|
||||
|
||||
|
||||
### GET /api/admin/modules/{moduleName}/uninstall-info
|
||||
<!-- @generated:start:api.admin.modules.uninstall-info -->
|
||||
- **라우트명**: `api.admin.modules.uninstall-info`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@uninstallInfo`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.uninstall`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| moduleName | path | string | 예 | — | 대상 module의 이름 (식별자) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.uninstall`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 모듈 제거 시 삭제될 데이터 정보를 조회합니다. `core.modules.uninstall` 권한이 필요합니다. 제거 확인 모달에서 사용자에게 어떤 데이터가 사라지는지 미리 보여주는 용도이며, 모듈을 찾을 수 없으면 404 를 반환합니다.
|
||||
|
||||
|
||||
### POST /api/admin/modules/{moduleName}/update
|
||||
<!-- @generated:start:api.admin.modules.update -->
|
||||
- **라우트명**: `api.admin.modules.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ModuleController@performUpdate`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.modules.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| moduleName | path | string | 예 | — | 대상 module의 이름 (식별자) |
|
||||
| layout_strategy | body | string | 아니오 | `overwrite`, `keep` | 업데이트 시 레이아웃 처리 전략 (overwrite: 새 버전으로 교체, keep: 사용자 수정본 유지) |
|
||||
| vendor_mode | body | string | 아니오 | `auto`, `composer`, `bundled` | 벤더 설치 모드 (auto/composer/bundled) |
|
||||
| force | body | boolean | 아니오 | — | 강제 실행 여부 (안전 확인/선행 검사 우회) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.module.perform_update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.modules.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 모듈을 최신 버전으로 업데이트합니다. `core.modules.install` 권한이 필요합니다. `layout_strategy` 로 레이아웃 처리 방식을(overwrite: 새 버전으로 교체, keep: 사용자 수정본 유지) 지정하며, `vendor_mode` 로 Composer 의존성 처리 방식을 선택합니다. 버전 제약·호환성 문제로 막힐 경우 `force: true` 로 강제 진행할 수 있습니다.
|
||||
|
||||
|
||||
### GET /api/modules/assets/{identifier}/{path}
|
||||
<!-- @generated:start:api.public.modules.assets -->
|
||||
- **라우트명**: `api.public.modules.assets`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicModuleController@serveAsset`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| path | path | string | 예 | — | 경로 |
|
||||
| identifier | query | string | 예 | — | 대상 확장/리소스의 식별자 |
|
||||
| path | query | string | 예 | — | 경로 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 모듈의 개별 프론트엔드 에셋 파일(JS/CSS/이미지 등)을 서빙하는 공개 엔드포인트입니다. 인증이 필요하지 않으며, 경로·확장자 보안 검증은 FormRequest 에서 완료됩니다. 모듈 미존재·파일 미존재·허용되지 않은 파일 유형은 각각 404/404/403 으로 응답하고, 정상 파일은 ETag 와 1년 캐시 헤더를 붙여 반환합니다. 소스맵 등 개별 에셋을 직접 참조할 때 사용되며, 통합 로딩은 `bundle.js`/`bundle.css` 를 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/bundle.css
|
||||
<!-- @generated:start:api.public.modules.bundle.css -->
|
||||
- **라우트명**: `api.public.modules.bundle.css`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicModuleController@serveBundleCss`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-200 — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). 활성 모듈 에셋이 없어도 빈 200 응답을 반환하므로 404 를 내지 않습니다._
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 활성 모듈들의 프론트엔드 CSS 를 서버에서 하나로 병합한 번들을 서빙하는 공개 엔드포인트입니다. 인증이 필요하지 않습니다. 활성 global 모듈 에셋이 없으면 빈 200(text/css) 응답을 반환하고, 있으면 병합 파일을 ETag·환경별 Cache-Control 과 함께 서빙합니다. 페이지가 모듈 스타일을 요청 1건으로 로드하도록 합니다.
|
||||
|
||||
|
||||
### GET /api/modules/bundle.js
|
||||
<!-- @generated:start:api.public.modules.bundle.js -->
|
||||
- **라우트명**: `api.public.modules.bundle.js`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicModuleController@serveBundleJs`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-200 — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). 활성 모듈 에셋이 없어도 빈 200 응답을 반환하므로 404 를 내지 않습니다._
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 활성 모듈들의 프론트엔드 IIFE JS 를 서버에서 하나로 병합한 번들을 서빙하는 공개 엔드포인트입니다. 인증이 필요하지 않습니다. 활성 global 모듈 에셋이 없으면 빈 200(text/javascript) 응답을 반환하고(프론트는 빈 스크립트 로드로 무해), 있으면 병합 파일을 ETag·환경별 Cache-Control 과 함께 서빙합니다. 프론트는 `G7Config.bundleUrls` 를 읽어 이 번들을 로드합니다.
|
||||
|
||||
|
||||
### GET /api/modules/{identifier}/components.json
|
||||
<!-- @generated:start:api.public.modules.components -->
|
||||
- **라우트명**: `api.public.modules.components`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicModuleController@serveComponents`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 모듈의 컴포넌트 정의 파일(components.json)을 서빙하는 공개 엔드포인트입니다. 인증이 필요하지 않습니다. 편집 모드 부팅 시 ComponentRegistry 가 활성 확장 매니페스트를 네임스페이스 병합하기 위해 fetch 하며, 구버전 모듈처럼 파일이 없으면 빈 components 로 폴백합니다. 응답은 1시간 캐시됩니다. 모듈 미존재 시 404.
|
||||
|
||||
|
||||
### GET /api/modules/{identifier}/editor-spec
|
||||
<!-- @generated:start:api.public.modules.editor_spec -->
|
||||
- **라우트명**: `api.public.modules.editor_spec`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicModuleController@serveEditorSpec`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 모듈의 레이아웃 편집기 스펙(editor-spec.json)을 서빙하는 공개 엔드포인트입니다. 인증이 필요하지 않습니다. 활성 모듈만 대상으로 하며 활성 디렉토리 → `_bundled` 폴백 순으로 읽어 `data.spec` 형태로 반환합니다. 비활성·미존재 모듈은 404 이고, 편집기 스펙 파일을 작성하지 않은 경우 spec=null 로 정상 응답합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# Notification Channels API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Notification Channels 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/notification-channels
|
||||
<!-- @generated:start:api.admin.notification-channels.index -->
|
||||
- **라우트명**: `api.admin.notification-channels.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationChannelController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| channels | array | `[{"id":"mail","name_key":"notification.channels.mail.name…` | 사용 가능한 알림 채널 메타데이터 목록. 각 원소는 `id`(채널 식별자: mail, database 등), `name`/`name_key`·`description`/`description_key`(활성 locale 기준 해석된 라벨/설명과 원본 다국어 키), `icon`(Font Awesome 클래스), `source`(제공 주체: core/module/plugin)·`source_label`(출처 표시 라벨), `allow_guest`(비회원 발송 허용 여부), `readiness`(컨트롤러가 `ChannelReadinessCheckerInterface`로 붙인 채널 설정 완료 여부 정보)로 구성됩니다. config 기본 채널(mail, database)에 `core.notification.filter_available_channels` 훅으로 추가된 확장 채널이 병합됩니다. |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 시스템에서 사용 가능한 알림 채널 목록을 반환하며, 각 채널에 설정 완료 여부(`readiness`) 정보를 붙여 제공합니다. 인증(`auth:sanctum`)과 `core.settings.read` 권한이 필요합니다. 플러그인이 Filter 훅으로 채널을 확장할 수 있으므로 목록은 설치된 확장에 따라 달라집니다. 알림 정의·템플릿 편집 화면에서 채널 선택 옵션을 채우고 미설정 채널을 안내할 때 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
# Notification Definitions API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Notification Definitions 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/notification-definitions
|
||||
<!-- @generated:start:api.admin.notification-definitions.index -->
|
||||
- **라우트명**: `api.admin.notification-definitions.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationDefinitionController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| search | query | string | 아니오 | max 255 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
|
||||
| extension_type | query | string | 아니오 | `core`, `module`, `plugin` | 확장 유형 (core/module/plugin/template) |
|
||||
| extension_identifier | query | string | 아니오 | max 100 | 확장 식별자 |
|
||||
| channel | query | string | 아니오 | max 50 | 채널 필터 — 활성 채널(`channels`) 배열에 이 채널을 포함하는 정의만 조회 (mail, database 등) |
|
||||
| is_active | query | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| sort_by | query | string | 아니오 | `id`, `type`, `extension_type`, `is_active`, `created_at`, `updated_at` | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.notification_definition.filter_index_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `1` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| type | string | `welcome` | 알림 타입 (welcome, order_confirmed 등) |
|
||||
| hook_prefix | string | `core.auth` | 훅 접두사 (core.auth, sirsoft-ecommerce 등) |
|
||||
| extension_type | string | `core` | 확장 타입: core, module, plugin |
|
||||
| extension_identifier | string | `core` | 확장 식별자: core, sirsoft-board 등 |
|
||||
| name | object | `{"ko":"회원가입 환영","en":"Welcome","ja":"会員登録 ウェルカム"}` | 다국어 이름 ({"ko": "회원가입 환영", "en": "Welcome"}) |
|
||||
| description | object | `{"ko":"회원가입 완료 시 발송되는 환영 알림","en":"Welcome notification s…` | 다국어 설명 |
|
||||
| variables | array | `[{"key":"name","description":"수신자 이름"},{"key":"app_name",…` | 사용 가능 변수 메타데이터 ([{key, description}]) |
|
||||
| channels | array | `["mail","database"]` | 활성 채널 (["mail", "database"]) |
|
||||
| hooks | array | `["core.auth.after_register"]` | 트리거 훅 목록 (["core.auth.after_register"]) |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| is_default | boolean | `true` | default 여부 |
|
||||
| templates | array | `[{"id":1,"definition_id":1,"channel":"mail","subject":{"k…` | 채널별 알림 템플릿 목록 (templates 관계 로드 시 NotificationTemplateResource 배열, 미로드 시 null) |
|
||||
| created_at | string | `2026-05-27 15:20:18` | 생성 일시 |
|
||||
| updated_at | string | `2026-06-30 13:33:16` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 등록된 알림 정의 목록을 페이지네이션으로 조회합니다. 인증(`auth:sanctum`)과 `core.settings.read` 권한이 필요합니다. `search`, `extension_type`, `extension_identifier`, `channel`, `is_active` 로 필터링하고 `sort_by`/`sort_order` 로 정렬하며, 확장이 `core.notification_definition.filter_index_rules` 훅으로 필터를 추가할 수 있습니다. 관리자 알림 정의 관리 목록 화면을 렌더링할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/admin/notification-definitions/{definition}
|
||||
<!-- @generated:start:api.admin.notification-definitions.show -->
|
||||
- **라우트명**: `api.admin.notification-definitions.show`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationDefinitionController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| definition | path | string | 예 | — | 대상 definition의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `21` | 기본 키 (내부 식별자) |
|
||||
| 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 | `` | 확장 식별자: core, sirsoft-board 등 |
|
||||
| name | object | `{"ko":"API 문서 샘플 알림","en":"API Doc Sample Notification"}` | 다국어 이름 ({"ko": "회원가입 환영", "en": "Welcome"}) |
|
||||
| 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 여부 |
|
||||
| templates | array | `[{"id":41,"definition_id":21,"channel":"mail","subject":"…` | 채널별 알림 템플릿 목록 (templates 관계 로드 시 NotificationTemplateResource 배열, 미로드 시 null) |
|
||||
| created_at | string | `2026-07-06 19:15:16` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-06 19:15:16` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 단일 알림 정의의 상세 정보를 조회하며, 응답에 소속 템플릿(`templates`)을 함께 로드합니다. 인증(`auth:sanctum`)과 `core.settings.read` 권한이 필요합니다. `definition` 경로 파라미터로 대상을 지정하며, 정의 편집 화면 진입 시 채널별 템플릿을 포함한 전체 구성을 불러올 때 사용합니다.
|
||||
|
||||
|
||||
### PUT /api/admin/notification-definitions/{definition}
|
||||
<!-- @generated:start:api.admin.notification-definitions.update -->
|
||||
- **라우트명**: `api.admin.notification-definitions.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationDefinitionController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| definition | path | string | 예 | — | 대상 definition의 식별자 |
|
||||
| channels | body | array | 아니오 | min 1 | 활성 채널 목록 — 이 정의가 발송에 사용할 채널 배열 (각 원소 최대 50자, mail·database 등). 지정 시 최소 1개 필요 |
|
||||
| hooks | body | array | 아니오 | — | 트리거 훅 목록 — 이 알림을 발송시키는 훅 이름 배열 (각 원소 최대 255자, core.auth.after_register 등) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.notification_definition.filter_update_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 알림 정의의 활성 채널(`channels`), 트리거 훅(`hooks`), 활성 상태(`is_active`)를 수정합니다. 인증(`auth:sanctum`)과 `core.settings.update` 권한이 필요합니다. Service 계층에서 수정 후 템플릿을 다시 로드해 반환하며, 확장이 `core.notification_definition.filter_update_rules` 훅으로 추가 파라미터를 검증에 넣을 수 있습니다. 발송 채널 구성이나 훅 연결을 변경할 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/notification-definitions/{definition}/reset
|
||||
<!-- @generated:start:api.admin.notification-definitions.reset -->
|
||||
- **라우트명**: `api.admin.notification-definitions.reset`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationDefinitionController@reset`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| definition | path | string | 예 | — | 대상 definition의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 알림 정의에 속한 모든 채널 템플릿을 기본값(default) 데이터로 일괄 복원하고, 정의 자체를 default 상태로 표시합니다. 인증(`auth:sanctum`)과 `core.settings.update` 권한이 필요합니다. 각 템플릿의 제목·본문을 기본값으로 덮어쓰는 파괴적 작업이므로 사용자 편집분이 사라집니다. 관리자가 커스터마이징한 알림 문구를 초기 상태로 되돌릴 때 사용합니다.
|
||||
|
||||
|
||||
### PATCH /api/admin/notification-definitions/{definition}/toggle-active
|
||||
<!-- @generated:start:api.admin.notification-definitions.toggle-active -->
|
||||
- **라우트명**: `api.admin.notification-definitions.toggle-active`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationDefinitionController@toggleActive`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| definition | path | string | 예 | — | 대상 definition의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 알림 정의의 활성 상태(`is_active`)를 현재 값의 반대로 토글합니다. 인증(`auth:sanctum`)과 `core.settings.update` 권한이 필요합니다. 비활성 정의는 해당 알림 발송이 중단되므로, 관리자가 목록에서 특정 알림을 켜거나 끄는 스위치 조작에 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
# Notification Logs API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Notification Logs 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/notification-logs
|
||||
<!-- @generated:start:api.admin.notification-logs.index -->
|
||||
- **라우트명**: `api.admin.notification-logs.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationLogController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.notification-logs.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| sender_user_id | query | integer | 아니오 | — | sender user 식별자 |
|
||||
| recipient_user_id | query | integer | 아니오 | — | recipient user 식별자 |
|
||||
| search | query | string | 아니오 | max 255 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
|
||||
| channel | query | string | 아니오 | max 50 | 발송 채널 필터 (해당 채널로 발송된 이력만 조회 — mail, database, fcm 등) |
|
||||
| notification_type | query | string | 아니오 | max 100 | 알림 타입 필터 (해당 타입의 이력만 조회 — welcome, order_confirmed 등) |
|
||||
| extension_type | query | string | 아니오 | `core`, `module`, `plugin` | 확장 유형 (core/module/plugin/template) |
|
||||
| status | query | string | 아니오 | — | 상태 필터 (해당 상태의 항목만 조회) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| sort_by | query | string | 아니오 | `id`, `channel`, `notification_type`, `status`, `sent_at`, `created_at` | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.notification_log.filter_index_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `677` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | integer | `677` | 기본 키 (내부 식별자) |
|
||||
| channel | string | `mail` | 채널: mail, database, fcm 등 |
|
||||
| notification_type | string | `apidoc.sample.event` | 알림 타입: welcome, order_confirmed 등 |
|
||||
| extension_type | string | `core` | 확장 타입: core, module, plugin |
|
||||
| extension_identifier | string | `` | 확장 식별자 |
|
||||
| recipient_user_id | integer | `166` | recipient user 식별자 (연관 리소스 참조) |
|
||||
| recipient_identifier | string | `apidoc-sample-user@example.com` | 수신자 식별자 (채널별: 이메일, 디바이스토큰, user_id 등) |
|
||||
| recipient_name | string | `API 문서 샘플 사용자` | 수신자 표시명 (발송 시점 스냅샷) |
|
||||
| sender_user_id | integer | `166` | sender user 식별자 (연관 리소스 참조) |
|
||||
| sender | object | `{"uuid":"a231747f-e82e-4cf2-9ae1-a261849dce40","name":"AP…` | 발신자 사용자 객체 (uuid/name/email — senderUser 관계 파생) |
|
||||
| recipient | object | `{"uuid":"a231747f-e82e-4cf2-9ae1-a261849dce40","name":"AP…` | 수신자 사용자 객체 (uuid/name/email — recipientUser 관계 파생) |
|
||||
| subject | string | `API 문서 샘플 알림` | 렌더링된 제목 |
|
||||
| body | string | `문서 실측용 알림 본문입니다.` | 렌더링된 본문 |
|
||||
| status | string | `sent` | 상태: sent, failed, skipped |
|
||||
| error_message | string | `해당 채널은 비회원 발송을 허용하지 않아 발송을 건너뛰었습니다.` | 에러 메시지 |
|
||||
| source | string | `apidoc` | 발송 출처: notification, test_mail 등 |
|
||||
| sent_at | string | `2026-07-06 18:20:23` | sent 일시 |
|
||||
| created_at | string | `2026-07-06 19:20:23` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-06 19:20:23` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.notification-logs.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 알림 발송 이력을 페이지네이션으로 조회합니다. 인증(`auth:sanctum`)과 `core.notification-logs.read` 권한이 필요합니다. 발송자/수신자 ID, `search`, `channel`, `notification_type`, `extension_type`, `status` 로 필터링하고 `sort_by`/`sort_order` 로 정렬하며, 확장이 `core.notification_log.filter_index_rules` 훅으로 필터를 추가할 수 있습니다. 요청 사용자(`request->user()`)를 Service 에 전달해 열람 범위를 결정하며, 관리자 알림 발송 이력 화면을 렌더링할 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/notification-logs/bulk-delete
|
||||
<!-- @generated:start:api.admin.notification-logs.bulk-destroy -->
|
||||
- **라우트명**: `api.admin.notification-logs.bulk-destroy`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationLogController@bulkDestroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.notification-logs.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.notification-logs.delete`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 알림 발송 이력을 ID 배열(`ids`)로 다건 삭제하고 삭제 건수(`deleted_count`)를 반환합니다. 인증(`auth:sanctum`)과 `core.notification-logs.delete` 권한이 필요합니다. 복구 불가능한 삭제이므로 주의가 필요하며, 관리자가 목록에서 여러 이력을 선택해 일괄 정리할 때 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/admin/notification-logs/{notificationLog}
|
||||
<!-- @generated:start:api.admin.notification-logs.destroy -->
|
||||
- **라우트명**: `api.admin.notification-logs.destroy`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationLogController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.notification-logs.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| notificationLog | path | string | 예 | — | 대상 notification log의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.notification-logs.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 단일 알림 발송 이력을 삭제합니다. 인증(`auth:sanctum`)과 `core.notification-logs.delete` 권한이 필요합니다. `notificationLog` 경로 파라미터로 대상을 지정하며, 복구 불가능한 삭제입니다. 관리자가 개별 발송 이력 한 건을 제거할 때 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
# Notification Templates API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Notification Templates 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### POST /api/admin/notification-templates/preview
|
||||
<!-- @generated:start:api.admin.notification-templates.preview -->
|
||||
- **라우트명**: `api.admin.notification-templates.preview`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationTemplateController@preview`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| definition_id | body | integer | 예 | — | definition 식별자 |
|
||||
| subject | body | array | 예 | — | 제목 |
|
||||
| body | body | array | 예 | — | 본문 |
|
||||
| locale | body | string | 아니오 | max 10 | 로케일 코드 (표시 언어/지역) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 저장 전 알림 템플릿의 렌더링 결과를 미리 확인합니다. `definition_id` 와 다국어 `subject`/`body`, 선택적 `locale` 을 받아 샘플 변수로 치환된 제목·본문을 반환합니다. 인증(`auth:sanctum`)과 `core.settings.read` 권한이 필요하며, 실제 발송이나 저장은 일어나지 않습니다. 템플릿 편집 화면에서 변수 치환 결과를 실시간으로 확인할 때 사용합니다.
|
||||
|
||||
|
||||
### PUT /api/admin/notification-templates/{template}
|
||||
<!-- @generated:start:api.admin.notification-templates.update -->
|
||||
- **라우트명**: `api.admin.notification-templates.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationTemplateController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| template | path | string | 예 | — | 대상 template의 식별자 |
|
||||
| subject | body | array | 예 | — | 제목 |
|
||||
| body | body | array | 예 | — | 본문 |
|
||||
| click_url | body | string | 아니오 | max 500 | 알림 클릭 시 이동할 대상 URL (미설정 시 이동 없음) |
|
||||
| recipients | body | array | 아니오 | — | 수신자 규칙 목록. 각 원소는 type(trigger_user: 이벤트 유발 사용자, related_user: 연관 사용자, role: 역할 대상, specific_users: 지정 사용자), value(대상 식별값), relation(연관 사용자 관계명), exclude_trigger_user(유발 사용자 제외 여부)로 구성 |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.notification_template.filter_update_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 단일 채널 알림 템플릿의 다국어 제목(`subject`)·본문(`body`)과 클릭 URL, 수신자(`recipients`), 활성 상태를 수정합니다. 인증(`auth:sanctum`)과 `core.settings.update` 권한이 필요합니다. `template` 경로 파라미터로 대상을 지정하며, 확장이 `core.notification_template.filter_update_rules` 훅으로 추가 파라미터를 검증에 넣을 수 있습니다. 관리자가 특정 채널의 알림 문구를 편집해 저장할 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/notification-templates/{template}/reset
|
||||
<!-- @generated:start:api.admin.notification-templates.reset -->
|
||||
- **라우트명**: `api.admin.notification-templates.reset`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationTemplateController@reset`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| template | path | string | 예 | — | 대상 template의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 단일 채널 템플릿을 소속 정의의 기본값 데이터로 복원합니다. 인증(`auth:sanctum`)과 `core.settings.update` 권한이 필요합니다. 소속 정의가 없으면 404, 해당 채널의 기본 데이터가 없으면 404 를 반환합니다. 편집한 문구를 버리고 기본값 하나만 되돌릴 때 사용하며, 정의 전체를 복원하는 정의 reset 과 달리 대상 템플릿에만 적용됩니다.
|
||||
|
||||
|
||||
### PATCH /api/admin/notification-templates/{template}/toggle-active
|
||||
<!-- @generated:start:api.admin.notification-templates.toggle-active -->
|
||||
- **라우트명**: `api.admin.notification-templates.toggle-active`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationTemplateController@toggleActive`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| template | path | string | 예 | — | 대상 template의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 단일 채널 알림 템플릿의 활성 상태(`is_active`)를 현재 값의 반대로 토글합니다. 인증(`auth:sanctum`)과 `core.settings.update` 권한이 필요합니다. 비활성 템플릿은 해당 채널로의 발송이 중단되므로, 정의는 유지한 채 특정 채널만 켜거나 끌 때 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,454 @@
|
||||
# Notifications API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Notifications 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/notifications
|
||||
<!-- @generated:start:api.admin.notifications.index -->
|
||||
- **라우트명**: `api.admin.notifications.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.notifications.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| read | query | string | 아니오 | `unread`, `read`, `all` | 읽음 상태 필터 (unread: 미읽음(`read_at` null)만, read: 읽음(`read_at` not null)만, all: 전체). 미지정 시 전체 |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.notification.filter_index_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.notifications.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
인증된 관리자 본인의 사이트내 알림 목록을 최신순(`created_at desc`)으로 페이지네이션해 반환합니다. `read` 파라미터로 미읽음(`unread`)·읽음(`read`)·전체(`all`, 기본)를 필터링하고, `per_page` 미지정 시 15건 단위로 반환합니다. 조회 대상은 항상 요청 사용자 본인의 알림으로 한정되며, 다른 사용자의 알림은 조회되지 않습니다. `_admin_base.json` 헤더의 알림 벨이 이 엔드포인트를 auto_fetch 로 소비하며 WebSocket 알림 수신 시 갱신됩니다. 항목 필드는 `id`, `type`, `type_label`, `subject`, `body`, `url`, `read_at`, `created_at` 로 구성됩니다.
|
||||
|
||||
|
||||
### DELETE /api/admin/notifications/all
|
||||
<!-- @generated:start:api.admin.notifications.destroy-all -->
|
||||
- **라우트명**: `api.admin.notifications.destroy-all`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationController@destroyAll`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.notifications.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.notifications.delete`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
인증된 관리자 본인의 모든 사이트내 알림(읽음·미읽음 무관)을 삭제합니다. 삭제 대상은 요청 사용자 본인의 알림으로만 한정되며, 응답 `data.deleted_count` 에 삭제된 건수를 반환합니다. 되돌릴 수 없는 작업이므로 UI 에서 확인 절차를 거친 뒤 호출합니다.
|
||||
|
||||
|
||||
### POST /api/admin/notifications/read-all
|
||||
<!-- @generated:start:api.admin.notifications.read-all -->
|
||||
- **라우트명**: `api.admin.notifications.read-all`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationController@markAllAsRead`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.notifications.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.notifications.update`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
인증된 관리자 본인의 미읽음 알림을 모두 읽음 처리합니다. 처리 대상 `read_at` 을 현재 시각으로 갱신하며, 응답 `data.marked_count` 에 읽음 처리된 건수를 반환합니다. 이미 읽음 상태인 알림은 대상에서 제외됩니다.
|
||||
|
||||
|
||||
### POST /api/admin/notifications/read-batch
|
||||
<!-- @generated:start:api.admin.notifications.read-batch -->
|
||||
- **라우트명**: `api.admin.notifications.read-batch`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationController@markBatchAsRead`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.notifications.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1, max 100 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.notification.filter_batch_read_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.notifications.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
`ids` 배열로 지정한 알림들을 일괄 읽음 처리합니다. 처리 대상은 요청 사용자 본인의 미읽음 알림 중 지정된 ID 에 해당하는 것으로 한정되며, 이미 읽음 상태이거나 본인 소유가 아닌 ID 는 무시됩니다. 응답 `data.marked_count` 에 실제 읽음 처리된 건수를 반환합니다. `ids` 는 최소 1개, 최대 100개까지 전달할 수 있습니다.
|
||||
|
||||
|
||||
### GET /api/admin/notifications/unread-count
|
||||
<!-- @generated:start:api.admin.notifications.unread-count -->
|
||||
- **라우트명**: `api.admin.notifications.unread-count`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationController@unreadCount`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.notifications.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| unread_count | integer | `0` | unread 개수 (집계) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.notifications.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
인증된 관리자 본인의 미읽음 알림 개수를 집계해 `data.unread_count` 로 반환합니다. `_admin_base.json` 헤더 알림 벨의 미읽음 배지에 사용되며, WebSocket 으로 새 알림이 수신되면 이 값을 재조회해 갱신합니다.
|
||||
|
||||
|
||||
### DELETE /api/admin/notifications/{notification}
|
||||
<!-- @generated:start:api.admin.notifications.destroy -->
|
||||
- **라우트명**: `api.admin.notifications.destroy`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.notifications.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| notification | path | string | 예 | — | 대상 notification의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.notifications.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
경로의 `{notification}` ID 에 해당하는 알림 1건을 삭제합니다. 대상은 요청 사용자 본인의 알림으로 한정되며, 해당 ID 가 본인 소유로 존재하지 않으면 404(`notification.user.not_found`)를 반환합니다.
|
||||
|
||||
|
||||
### PATCH /api/admin/notifications/{notification}/read
|
||||
<!-- @generated:start:api.admin.notifications.read -->
|
||||
- **라우트명**: `api.admin.notifications.read`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\NotificationController@markAsRead`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.notifications.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| notification | path | string | 예 | — | 대상 notification의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.notifications.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
경로의 `{notification}` ID 에 해당하는 알림 1건을 읽음 처리하고, 갱신된 알림 리소스를 `data` 로 반환합니다. 대상은 요청 사용자(관리자) 본인의 알림으로 한정되며, 본인 소유로 존재하지 않으면 404(`notification.user.not_found`)를 반환합니다. 반환 리소스에는 `id`, `type`, `type_label`, `subject`, `body`, `url`, `read_at`, `created_at` 가 포함됩니다.
|
||||
|
||||
|
||||
### GET /api/user/notifications
|
||||
<!-- @generated:start:api.user.notifications.index -->
|
||||
- **라우트명**: `api.user.notifications.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\NotificationController@index`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.user-notifications.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| read | query | string | 아니오 | `unread`, `read`, `all` | 읽음 상태 필터 (unread: 미읽음(`read_at` null)만, read: 읽음(`read_at` not null)만, all: 전체). 미지정 시 전체 |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.notification.filter_index_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.user-notifications.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
인증된 사용자 본인의 사이트내 알림 목록을 최신순(`created_at desc`)으로 페이지네이션해 반환합니다. `read` 파라미터로 미읽음(`unread`)·읽음(`read`)·전체(`all`, 기본)를 필터링하고, `per_page` 미지정 시 20건 단위로 반환합니다. 조회 대상은 항상 요청 사용자 본인의 알림으로 한정됩니다. `_user_base.json` 이 이 엔드포인트를 소비하며 WebSocket 알림 수신 시 갱신됩니다. 관리자 스코프(`/api/admin/notifications`)와 동일한 서비스·리소스를 사용하되 권한(`core.user-notifications.*`)과 기본 페이지 크기(20건)가 다릅니다.
|
||||
|
||||
|
||||
### DELETE /api/user/notifications/all
|
||||
<!-- @generated:start:api.user.notifications.destroy-all -->
|
||||
- **라우트명**: `api.user.notifications.destroy-all`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\NotificationController@destroyAll`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.user-notifications.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.user-notifications.delete`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
인증된 사용자 본인의 모든 사이트내 알림(읽음·미읽음 무관)을 삭제합니다. 삭제 대상은 요청 사용자 본인의 알림으로만 한정되며, 응답 `data.deleted_count` 에 삭제된 건수를 반환합니다. 되돌릴 수 없는 작업입니다.
|
||||
|
||||
|
||||
### POST /api/user/notifications/read-all
|
||||
<!-- @generated:start:api.user.notifications.read-all -->
|
||||
- **라우트명**: `api.user.notifications.read-all`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\NotificationController@markAllAsRead`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.user-notifications.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.user-notifications.update`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
인증된 사용자 본인의 미읽음 알림을 모두 읽음 처리합니다. 처리 대상 `read_at` 을 현재 시각으로 갱신하며, 응답 `data.marked_count` 에 읽음 처리된 건수를 반환합니다. 이미 읽음 상태인 알림은 대상에서 제외됩니다.
|
||||
|
||||
|
||||
### POST /api/user/notifications/read-batch
|
||||
<!-- @generated:start:api.user.notifications.read-batch -->
|
||||
- **라우트명**: `api.user.notifications.read-batch`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\NotificationController@markBatchAsRead`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.user-notifications.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1, max 100 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.notification.filter_batch_read_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.user-notifications.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
`ids` 배열로 지정한 알림들을 일괄 읽음 처리합니다. 처리 대상은 요청 사용자 본인의 미읽음 알림 중 지정된 ID 에 해당하는 것으로 한정되며, 이미 읽음 상태이거나 본인 소유가 아닌 ID 는 무시됩니다. 응답 `data.marked_count` 에 실제 읽음 처리된 건수를 반환합니다. `ids` 는 최소 1개, 최대 100개까지 전달할 수 있습니다.
|
||||
|
||||
|
||||
### GET /api/user/notifications/unread-count
|
||||
<!-- @generated:start:api.user.notifications.unread-count -->
|
||||
- **라우트명**: `api.user.notifications.unread-count`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\NotificationController@unreadCount`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.user-notifications.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| unread_count | integer | `0` | unread 개수 (집계) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.user-notifications.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
인증된 사용자 본인의 미읽음 알림 개수를 집계해 `data.unread_count` 로 반환합니다. `_user_base.json` 의 알림 미읽음 배지에 사용되며, WebSocket 으로 새 알림이 수신되면 이 값을 재조회해 갱신합니다.
|
||||
|
||||
|
||||
### DELETE /api/user/notifications/{notification}
|
||||
<!-- @generated:start:api.user.notifications.destroy -->
|
||||
- **라우트명**: `api.user.notifications.destroy`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\NotificationController@destroy`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.user-notifications.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| notification | path | string | 예 | — | 대상 notification의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.user-notifications.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
경로의 `{notification}` ID 에 해당하는 알림 1건을 삭제합니다. 대상은 요청 사용자 본인의 알림으로 한정되며, 해당 ID 가 본인 소유로 존재하지 않으면 404(`notification.user.not_found`)를 반환합니다.
|
||||
|
||||
|
||||
### PATCH /api/user/notifications/{notification}/read
|
||||
<!-- @generated:start:api.user.notifications.read -->
|
||||
- **라우트명**: `api.user.notifications.read`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\NotificationController@markAsRead`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.user-notifications.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| notification | path | string | 예 | — | 대상 notification의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.user-notifications.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
경로의 `{notification}` ID 에 해당하는 알림 1건을 읽음 처리하고, 갱신된 알림 리소스를 `data` 로 반환합니다. 대상은 요청 사용자 본인의 알림으로 한정되며, 본인 소유로 존재하지 않으면 404(`notification.user.not_found`)를 반환합니다. 반환 리소스에는 `id`, `type`, `type_label`, `subject`, `body`, `url`, `read_at`, `created_at` 가 포함됩니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# Password API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Password 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### PUT /api/me/password
|
||||
<!-- @generated:start:api.me.password -->
|
||||
- **라우트명**: `api.me.password`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\ProfileController@changePassword`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| current_password | body | string | 예 | — | 현재 비밀번호 (변경 전 확인용) |
|
||||
| password | body | string | 예 | — | 비밀번호 |
|
||||
| password_confirmation | body | string | 예 | — | 비밀번호 확인 (password 와 일치해야 함) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.user.change_password_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 로그인한 사용자가 자신의 비밀번호를 변경한다. 프론트의 비밀번호 변경 화면(`mypage/change-password.json`)이 사용한다. `current_password` 는 `current_password:sanctum` 규칙으로 검증되어 현재 비밀번호가 틀리면 실패하며, 새 비밀번호는 8자 이상이면서 `password_confirmation` 과 일치해야 한다. 해싱은 `UserService::updateUser()` 가 담당한다. 비밀번호 변경이 본인인증(IDV) 대상으로 설정된 경우 확장이 428 을 유발할 수 있으며, 이는 글로벌 예외 핸들러가 처리한다.
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Permissions API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Permissions 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/permissions
|
||||
<!-- @generated:start:api.admin.permissions.index -->
|
||||
- **라우트명**: `api.admin.permissions.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PermissionController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.permissions.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| admin | object | `{"label":"관리자 권한","icon":"cog","permissions":[{"id":1,"id…` | 관리자(admin) 타입 권한 그룹. `label`·`icon`(PermissionType::Admin 의 label()/icon() 산물)과 admin 타입으로 필터링된 권한 트리(`permissions`)를 담는다. |
|
||||
| user | object | `{"label":"사용자 권한","icon":"user","permissions":[{"id":1,"i…` | 사용자(user) 타입 권한 그룹. `label`·`icon`(PermissionType::User 의 label()/icon() 산물)과 user 타입으로 필터링된 권한 트리(`permissions`)를 담는다. |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.permissions.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
시스템의 전체 권한을 계층형 트리로 조회한다. 역할 생성·편집 화면(`admin_role_form.json`)의 권한 선택 트리를 채우는 데 사용된다. 권한은 모듈 → 카테고리 → 개별 권한 순으로 중첩되며(각 노드의 `children`), 코어 권한이 먼저 오도록 정렬된다. 응답의 `permissions` 는 권한 타입별(admin/user)로 그룹화되고, 각 그룹은 `label`·`icon` 메타와 필터링된 권한 트리를 담는다. 함께 반환되는 `types`(권한 타입 목록), `default_type`(기본 탭), `scope_options`(scope_type 선택지: 전체/역할/본인)는 편집 UI 구성에 쓰인다. 리프 노드만 실제 부여 가능한 권한(`is_assignable`)이다. `core.permissions.read` 권한이 필요하다.
|
||||
|
||||
|
||||
@@ -0,0 +1,885 @@
|
||||
# Plugins API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Plugins 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/plugins
|
||||
<!-- @generated:start:api.admin.plugins.index -->
|
||||
- **라우트명**: `api.admin.plugins.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| search | query | string | 아니오 | max 255 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
|
||||
| filters | query | array | 아니오 | max 10 | 추가 필터 조건 맵 (필드별 조건) |
|
||||
| status | query | string | 아니오 | `installed`, `uninstalled`, `active`, `inactive` | 상태 필터 (해당 상태의 항목만 조회) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
| include_hidden | query | boolean | 아니오 | — | 숨김 확장 포함 여부 (manifest `hidden=true` 로 목록에서 감춰진 플러그인까지 조회) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.plugin.index_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | null | `null` | 기본 키 (내부 식별자) |
|
||||
| identifier | string | `sirsoft-ckeditor5` | 플러그인 고유 식별자 (vendor-plugin 형식) |
|
||||
| vendor | string | `sirsoft` | 벤더/개발자명 |
|
||||
| name | string | `CKEditor 5 WYSIWYG 에디터` | 플러그인 이름 (다국어 JSON) |
|
||||
| version | string | `1.0.0` | 플러그인 버전 |
|
||||
| description | string | `CKEditor 5를 이용한 WYSIWYG 에디터 플러그인입니다. …` | 플러그인 설명 (다국어 JSON) |
|
||||
| dependencies | array | `[]` | 의존하는 확장 맵 (manifest 파생 — {modules, plugins}) |
|
||||
| permissions | array | `[]` | 연결된 권한 목록 (id/identifier/name — 역할 경유 권한 관계 파생) |
|
||||
| roles | array | `[]` | 플러그인이 정의한 역할 목록 (manifest 파생 — 설치 시 시드되는 역할) |
|
||||
| config | array | `[]` | 플러그인 설정 값 (manifest config 정의 기반 현재 설정 맵) |
|
||||
| hooks | array | `[]` | 훅 설정 정보 |
|
||||
| status | string | `active` | 상태 (active: 활성화, inactive: 비활성화, installing: 설치 중, uninstalling: 제거 중, updating: 업데이트 중) |
|
||||
| is_installed | boolean | `false` | installed 여부 |
|
||||
| has_settings | boolean | `true` | settings 여부 |
|
||||
| settings_route | string | `/admin/plugins/sirsoft-ckeditor5/sett…` | 설정 페이지 경로 (설정 UI 진입 라우트, 설정 미제공 시 null) |
|
||||
| assets | object | `{"js":"\/api\/plugins\/assets\/sirsoft-ckeditor5\/dist\/j…` | 프론트엔드 에셋 매니페스트 (manifest 파생 — js/css 진입점·로딩 전략) |
|
||||
| update_available | boolean | `false` | 최신 버전 대비 업데이트 가능 여부 |
|
||||
| update_source | null | `null` | 업데이트 감지 출처 (github, bundled 등) |
|
||||
| latest_version | string | `1.0.0` | 감지된 최신 배포 버전 |
|
||||
| file_version | string | `1.0.0` | 설치된 파일의 manifest 버전 |
|
||||
| github_url | string | `https://github.com/gnuboard/g7-plugin…` | GitHub 저장소 URL |
|
||||
| github_changelog_url | string | `https://github.com/gnuboard/g7-plugin…` | GitHub 변경 내역 URL |
|
||||
| is_pending | boolean | `false` | _pending 대기소에 있어 설치 대기 중인지 여부 |
|
||||
| is_bundled | boolean | `false` | 코어에 선탑재된 번들 확장인지 여부 |
|
||||
| deactivated_reason | null | `null` | 비활성화 사유: manual(사용자 수동) \| incompatible_core(코어 버전 호환성) \| null(active) |
|
||||
| deactivated_at | null | `null` | deactivated 일시 |
|
||||
| incompatible_required_version | null | `null` | 요구 코어 버전 미충족 시 필요한 버전 (호환되면 null) |
|
||||
| abilities | object | `{"can_install":true,"can_activate":true,"can_uninstall":t…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 설치된 플러그인과 미설치 플러그인을 모두 포함한 전체 플러그인 목록을 페이지네이션으로 조회합니다. `search` 는 이름·식별자·설명·벤더에 대한 OR 검색이고 `filters` 는 AND 조건으로 적용됩니다. `core.plugins.read` 권한이 필요하며, 응답의 `abilities` 는 현재 사용자의 install/activate/uninstall 권한 보유 여부를 담습니다. 관리자 플러그인 관리 화면의 목록 그리드를 구성하는 기본 엔드포인트입니다.
|
||||
|
||||
|
||||
### POST /api/admin/plugins/activate
|
||||
<!-- @generated:start:api.admin.plugins.activate -->
|
||||
- **라우트명**: `api.admin.plugins.activate`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@activate`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.activate`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| plugin_name | body | string | 예 | max 255 | plugin 이름 (식별자) |
|
||||
| force | body | boolean | 아니오 | — | 강제 실행 여부 (안전 확인/선행 검사 우회) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.plugin.activate_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.activate`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 설치된 플러그인을 활성화합니다. `core.plugins.activate` 권한이 필요합니다. `force` 없이 호출했을 때 필요한 의존 확장이 충족되지 않으면 409 응답으로 `missing_modules`·`missing_plugins` 목록과 함께 경고를 반환하므로, 사용자 확인 후 `force: true` 로 재요청해야 합니다. 재활성화 시 cascade 로 함께 비활성화됐던 번들 언어팩 목록이 `pending_language_packs` 로 응답에 포함됩니다.
|
||||
|
||||
|
||||
### POST /api/admin/plugins/check-updates
|
||||
<!-- @generated:start:api.admin.plugins.check-updates -->
|
||||
- **라우트명**: `api.admin.plugins.check-updates`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@checkUpdates`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.install`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 설치된 모든 플러그인에 대해 GitHub·번들 소스를 조회하여 새 버전 배포 여부를 일괄 확인합니다. `core.plugins.install` 권한이 필요합니다. 파라미터 없이 호출하며, 각 플러그인의 업데이트 가능 여부와 감지된 최신 버전 정보를 반환합니다. 플러그인 목록 화면 진입 시 업데이트 뱃지를 갱신하는 용도로 사용됩니다.
|
||||
|
||||
|
||||
### POST /api/admin/plugins/deactivate
|
||||
<!-- @generated:start:api.admin.plugins.deactivate -->
|
||||
- **라우트명**: `api.admin.plugins.deactivate`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@deactivate`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.activate`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| plugin_name | body | string | 예 | max 255 | plugin 이름 (식별자) |
|
||||
| force | body | boolean | 아니오 | — | 강제 실행 여부 (안전 확인/선행 검사 우회) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.plugin.deactivate_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.activate`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 활성 플러그인을 비활성화합니다. `core.plugins.activate` 권한이 필요합니다. `force` 없이 호출했을 때 이 플러그인에 의존하는 템플릿·모듈·플러그인이 있으면 409 응답으로 `dependent_templates`·`dependent_modules`·`dependent_plugins` 목록과 함께 경고를 반환합니다. 의존 관계 확인 후 `force: true` 로 강제 비활성화할 수 있습니다.
|
||||
|
||||
|
||||
### POST /api/admin/plugins/install
|
||||
<!-- @generated:start:api.admin.plugins.install -->
|
||||
- **라우트명**: `api.admin.plugins.install`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@install`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| plugin_name | body | string | 예 | max 255 | plugin 이름 (식별자) |
|
||||
| vendor_mode | body | string | 아니오 | `auto`, `composer`, `bundled` | 벤더 설치 모드 (auto/composer/bundled) |
|
||||
| dependencies | body | array | 아니오 | — | 함께 설치할 의존 확장 목록 (install-preview 응답 기반 사용자 선택 — 원소 type: module\|plugin, identifier) |
|
||||
| language_packs | body | array | 아니오 | — | 함께 설치할 번들 언어팩 식별자 목록 (best-effort cascade 2단계) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.plugin.install_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** `_pending`·`_bundled` 대기소에 있는 플러그인을 활성 디렉토리로 설치합니다. `core.plugins.install` 권한이 필요합니다. `vendor_mode` 로 Composer 의존성 설치 방식을(auto/composer/bundled) 지정하며, 요청 본문의 `dependencies` 로 선택한 의존 확장을 먼저 설치(cascade 1단계, 실패 시 전체 중단)한 뒤 `language_packs` 로 지정한 번들 언어팩을 best-effort 로 함께 설치합니다(cascade 2단계). 언어팩 설치 실패는 응답의 `language_pack_failures` 에 담겨 반환됩니다.
|
||||
|
||||
|
||||
### POST /api/admin/plugins/install-from-file
|
||||
<!-- @generated:start:api.admin.plugins.install-from-file -->
|
||||
- **라우트명**: `api.admin.plugins.install-from-file`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@installFromFile`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| file | body | file | 예 | max 51200 | 업로드 파일 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.plugin.install_from_file_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 업로드된 ZIP 파일에서 플러그인을 설치합니다. `core.plugins.install` 권한이 필요하며, 파일은 최대 50MB(51200KB)까지 허용됩니다. ZIP 압축 해제 후 plugin.json 검증을 거쳐 설치하며, 성공 시 201 상태로 설치된 플러그인 정보를 반환합니다. 설치 전 manifest 만 미리 확인하려면 `manifest-preview` 를 먼저 호출하는 것이 안전합니다.
|
||||
|
||||
|
||||
### POST /api/admin/plugins/install-from-github
|
||||
<!-- @generated:start:api.admin.plugins.install-from-github -->
|
||||
- **라우트명**: `api.admin.plugins.install-from-github`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@installFromGithub`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| github_url | body | string | 예 | — | GitHub 저장소 URL |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.plugin.install_from_github_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** GitHub 저장소 URL 에서 플러그인을 내려받아 설치합니다. `core.plugins.install` 권한이 필요합니다. `github_url` 로 지정한 공개 저장소의 릴리스/소스를 받아 압축 해제·검증 후 설치하며, 성공 시 201 상태로 설치된 플러그인 정보를 반환합니다.
|
||||
|
||||
|
||||
### GET /api/admin/plugins/installed
|
||||
<!-- @generated:start:api.admin.plugins.installed -->
|
||||
- **라우트명**: `api.admin.plugins.installed`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@installed`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | null | `null` | 기본 키 (내부 식별자) |
|
||||
| identifier | string | `sirsoft-ckeditor5` | 플러그인 고유 식별자 (vendor-plugin 형식) |
|
||||
| vendor | string | `sirsoft` | 벤더/개발자명 |
|
||||
| name | string | `CKEditor 5 WYSIWYG 에디터` | 플러그인 이름 (다국어 JSON) |
|
||||
| version | string | `1.0.0` | 플러그인 버전 |
|
||||
| description | string | `CKEditor 5를 이용한 WYSIWYG 에디터 플러그인입니다. …` | 플러그인 설명 (다국어 JSON) |
|
||||
| dependencies | array | `[]` | 의존하는 확장 맵 (manifest 파생 — {modules, plugins}) |
|
||||
| permissions | array | `[]` | 연결된 권한 목록 (id/identifier/name — 역할 경유 권한 관계 파생) |
|
||||
| roles | array | `[]` | 플러그인이 정의한 역할 목록 (manifest 파생 — 설치 시 시드되는 역할) |
|
||||
| config | array | `[]` | 플러그인 설정 값 (manifest config 정의 기반 현재 설정 맵) |
|
||||
| hooks | array | `[]` | 훅 설정 정보 |
|
||||
| status | string | `active` | 상태 (active: 활성화, inactive: 비활성화, installing: 설치 중, uninstalling: 제거 중, updating: 업데이트 중) |
|
||||
| is_installed | boolean | `false` | installed 여부 |
|
||||
| has_settings | boolean | `true` | settings 여부 |
|
||||
| settings_route | string | `/admin/plugins/sirsoft-ckeditor5/sett…` | 설정 페이지 경로 (설정 UI 진입 라우트, 설정 미제공 시 null) |
|
||||
| assets | object | `{"js":"\/api\/plugins\/assets\/sirsoft-ckeditor5\/dist\/j…` | 프론트엔드 에셋 매니페스트 (manifest 파생 — js/css 진입점·로딩 전략) |
|
||||
| update_available | boolean | `false` | 최신 버전 대비 업데이트 가능 여부 |
|
||||
| update_source | null | `null` | 업데이트 감지 출처 (github, bundled 등) |
|
||||
| latest_version | string | `1.0.0` | 감지된 최신 배포 버전 |
|
||||
| file_version | string | `1.0.0` | 설치된 파일의 manifest 버전 |
|
||||
| github_url | string | `https://github.com/gnuboard/g7-plugin…` | GitHub 저장소 URL |
|
||||
| github_changelog_url | string | `https://github.com/gnuboard/g7-plugin…` | GitHub 변경 내역 URL |
|
||||
| is_pending | boolean | `false` | _pending 대기소에 있어 설치 대기 중인지 여부 |
|
||||
| is_bundled | boolean | `false` | 코어에 선탑재된 번들 확장인지 여부 |
|
||||
| deactivated_reason | null | `null` | 비활성화 사유: manual(사용자 수동) \| incompatible_core(코어 버전 호환성) \| null(active) |
|
||||
| deactivated_at | null | `null` | deactivated 일시 |
|
||||
| incompatible_required_version | null | `null` | 요구 코어 버전 미충족 시 필요한 버전 (호환되면 null) |
|
||||
| abilities | object | `{"can_install":true,"can_activate":true,"can_uninstall":t…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 현재 설치된 플러그인만 조회합니다(미설치 항목 제외). 이 엔드포인트는 세부 권한 미들웨어 없이 `auth:sanctum` 인증만 요구하므로, 다른 화면이 활성/설치된 플러그인 목록을 참조할 때 사용하는 경량 조회 API 입니다. 페이지네이션 없이 설치된 항목 배열을 반환합니다.
|
||||
|
||||
|
||||
### POST /api/admin/plugins/manifest-preview
|
||||
<!-- @generated:start:api.admin.plugins.manifest-preview -->
|
||||
- **라우트명**: `api.admin.plugins.manifest-preview`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@manifestPreview`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| file | body | file | 예 | max 51200 | 업로드 파일 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 업로드된 ZIP 파일의 plugin.json manifest 와 검증 결과만 추출합니다(실제 설치는 수행하지 않음). `core.plugins.install` 권한이 필요하며 파일은 최대 50MB 까지 허용됩니다. 설치 모달에서 사용자가 파일 선택 직후 manifest 유효성과 검증 실패 사유를 미리 확인하는 용도입니다. 검증 오류 시 422 로 사유를 반환합니다.
|
||||
|
||||
|
||||
### POST /api/admin/plugins/refresh-layouts
|
||||
<!-- @generated:start:api.admin.plugins.refresh-layouts -->
|
||||
- **라우트명**: `api.admin.plugins.refresh-layouts`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@refreshLayouts`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.activate`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| plugin_name | body | string | 예 | max 255 | plugin 이름 (식별자) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.plugin.refresh_layouts_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.activate`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 플러그인의 레이아웃 파일을 다시 읽어 DB 에 동기화합니다. `core.plugins.activate` 권한이 필요합니다. 파일에서 변경된 레이아웃은 갱신되고 삭제된 레이아웃은 DB 에서도 제거되며, 응답으로 created/updated/deleted/unchanged 건수를 반환합니다. 플러그인의 `_bundled` 레이아웃 JSON 을 수정한 뒤 재빌드 없이 반영할 때 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/admin/plugins/uninstall
|
||||
<!-- @generated:start:api.admin.plugins.uninstall -->
|
||||
- **라우트명**: `api.admin.plugins.uninstall`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@uninstall`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.uninstall`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| plugin_name | query | string | 예 | max 255 | plugin 이름 (식별자) |
|
||||
| delete_data | query | boolean | 아니오 | — | 데이터 삭제 여부 (true 시 플러그인이 생성한 DB 데이터까지 함께 삭제, 미지정 시 데이터 보존) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.plugin.uninstall_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.uninstall`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 플러그인을 시스템에서 제거합니다. `core.plugins.uninstall` 권한이 필요합니다. 활성 디렉토리만 삭제하고 `_bundled` 원본은 보존합니다. `delete_data: true` 인 경우 플러그인이 생성한 DB 데이터까지 함께 삭제하며, 기본값은 데이터 보존입니다. 삭제될 데이터 범위는 사전에 `uninstall-info` 로 확인할 수 있습니다.
|
||||
|
||||
|
||||
### GET /api/admin/plugins/{identifier}/changelog
|
||||
<!-- @generated:start:api.admin.plugins.changelog -->
|
||||
- **라우트명**: `api.admin.plugins.changelog`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@changelog`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| source | query | string | 아니오 | `active`, `bundled`, `github` | 변경 내역 조회 출처 (active: 활성 설치본, bundled: 번들 원본, github: 원격 저장소) |
|
||||
| from_version | query | string | 아니오 | — | 시작 버전 (범위 하한) |
|
||||
| to_version | query | string | 아니오 | — | 대상 버전 (범위 상한) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.extension.changelog_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 플러그인의 변경 내역(CHANGELOG)을 조회합니다. `core.plugins.read` 권한이 필요합니다. `source` 로 조회 출처를(active: 활성 설치본, bundled: 번들 원본, github: 원격 저장소) 선택하고, `from_version`·`to_version` 으로 버전 구간을 좁힐 수 있습니다. 업데이트 전 사용자에게 변경 사항을 안내하는 데 사용됩니다.
|
||||
|
||||
|
||||
### GET /api/admin/plugins/{identifier}/dependent-templates
|
||||
<!-- @generated:start:api.admin.plugins.dependent-templates -->
|
||||
- **라우트명**: `api.admin.plugins.dependent-templates`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@dependentTemplates`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 이 플러그인에 의존하는 템플릿 목록을 조회합니다. `core.plugins.read` 권한이 필요합니다. 응답으로 의존 템플릿 배열과 총 개수를 반환하며, 플러그인 비활성화·제거 전 영향을 받는 템플릿을 사용자에게 미리 알리는 데 사용됩니다.
|
||||
|
||||
|
||||
### GET /api/admin/plugins/{identifier}/license
|
||||
<!-- @generated:start:api.admin.plugins.license -->
|
||||
- **라우트명**: `api.admin.plugins.license`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@license`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 플러그인에 포함된 라이선스 파일의 원문 내용을 반환합니다. `core.plugins.read` 권한이 필요합니다. `identifier` 는 소문자·숫자·하이픈·언더스코어 형식만 허용되며 형식에 맞지 않거나 라이선스 파일이 없으면 404 를 반환합니다. 라이선스 고지 화면에 전문을 표시하는 용도입니다.
|
||||
|
||||
|
||||
### GET /api/admin/plugins/{identifier}/settings
|
||||
<!-- @generated:start:api.admin.plugins.settings.show -->
|
||||
- **라우트명**: `api.admin.plugins.settings.show`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginSettingsController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 플러그인의 현재 설정 값을 조회합니다. `core.plugins.read` 권한이 필요합니다. 저장된 설정이 없거나 플러그인을 찾을 수 없으면 404 를 반환합니다. 설정 페이지 진입 시 폼의 현재 값을 채우는 용도이며, 폼 스키마/UI 구성은 별도의 `settings/layout` 엔드포인트에서 조회합니다.
|
||||
|
||||
|
||||
### PUT /api/admin/plugins/{identifier}/settings
|
||||
<!-- @generated:start:api.admin.plugins.settings.update -->
|
||||
- **라우트명**: `api.admin.plugins.settings.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginSettingsController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.plugin_settings.update_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 플러그인의 설정 값을 저장합니다. `core.plugins.update` 권한이 필요합니다. 검증된 값을 우선 사용하되, PluginManager 에 등록되지 않아 검증 규칙이 없는 플러그인의 경우 요청 본문 전체(`all()`)를 저장합니다. 저장 실패 시 500 을 반환하고, 성공 시 갱신된 설정 값을 함께 반환합니다.
|
||||
|
||||
|
||||
### GET /api/admin/plugins/{identifier}/settings/layout
|
||||
<!-- @generated:start:api.admin.plugins.settings.layout -->
|
||||
- **라우트명**: `api.admin.plugins.settings.layout`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginSettingsController@layout`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 플러그인 설정 페이지의 UI 구성과 설정 스키마(레이아웃)를 조회합니다. `core.plugins.read` 권한이 필요합니다. 레이아웃이 정의되지 않았거나 플러그인을 찾을 수 없으면 404 를 반환합니다. 설정 값 조회(`settings`)와 짝을 이루어 설정 화면을 렌더링하는 데 사용됩니다.
|
||||
|
||||
|
||||
### GET /api/admin/plugins/{pluginName}
|
||||
<!-- @generated:start:api.admin.plugins.show -->
|
||||
- **라우트명**: `api.admin.plugins.show`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| pluginName | path | string | 예 | — | 대상 plugin의 이름 (식별자) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 플러그인의 상세 정보를 조회합니다. `core.plugins.read` 권한이 필요합니다. 목록보다 자세한 `toDetailArray()` 형태를 반환하며, 이 플러그인이 지원하는 번들 언어팩 정보가 함께 주입됩니다. 플러그인을 찾을 수 없으면 404 를 반환합니다.
|
||||
|
||||
|
||||
### GET /api/admin/plugins/{pluginName}/check-modified-layouts
|
||||
<!-- @generated:start:api.admin.plugins.check-modified-layouts -->
|
||||
- **라우트명**: `api.admin.plugins.check-modified-layouts`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@checkModifiedLayouts`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| pluginName | path | string | 예 | — | 대상 plugin의 이름 (식별자) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 플러그인에서 사용자가 수정한 레이아웃이 있는지 확인합니다. `core.plugins.read` 권한이 필요합니다. 업데이트 실행 전 이 정보를 조회하여 레이아웃 전략(overwrite: 새 버전으로 교체, keep: 사용자 수정본 유지) 선택을 안내하는 데 사용됩니다.
|
||||
|
||||
|
||||
### GET /api/admin/plugins/{pluginName}/install-preview
|
||||
<!-- @generated:start:api.admin.plugins.install-preview -->
|
||||
- **라우트명**: `api.admin.plugins.install-preview`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@installPreview`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| pluginName | path | string | 예 | — | 대상 plugin의 이름 (식별자) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.install`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 플러그인 설치 시 함께 처리될 cascade 후보(의존 확장 + 동반 가능한 번들 언어팩) 트리를 반환합니다. `core.plugins.install` 권한이 필요합니다. 설치 모달 오픈 시 호출되어 사용자가 함께 설치할 항목을 선택하도록 노출하며, ZIP 업로드 기반의 `manifest-preview` 와 달리 이미 알려진 식별자에 대한 GET 조회입니다.
|
||||
|
||||
|
||||
### GET /api/admin/plugins/{pluginName}/uninstall-info
|
||||
<!-- @generated:start:api.admin.plugins.uninstall-info -->
|
||||
- **라우트명**: `api.admin.plugins.uninstall-info`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@uninstallInfo`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.uninstall`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| pluginName | path | string | 예 | — | 대상 plugin의 이름 (식별자) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.uninstall`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 플러그인 제거 시 삭제될 데이터 정보를 조회합니다. `core.plugins.uninstall` 권한이 필요합니다. 제거 확인 모달에서 사용자에게 어떤 데이터가 사라지는지 미리 보여주는 용도이며, 플러그인을 찾을 수 없으면 404 를 반환합니다.
|
||||
|
||||
|
||||
### POST /api/admin/plugins/{pluginName}/update
|
||||
<!-- @generated:start:api.admin.plugins.update -->
|
||||
- **라우트명**: `api.admin.plugins.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\PluginController@performUpdate`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.plugins.install`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| pluginName | path | string | 예 | — | 대상 plugin의 이름 (식별자) |
|
||||
| layout_strategy | body | string | 아니오 | `overwrite`, `keep` | 레이아웃 처리 전략 (overwrite: 새 버전으로 교체, keep: 사용자 수정본 유지) |
|
||||
| vendor_mode | body | string | 아니오 | `auto`, `composer`, `bundled` | 벤더 설치 모드 (auto/composer/bundled) |
|
||||
| force | body | boolean | 아니오 | — | 강제 실행 여부 (안전 확인/선행 검사 우회) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.plugin.perform_update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.plugins.install`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 플러그인을 최신 버전으로 업데이트합니다. `core.plugins.install` 권한이 필요합니다. `layout_strategy` 로 레이아웃 처리 방식을(overwrite: 새 버전으로 교체, keep: 사용자 수정본 유지) 지정하며, `vendor_mode` 로 Composer 의존성 처리 방식을 선택합니다. 버전 제약·호환성 문제로 막힐 경우 `force: true` 로 강제 진행할 수 있습니다.
|
||||
|
||||
|
||||
### GET /api/plugins/assets/{identifier}/{path}
|
||||
<!-- @generated:start:api.public.plugins.assets -->
|
||||
- **라우트명**: `api.public.plugins.assets`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicPluginController@serveAsset`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| path | path | string | 예 | — | 경로 |
|
||||
| identifier | query | string | 예 | — | 대상 확장/리소스의 식별자 |
|
||||
| path | query | string | 예 | — | 경로 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 플러그인의 개별 프론트엔드 에셋 파일(JS/CSS/이미지 등)을 서빙하는 공개 엔드포인트입니다. 인증이 필요하지 않으며, 경로·확장자 보안 검증은 FormRequest 에서 완료됩니다. 플러그인 미존재·파일 미존재·허용되지 않은 파일 유형은 각각 404/404/403 으로 응답하고, 정상 파일은 ETag 와 1년 캐시 헤더를 붙여 반환합니다. 소스맵 등 개별 에셋을 직접 참조할 때 사용되며, 통합 로딩은 `bundle.js`/`bundle.css` 를 사용합니다.
|
||||
|
||||
|
||||
### GET /api/plugins/bundle.css
|
||||
<!-- @generated:start:api.public.plugins.bundle.css -->
|
||||
- **라우트명**: `api.public.plugins.bundle.css`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicPluginController@serveBundleCss`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-200 — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회 — 활성 에셋이 없으면 빈 200 응답)._
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 활성 플러그인들의 프론트엔드 CSS 를 서버에서 하나로 병합한 번들을 서빙하는 공개 엔드포인트입니다. 인증이 필요하지 않습니다. 활성 global 플러그인 에셋이 없으면 빈 200(text/css) 응답을 반환하고, 있으면 병합 파일을 ETag·환경별 Cache-Control 과 함께 서빙합니다. 페이지가 플러그인 스타일을 요청 1건으로 로드하도록 합니다.
|
||||
|
||||
|
||||
### GET /api/plugins/bundle.js
|
||||
<!-- @generated:start:api.public.plugins.bundle.js -->
|
||||
- **라우트명**: `api.public.plugins.bundle.js`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicPluginController@serveBundleJs`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-200 — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회 — 활성 에셋이 없으면 빈 200 응답)._
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 활성 플러그인들의 프론트엔드 IIFE JS 를 서버에서 하나로 병합한 번들을 서빙하는 공개 엔드포인트입니다. 인증이 필요하지 않습니다. 활성 global 플러그인 에셋이 없으면 빈 200(text/javascript) 응답을 반환하고, 있으면 병합 파일을 ETag·환경별 Cache-Control 과 함께 서빙합니다. 프론트는 `G7Config.bundleUrls` 를 읽어 이 번들을 로드합니다.
|
||||
|
||||
|
||||
### GET /api/plugins/{identifier}/components.json
|
||||
<!-- @generated:start:api.public.plugins.components -->
|
||||
- **라우트명**: `api.public.plugins.components`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicPluginController@serveComponents`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 플러그인의 컴포넌트 정의 파일(components.json)을 서빙하는 공개 엔드포인트입니다. 인증이 필요하지 않습니다. 편집 모드 부팅 시 ComponentRegistry 가 활성 확장 매니페스트를 네임스페이스 병합하기 위해 fetch 하며, 구버전 플러그인처럼 파일이 없으면 빈 components 로 폴백합니다. 응답은 1시간 캐시됩니다. 플러그인 미존재 시 404.
|
||||
|
||||
|
||||
### GET /api/plugins/{identifier}/editor-spec
|
||||
<!-- @generated:start:api.public.plugins.editor_spec -->
|
||||
- **라우트명**: `api.public.plugins.editor_spec`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicPluginController@serveEditorSpec`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 플러그인의 레이아웃 편집기 스펙(editor-spec.json)을 서빙하는 공개 엔드포인트입니다. 인증이 필요하지 않습니다. 활성 플러그인만 대상으로 하며 활성 디렉토리 → `_bundled` 폴백 순으로 읽어 `data.spec` 형태로 반환합니다. 비활성·미존재 플러그인은 404 이고, 편집기 스펙 파일을 작성하지 않은 경우 spec=null 로 정상 응답합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
# Profile API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Profile 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/user/profile
|
||||
<!-- @generated:start:api.user.profile.show -->
|
||||
- **라우트명**: `api.user.profile.show`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\ProfileController@show`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.profile.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.profile.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
`GET /api/me` 와 동일하게 `ProfileController@show` 를 호출해 현재 사용자의 프로필을 조회하지만, `permission:core.profile.read` 권한 미들웨어가 추가된 경로다. 응답 형태는 `UserResource::toProfileArray()` 산물로 `GET /api/me` 와 같으며, 필드별 소유(확장 병합) 규칙도 동일하다. 실측 예시가 비어 있는 것은 문서 생성 시 샘플 사용자가 해당 권한을 갖지 못해 403 이 반환되었기 때문이며, 응답 필드는 `GET /api/me` 문서를 참조한다.
|
||||
|
||||
|
||||
### PUT /api/user/profile
|
||||
<!-- @generated:start:api.user.profile.update -->
|
||||
- **라우트명**: `api.user.profile.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\ProfileController@update`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.profile.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | string | 예 | max 255 | 대상의 이름/명칭 |
|
||||
| nickname | body | string | 아니오 | max 50 | 닉네임 |
|
||||
| email | body | email | 예 | max 255 | 이메일 주소 |
|
||||
| password | body | string | 아니오 | — | 비밀번호 |
|
||||
| current_password | body | string | 아니오 | — | 현재 비밀번호 (변경 전 확인용) |
|
||||
| language | body | string | 아니오 | — | 언어 코드 |
|
||||
| country | body | string | 아니오 | — | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| timezone | body | string | 아니오 | — | 타임존 식별자 |
|
||||
| homepage | body | string | 아니오 | max 255 | 홈페이지 URL |
|
||||
| mobile | body | string | 아니오 | max 20 | 휴대전화 번호 |
|
||||
| phone | body | string | 아니오 | max 20 | 전화번호 |
|
||||
| zipcode | body | string | 아니오 | max 10 | 우편번호 |
|
||||
| address | body | string | 아니오 | max 255 | 기본 주소 |
|
||||
| address_detail | body | string | 아니오 | max 255 | 상세 주소 |
|
||||
| signature | body | string | 아니오 | max 1000 | 서명 |
|
||||
| bio | body | string | 아니오 | max 5000 | 자기소개 |
|
||||
| notify_post_complete | body | boolean | 아니오 | — | 내 글에 답변/처리 완료 시 알림 수신 여부 (게시판 모듈 알림 설정) |
|
||||
| notify_post_reply | body | boolean | 아니오 | — | 내 글에 답글이 달렸을 때 알림 수신 여부 (게시판 모듈 알림 설정) |
|
||||
| notify_comment | body | boolean | 아니오 | — | 내 글에 댓글이 달렸을 때 알림 수신 여부 (게시판 모듈 알림 설정) |
|
||||
| notify_reply_comment | body | boolean | 아니오 | — | 내 댓글에 대댓글이 달렸을 때 알림 수신 여부 (게시판 모듈 알림 설정) |
|
||||
| email_subscription | body | boolean | 아니오 | — | 광고성 이메일 수신 동의 여부 (sirsoft-marketing 채널, 훅 주입 파라미터) |
|
||||
| marketing_consent | body | boolean | 아니오 | — | 마케팅 정보 수신 전체 동의 마스터 키 — 마케팅 채널 전체 동의/철회 제어 (sirsoft-marketing 훅 주입 파라미터) |
|
||||
| third_party_consent | body | boolean | 아니오 | — | 제3자 정보 제공 동의 여부 (법적 필수 항목, sirsoft-marketing 훅 주입 파라미터) |
|
||||
| info_disclosure | body | boolean | 아니오 | — | 개인정보 이용 안내 동의 여부 (법적 필수 항목, sirsoft-marketing 훅 주입 파라미터) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.user.update_profile_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.profile.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
`PUT /api/me` 와 동일하게 `ProfileController@update` 를 호출해 프로필을 수정하되, `permission:core.profile.update` 권한 미들웨어가 추가된 경로다. 요청 파라미터와 검증 규칙(`UpdateProfileRequest`), 확장 소유 파라미터 병합(`core.user.update_profile_validation_rules`)은 `PUT /api/me` 와 동일하다. 성공 시 갱신된 프로필이 `UserResource` 형태로 반환된다.
|
||||
|
||||
|
||||
### GET /api/user/profile/activity-log
|
||||
<!-- @generated:start:api.user.profile.activity-log -->
|
||||
- **라우트명**: `api.user.profile.activity-log`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\ProfileController@activityLog`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:core.profile.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`core.profile.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 사용자의 최근 활동 로그를 조회한다(`permission:core.profile.read` 필요). `data.activities` 에 최대 50건의 로그가 최신순으로 담기며, 각 항목은 `id`·`action`·`action_label`·`description`(로케일 반영)·`ip_address`·`created_at`(ISO 8601) 필드를 가진다. 실측 예시가 비어 있는 것은 문서 생성 시 샘플 사용자가 권한을 갖지 못해 403 이 반환되었기 때문이다.
|
||||
|
||||
|
||||
### POST /api/user/profile/update-language
|
||||
<!-- @generated:start:api.user.profile.update-language -->
|
||||
- **라우트명**: `api.user.profile.update-language`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\ProfileController@updateLanguage`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 400 | Bad Request | `language` 값이 `config('app.supported_locales')`(기본 `['ko','en']`)에 포함되지 않는 미지원 로케일인 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 사용자의 언어 설정만 변경한다. 요청 본문의 `language` 값을 받아 `config('app.supported_locales')`(기본 `['ko','en']`)에 포함되는지 검사하며, 허용되지 않는 값이면 400 을 반환한다. 프로필 전체 수정 없이 언어만 즉시 전환할 때 사용하며, 성공 시 갱신된 사용자 정보가 `UserResource` 형태로 반환된다. `language` 는 FormRequest 가 아닌 컨트롤러에서 직접 읽어 검증하므로 문서 상단 파라미터 표에는 자동 수집되지 않는다.
|
||||
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
# Roles API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Roles 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/roles
|
||||
<!-- @generated:start:api.admin.roles.index -->
|
||||
- **라우트명**: `api.admin.roles.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\RoleController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.permissions.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| search | query | string | 아니오 | max 255 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
|
||||
| is_active | query | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `23` | 기본 키 (내부 식별자) |
|
||||
| identifier | string | `sirsoft-board.archive.manager` | 역할명 (예: admin, user, manager) |
|
||||
| name | string | `아카이브 게시판 관리자` | 역할 이름 (다국어 JSON) |
|
||||
| name_raw | object | `{"ko":"아카이브 게시판 관리자","en":"Archive Board Manager"}` | `name` 의 원본 값 (현재 로케일 미해석 원본 JSON/문자열) |
|
||||
| description | string | `아카이브 게시판의 관리자 역할` | 역할 설명 (다국어 JSON) |
|
||||
| description_raw | object | `{"ko":"아카이브 게시판의 관리자 역할","en":"Manager role for Archive b…` | `description` 의 원본 값 (현재 로케일 미해석 원본 JSON/문자열) |
|
||||
| extension_type | string | `module` | 확장 소유 타입: core(코어), module(모듈), plugin(플러그인), NULL(사용자 정의) |
|
||||
| extension_identifier | string | `sirsoft-board` | 확장 식별자 (예: core, sirsoft-board, sirsoft-payment) |
|
||||
| extension_name | string | `게시판` | 이 리소스를 소유한 확장의 표시 이름 (manifest name) |
|
||||
| is_deletable | boolean | `false` | deletable 여부 |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| users_count | integer | `1` | users 개수 (집계) |
|
||||
| permission_ids | array | `[312,313,314,315,316,317,318,319,320,321,322,323,324,325,…` | permission 식별자 배열 (연관 리소스 참조) |
|
||||
| permission_values | array | `[{"id":312,"scope_type":null},{"id":313,"scope_type":null…` | 할당된 각 권한의 id와 적용 범위만 담은 경량 목록 (원소 id/scope_type — 역할-권한 pivot 파생). scope_type: null=전체, role=역할 범위, self=본인 범위 |
|
||||
| permissions | array | `[{"id":85,"parent_id":null,"identifier":"sirsoft-board","…` | 연결된 권한 목록 (id/identifier/name — 역할 경유 권한 관계 파생) |
|
||||
| created_at | string | `2026-06-04 09:35:35` | 생성 일시 |
|
||||
| updated_at | string | `2026-06-04 09:35:35` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true,"c…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.permissions.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
역할 관리 화면(`admin_role_list.json`)의 목록 데이터를 제공하는 페이지네이션 조회 엔드포인트다. `search`(identifier/name 텍스트 검색)와 `is_active`(활성 여부)로 필터링하며 `per_page` 로 페이지 크기를 조절한다. 응답에는 각 역할의 할당 권한(permission_ids/permission_values/permissions), 소유 확장 정보, 사용자 수, 현재 사용자의 조작 가능 여부(abilities)가 포함된다. `core.permissions.read` 권한이 필요하다.
|
||||
|
||||
|
||||
### POST /api/admin/roles
|
||||
<!-- @generated:start:api.admin.roles.store -->
|
||||
- **라우트명**: `api.admin.roles.store`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\RoleController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.permissions.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| identifier | body | string | 예 | max 100 | 대상 확장/리소스의 식별자 |
|
||||
| name | body | string | 예 | — | 대상의 이름/명칭 |
|
||||
| description | body | string | 아니오 | — | 설명 |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| permissions | body | array | 아니오 | — | 역할에 부여할 권한 목록. 각 원소는 `{id, scope_type}` (id=권한 식별자, scope_type=적용 범위: null 전체 / role 역할 범위 / self 본인 범위). 전달된 목록 기준으로 역할의 권한 집합이 재설정됨 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.role.store_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.permissions.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
새 역할을 생성한다. `identifier` 는 소문자로 시작하는 영숫자·언더스코어 형식(`^[a-z][a-z0-9_]*$`)이어야 하고 전역 고유해야 한다. `name`·`description` 은 다국어 필드로, 문자열로 보내면 설정된 로케일 전체에 동일 값이 채워지고 객체(`{"ko":..., "en":...}`)로도 보낼 수 있다. `permissions` 는 `[{id, scope_type}]` 형식으로 부여할 권한과 각 권한의 적용 범위(scope_type: null=전체, role, self)를 지정한다. 검증 규칙은 `core.role.store_validation_rules` 필터 훅으로 확장이 확장할 수 있다. `core.permissions.create` 권한이 필요하며 성공 시 201 로 생성된 역할을 반환한다.
|
||||
|
||||
|
||||
### GET /api/admin/roles/active
|
||||
<!-- @generated:start:api.admin.roles.active -->
|
||||
- **라우트명**: `api.admin.roles.active`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\RoleController@active`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| identifier | string | `admin` | 역할명 (예: admin, user, manager) |
|
||||
| name | string | `관리자` | 역할 이름 (다국어 JSON) |
|
||||
| name_raw | object | `{"ko":"관리자","en":"Administrator"}` | `name` 의 원본 값 (현재 로케일 미해석 원본 JSON/문자열) |
|
||||
| description | string | `시스템의 모든 기능에 접근할 수 있는 최고 관리자입니다.` | 역할 설명 (다국어 JSON) |
|
||||
| description_raw | object | `{"ko":"시스템의 모든 기능에 접근할 수 있는 최고 관리자입니다.","en":"Super admin…` | `description` 의 원본 값 (현재 로케일 미해석 원본 JSON/문자열) |
|
||||
| extension_type | string | `core` | 확장 소유 타입: core(코어), module(모듈), plugin(플러그인), NULL(사용자 정의) |
|
||||
| extension_identifier | string | `core` | 확장 식별자 (예: core, sirsoft-board, sirsoft-payment) |
|
||||
| extension_name | string | `이커머스` | 이 리소스를 소유한 확장의 표시 이름 (manifest name) |
|
||||
| is_deletable | boolean | `false` | deletable 여부 |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| created_at | string | `2026-05-27 15:20:18` | 생성 일시 |
|
||||
| updated_at | string | `2026-06-30 13:41:48` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true,"c…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
셀렉트 UI(사용자 폼·메뉴 편집의 역할 선택 등)에 채울 활성 역할 목록을 제공한다. 별도 권한 미들웨어가 없어 인증만 되면 호출 가능하지만, 내부에서 권한에 따라 범위가 갈린다. `core.permissions.read` 권한 보유자는 전체 활성 역할을 받고(사용자에게 역할을 부여하는 관리 용도), 미보유자는 자신에게 부여된 활성 역할만 받는다(자기 정보 폼 표시 용도). 응답의 `abilities.can_assign_roles` 는 `core.permissions.update` 권한 보유 여부를 나타낸다.
|
||||
|
||||
|
||||
### DELETE /api/admin/roles/{role}
|
||||
<!-- @generated:start:api.admin.roles.destroy -->
|
||||
- **라우트명**: `api.admin.roles.destroy`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\RoleController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.permissions.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| role | path | string | 예 | — | 대상 role의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.permissions.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
역할을 삭제한다. 코어 소유 역할(admin/user 등)은 403(`role.system_role_delete_error`)으로, 모듈·플러그인이 소유한 확장 역할은 403(`role.extension_owned_role_delete_error`)으로 거부된다. 삭제 가능한(사용자 정의) 역할만 제거되며, CASCADE 에 의존하지 않고 권한·메뉴·사용자 매핑을 명시적으로 해제한 뒤 역할을 삭제한다. `core.permissions.delete` 권한이 필요하다.
|
||||
|
||||
|
||||
### GET /api/admin/roles/{role}
|
||||
<!-- @generated:start:api.admin.roles.show -->
|
||||
- **라우트명**: `api.admin.roles.show`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\RoleController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.permissions.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| role | path | string | 예 | — | 대상 role의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `66` | 기본 키 (내부 식별자) |
|
||||
| identifier | string | `apidoc-sample-role` | 역할명 (예: admin, user, manager) |
|
||||
| name | string | `API 문서 샘플 역할` | 역할 이름 (다국어 JSON) |
|
||||
| name_raw | object | `{"ko":"API 문서 샘플 역할","en":"API Doc Sample Role"}` | `name` 의 원본 값 (현재 로케일 미해석 원본 JSON/문자열) |
|
||||
| description | string | `문서 실측용 역할` | 역할 설명 (다국어 JSON) |
|
||||
| description_raw | object | `{"ko":"문서 실측용 역할","en":"Sample role for API docs"}` | `description` 의 원본 값 (현재 로케일 미해석 원본 JSON/문자열) |
|
||||
| extension_type | null | `null` | 확장 소유 타입: core(코어), module(모듈), plugin(플러그인), NULL(사용자 정의) |
|
||||
| extension_identifier | null | `null` | 확장 식별자 (예: core, sirsoft-board, sirsoft-payment) |
|
||||
| extension_name | null | `null` | 이 리소스를 소유한 확장의 표시 이름 (manifest name) |
|
||||
| is_deletable | boolean | `true` | deletable 여부 |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| users_count | integer | `0` | users 개수 (집계) |
|
||||
| permission_ids | array | `[1,85,100]` | permission 식별자 배열 (연관 리소스 참조) |
|
||||
| permission_values | array | `[{"id":1,"scope_type":null},{"id":85,"scope_type":null},{…` | 할당된 각 권한의 id와 적용 범위만 담은 경량 목록 (원소 id/scope_type — 역할-권한 pivot 파생). scope_type: null=전체, role=역할 범위, self=본인 범위 |
|
||||
| permissions | array | `[{"id":1,"parent_id":null,"identifier":"core","name":"코어"…` | 연결된 권한 목록 (id/identifier/name — 역할 경유 권한 관계 파생) |
|
||||
| created_at | string | `2026-07-06 19:15:16` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-06 19:15:16` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true,"c…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.permissions.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
단일 역할의 상세 정보를 조회한다. 역할 편집 화면과 복제(clone_from) 시 원본 값을 채우는 데 사용된다. 목록 응답과 달리 permissions 관계를 pivot(scope_type)과 함께 로드하므로 `permission_ids`·`permission_values`·`permissions`(계층 트리)와 `users_count` 가 항상 포함된다. `core.permissions.read` 권한이 필요하다.
|
||||
|
||||
|
||||
### PUT /api/admin/roles/{role}
|
||||
<!-- @generated:start:api.admin.roles.update -->
|
||||
- **라우트명**: `api.admin.roles.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\RoleController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.permissions.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| role | path | string | 예 | — | 대상 role의 식별자 |
|
||||
| name | body | string | 예 | — | 대상의 이름/명칭 |
|
||||
| description | body | string | 아니오 | — | 설명 |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| permissions | body | array | 아니오 | — | 역할에 부여할 권한 목록. 각 원소는 `{id, scope_type}` (id=권한 식별자, scope_type=적용 범위: null 전체 / role 역할 범위 / self 본인 범위). 전달된 목록 기준으로 역할의 권한 집합이 재설정됨 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.role.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.permissions.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
기존 역할의 `name`·`description`·`is_active`·`permissions` 를 수정한다. 생성과 달리 `identifier` 는 변경 대상이 아니며, 각 필드는 `sometimes` 규칙이라 전달된 항목만 갱신된다. `permissions` 를 보내면 `[{id, scope_type}]` 형식으로 역할의 권한 집합 전체가 동기화된다(전달된 목록 기준으로 재설정). `name`·`description` 은 문자열/다국어 객체 양쪽을 받는다. 검증 규칙은 `core.role.update_validation_rules` 필터 훅으로 확장할 수 있다. `core.permissions.update` 권한이 필요하다.
|
||||
|
||||
|
||||
### PATCH /api/admin/roles/{role}/toggle-status
|
||||
<!-- @generated:start:api.admin.roles.toggle-status -->
|
||||
- **라우트명**: `api.admin.roles.toggle-status`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\RoleController@toggleStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.permissions.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| role | path | string | 예 | — | 대상 role의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.permissions.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
역할의 `is_active` 상태를 반대로 토글한다(활성↔비활성). 목록 화면의 상태 스위치에서 호출되며, 별도 본문 없이 대상 역할만 지정하면 된다. 성공 시 사용자 수를 다시 집계한 갱신된 역할 리소스를 반환한다. `core.permissions.update` 권한이 필요하다.
|
||||
|
||||
|
||||
@@ -0,0 +1,485 @@
|
||||
# Schedules API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Schedules 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/schedules
|
||||
<!-- @generated:start:api.admin.schedules.index -->
|
||||
- **라우트명**: `api.admin.schedules.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ScheduleController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.schedules.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| filters | query | array | 아니오 | max 10 | 추가 필터 조건 맵 (필드별 조건) |
|
||||
| type | query | string | 아니오 | `artisan`, `shell`, `url` | 유형 필터 (해당 유형의 항목만 조회) |
|
||||
| frequency | query | string | 아니오 | `everyMinute`, `hourly`, `daily`, `weekly`, `monthly`, `custom` | 실행 주기 |
|
||||
| status | query | string | 아니오 | `active`, `inactive` | 상태 필터 (해당 상태의 항목만 조회) |
|
||||
| last_result | query | string | 아니오 | `success`, `failed`, `running`, `never` | 마지막 실행 결과 필터: success(성공), failed(실패), running(실행중), never(미실행) 중 해당 결과인 스케줄만 조회 |
|
||||
| without_overlapping | query | string | 아니오 | `0`, `1` | 중복 실행 방지 여부 |
|
||||
| run_in_maintenance | query | string | 아니오 | `0`, `1` | 점검 모드 중 실행 여부 |
|
||||
| extension_type | query | string | 아니오 | `core`, `module`, `plugin` | 확장 유형 (core/module/plugin/template) |
|
||||
| extension_identifier | query | string | 아니오 | max 255 | 확장 식별자 |
|
||||
| created_from | query | date | 아니오 | — | 생성일 범위의 시작일 (이 날짜 이후 생성된 스케줄만 조회) |
|
||||
| created_to | query | date | 아니오 | — | 생성일 범위의 종료일 (이 날짜 이전 생성된 스케줄만 조회, created_from 이후여야 함) |
|
||||
| sort_by | query | string | 아니오 | `created_at`, `name`, `next_run_at`, `last_run_at`, `is_active`, `last_result` | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.schedule.list_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| name | string | `API 문서 샘플 스케줄` | 작업명 |
|
||||
| type | string | `artisan` | 작업 유형: artisan(Artisan 커맨드), shell(쉘 명령), url(URL 호출) |
|
||||
| type_label | string | `Artisan 커맨드` | `type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| command | string | `cache:clear` | 명령어 또는 URL |
|
||||
| expression | string | `0 3 * * *` | Cron 표현식 |
|
||||
| frequency | string | `daily` | 실행 주기: everyMinute(매분), hourly(매시간), daily(매일), weekly(매주), monthly(매월), custom(사용자 정의) |
|
||||
| frequency_label | string | `매일` | `frequency` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| without_overlapping | boolean | `true` | 중복 실행 방지 여부: 0(허용), 1(방지) |
|
||||
| run_in_maintenance | boolean | `false` | 점검 모드 실행 여부: 0(비실행), 1(실행) |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| last_result | string | `success` | 마지막 실행 결과: success(성공), failed(실패), running(실행중), never(미실행) |
|
||||
| last_result_label | string | `성공` | `last_result` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| last_run_at | string | `2026-07-05T19:20:23+09:00` | last run 일시 |
|
||||
| last_duration | null | `null` | 마지막 실행의 소요 시간을 사람이 읽는 문자열로 포맷한 값 (예: "45초", "2분 3초" — 마지막 실행 이력의 duration 파생, 실행 이력이 없으면 null) |
|
||||
| next_run_at | string | `2026-07-07T12:00:00+09:00` | next run 일시 |
|
||||
| creator | object | `{"uuid":"a231747f-e82e-4cf2-9ae1-a261849dce40","name":"AP…` | 생성자 정보 객체 (uuid/name/email — creator 관계 파생) |
|
||||
| created_at | string | `2026-07-06` | 생성 일시 |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true,"c…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.schedules.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 예약 작업(스케줄) 목록을 페이지네이션과 함께 조회하며, 응답에는 상태별 통계도 포함됩니다. `core.schedules.read` 권한이 필요합니다. `type`/`frequency`/`status`/`last_result`/`extension_type` 등으로 필터링하고 `sort_by`/`sort_order` 로 정렬할 수 있습니다. 관리자 스케줄 관리 화면의 목록·필터·요약 카드 표시에 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/schedules
|
||||
<!-- @generated:start:api.admin.schedules.store -->
|
||||
- **라우트명**: `api.admin.schedules.store`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ScheduleController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.schedules.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | string | 예 | max 255 | 대상의 이름/명칭 |
|
||||
| description | body | string | 아니오 | max 1000 | 설명 |
|
||||
| type | body | string | 예 | `artisan`, `shell`, `url` | 작업 유형: artisan(Artisan 커맨드 실행), shell(쉘 명령 실행), url(URL 호출) |
|
||||
| command | body | string | 예 | max 2000 | 실행할 아티즌 커맨드 |
|
||||
| expression | body | string | 예 | max 100 | 실행 시각을 정의하는 Cron 표현식 (예: `0 3 * * *`, 다음 실행 시각 next_run_at 계산의 기준) |
|
||||
| frequency | body | string | 예 | `everyMinute`, `hourly`, `daily`, `weekly`, `monthly`, `custom` | 실행 주기 |
|
||||
| without_overlapping | body | boolean | 아니오 | — | 중복 실행 방지 여부 |
|
||||
| run_in_maintenance | body | boolean | 아니오 | — | 점검 모드 중 실행 여부 |
|
||||
| timeout | body | integer | 아니오 | min 1, max 86400 | 타임아웃 (초) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| extension_type | body | string | 아니오 | `core`, `module`, `plugin` | 확장 유형 (core/module/plugin/template) |
|
||||
| extension_identifier | body | string | 아니오 | max 255 | 확장 식별자 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.schedule.create_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.schedules.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 새 예약 작업을 생성합니다. `core.schedules.create` 권한이 필요합니다. `type`(artisan/shell/url), `command`, `expression`, `frequency` 를 지정하며 생성자(creator)는 현재 사용자로 자동 기록됩니다. 검증 실패 시 422로 응답하고, 성공 시 201과 생성된 스케줄 리소스를 반환합니다. 관리자 스케줄 등록 폼에 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/admin/schedules/bulk
|
||||
<!-- @generated:start:api.admin.schedules.bulk-delete -->
|
||||
- **라우트명**: `api.admin.schedules.bulk-delete`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ScheduleController@bulkDelete`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.schedules.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | query | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.schedule.bulk_delete_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.schedules.delete`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 전달된 `ids` 배열의 스케줄을 일괄 삭제합니다. `core.schedules.delete` 권한이 필요합니다. 삭제 처리 결과 요약을 반환하며, 검증 실패 시 422로 응답합니다. 목록에서 여러 스케줄을 선택해 한 번에 제거하는 동작에 사용합니다.
|
||||
|
||||
|
||||
### PATCH /api/admin/schedules/bulk-status
|
||||
<!-- @generated:start:api.admin.schedules.bulk-status -->
|
||||
- **라우트명**: `api.admin.schedules.bulk-status`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ScheduleController@bulkUpdateStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.schedules.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
| is_active | body | boolean | 예 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.schedule.bulk_update_status_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.schedules.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 전달된 `ids` 배열의 스케줄 활성 상태(`is_active`)를 일괄 변경합니다. `core.schedules.update` 권한이 필요합니다. 처리 결과 요약을 반환하며, 검증 실패 시 422로 응답합니다. 목록에서 여러 스케줄을 선택해 한 번에 활성화/비활성화하는 동작에 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/admin/schedules/history/{historyId}
|
||||
<!-- @generated:start:api.admin.schedules.delete-history -->
|
||||
- **라우트명**: `api.admin.schedules.delete-history`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ScheduleController@deleteHistory`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.schedules.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| historyId | path | string | 예 | — | 대상 history의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.schedules.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 실행 이력 레코드를 삭제합니다. `core.schedules.delete` 권한이 필요합니다. 대상 이력이 없으면 404로 응답합니다. 스케줄 상세의 실행 이력 목록에서 개별 이력을 제거할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/admin/schedules/statistics
|
||||
<!-- @generated:start:api.admin.schedules.statistics -->
|
||||
- **라우트명**: `api.admin.schedules.statistics`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ScheduleController@statistics`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.schedules.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| total | integer | `1` | 전체 개수 (집계) |
|
||||
| active | integer | `1` | 활성(is_active=true) 스케줄 수 |
|
||||
| inactive | integer | `0` | 비활성(is_active=false) 스케줄 수 |
|
||||
| success | integer | `1` | 마지막 실행 결과가 성공(success)인 스케줄 수 |
|
||||
| failed | integer | `0` | 마지막 실행 결과가 실패(failed)인 스케줄 수 |
|
||||
| running | integer | `0` | 마지막 실행 결과가 실행중(running)인 스케줄 수 |
|
||||
| never_run | integer | `0` | 아직 한 번도 실행되지 않은(last_result=never) 스케줄 수 |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.schedules.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 스케줄 전체의 집계 통계를 조회합니다. `core.schedules.read` 권한이 필요합니다. 전체/활성/비활성 수와 마지막 실행 결과별(성공/실패/실행중/미실행) 건수를 반환합니다. 관리자 스케줄 대시보드의 요약 카드 표시에 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/admin/schedules/{schedule}
|
||||
<!-- @generated:start:api.admin.schedules.destroy -->
|
||||
- **라우트명**: `api.admin.schedules.destroy`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ScheduleController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.schedules.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| schedule | path | string | 예 | — | 대상 schedule의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.schedules.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 단일 스케줄을 삭제합니다. `core.schedules.delete` 권한이 필요합니다. 경로의 `schedule` 은 라우트 모델 바인딩으로 해석되어 존재하지 않으면 404가 됩니다. 관리자 스케줄 관리 화면의 개별 삭제 동작에 사용합니다.
|
||||
|
||||
|
||||
### GET /api/admin/schedules/{schedule}
|
||||
<!-- @generated:start:api.admin.schedules.show -->
|
||||
- **라우트명**: `api.admin.schedules.show`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ScheduleController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.schedules.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| schedule | path | string | 예 | — | 대상 schedule의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| name | string | `API 문서 샘플 스케줄` | 작업명 |
|
||||
| description | string | `문서 실측용 스케줄` | 설명 |
|
||||
| type | string | `artisan` | 작업 유형: artisan(Artisan 커맨드), shell(쉘 명령), url(URL 호출) |
|
||||
| type_label | string | `Artisan 커맨드` | `type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| command | string | `cache:clear` | 명령어 또는 URL |
|
||||
| expression | string | `0 3 * * *` | Cron 표현식 |
|
||||
| frequency | string | `daily` | 실행 주기: everyMinute(매분), hourly(매시간), daily(매일), weekly(매주), monthly(매월), custom(사용자 정의) |
|
||||
| frequency_label | string | `매일` | `frequency` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| without_overlapping | boolean | `true` | 중복 실행 방지 여부: 0(허용), 1(방지) |
|
||||
| run_in_maintenance | boolean | `false` | 점검 모드 실행 여부: 0(비실행), 1(실행) |
|
||||
| timeout | integer | `300` | 실행 제한 시간 (초) |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| last_result | string | `success` | 마지막 실행 결과: success(성공), failed(실패), running(실행중), never(미실행) |
|
||||
| last_result_label | string | `성공` | `last_result` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| last_run_at | string | `2026-07-05T19:20:23+09:00` | last run 일시 |
|
||||
| last_duration | null | `null` | 마지막 실행의 소요 시간을 사람이 읽는 문자열로 포맷한 값 (예: "45초", "2분 3초" — 마지막 실행 이력의 duration 파생, 실행 이력이 없으면 null) |
|
||||
| next_run_at | string | `2026-07-07T12:00:00+09:00` | next run 일시 |
|
||||
| extension_type | null | `null` | 확장 소유 타입: core(코어), module(모듈), plugin(플러그인), NULL(사용자 정의) |
|
||||
| extension_identifier | null | `null` | 확장 식별자 (예: core, sirsoft-board, sirsoft-payment) |
|
||||
| creator | object | `{"uuid":"a231747f-e82e-4cf2-9ae1-a261849dce40","name":"AP…` | 생성자 정보 객체 (uuid/name/email — creator 관계 파생) |
|
||||
| created_at | string | `2026-07-06 19:20:23` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-06 19:20:23` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true,"c…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.schedules.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 단일 스케줄의 상세 정보를 조회하며 생성자(creator) 정보를 함께 로드합니다. `core.schedules.read` 권한이 필요합니다. 경로의 `schedule` 은 라우트 모델 바인딩으로 해석되어 없으면 404가 됩니다. 관리자 스케줄 상세/수정 화면의 초기 데이터 로딩에 사용합니다.
|
||||
|
||||
|
||||
### PUT /api/admin/schedules/{schedule}
|
||||
<!-- @generated:start:api.admin.schedules.update -->
|
||||
- **라우트명**: `api.admin.schedules.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ScheduleController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.schedules.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| schedule | path | string | 예 | — | 대상 schedule의 식별자 |
|
||||
| name | body | string | 예 | max 255 | 대상의 이름/명칭 |
|
||||
| description | body | string | 아니오 | max 1000 | 설명 |
|
||||
| type | body | string | 예 | `artisan`, `shell`, `url` | 작업 유형: artisan(Artisan 커맨드 실행), shell(쉘 명령 실행), url(URL 호출) |
|
||||
| command | body | string | 예 | max 2000 | 실행할 아티즌 커맨드 |
|
||||
| expression | body | string | 예 | max 100 | 실행 시각을 정의하는 Cron 표현식 (예: `0 3 * * *`, 다음 실행 시각 next_run_at 계산의 기준) |
|
||||
| frequency | body | string | 예 | `everyMinute`, `hourly`, `daily`, `weekly`, `monthly`, `custom` | 실행 주기 |
|
||||
| without_overlapping | body | boolean | 아니오 | — | 중복 실행 방지 여부 |
|
||||
| run_in_maintenance | body | boolean | 아니오 | — | 점검 모드 중 실행 여부 |
|
||||
| timeout | body | integer | 아니오 | min 1, max 86400 | 타임아웃 (초) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| extension_type | body | string | 아니오 | `core`, `module`, `plugin` | 확장 유형 (core/module/plugin/template) |
|
||||
| extension_identifier | body | string | 아니오 | max 255 | 확장 식별자 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.schedule.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.schedules.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 기존 스케줄 정보를 수정합니다. `core.schedules.update` 권한이 필요합니다. store 와 동일한 필드(`type`/`command`/`expression`/`frequency` 등)를 받으며 검증 실패 시 422로 응답합니다. 경로의 `schedule` 은 라우트 모델 바인딩으로 해석되며, 수정된 스케줄 리소스를 반환합니다. 관리자 스케줄 수정 폼에 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/schedules/{schedule}/duplicate
|
||||
<!-- @generated:start:api.admin.schedules.duplicate -->
|
||||
- **라우트명**: `api.admin.schedules.duplicate`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ScheduleController@duplicate`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.schedules.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| schedule | path | string | 예 | — | 대상 schedule의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.schedules.create`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 기존 스케줄을 복제해 새 스케줄을 만듭니다. `core.schedules.create` 권한이 필요합니다. 원본을 바탕으로 새 레코드를 생성하며, 성공 시 201과 복제된 스케줄 리소스를 반환합니다. 유사한 설정의 스케줄을 빠르게 추가하는 "복제" 동작에 사용합니다.
|
||||
|
||||
|
||||
### GET /api/admin/schedules/{schedule}/history
|
||||
<!-- @generated:start:api.admin.schedules.history -->
|
||||
- **라우트명**: `api.admin.schedules.history`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ScheduleController@history`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.schedules.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| schedule | path | string | 예 | — | 대상 schedule의 식별자 |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| status | query | string | 아니오 | `success`, `failed`, `running` | 상태 필터 (해당 상태의 항목만 조회) |
|
||||
| trigger_type | query | string | 아니오 | `scheduled`, `manual` | 실행 방식 필터: scheduled(예약 시각 자동 실행), manual(관리자의 즉시 실행) 중 해당 이력만 조회 |
|
||||
| started_from | query | date | 아니오 | — | 실행 시작일 범위의 시작일 (이 날짜 이후 시작된 이력만 조회) |
|
||||
| started_to | query | date | 아니오 | — | 실행 시작일 범위의 종료일 (이 날짜 이전 시작된 이력만 조회, started_from 이후여야 함) |
|
||||
| sort_by | query | string | 아니오 | `started_at`, `ended_at`, `duration`, `status` | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.schedule.history_list_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.schedules.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 스케줄의 실행 이력을 페이지네이션으로 조회합니다. `core.schedules.read` 권한이 필요합니다. `status`(success/failed/running), `trigger_type`(scheduled/manual), 기간(`started_from`/`started_to`)으로 필터링하고 `sort_by`/`sort_order` 로 정렬할 수 있습니다. 스케줄 상세의 실행 이력 탭 표시에 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/schedules/{schedule}/run
|
||||
<!-- @generated:start:api.admin.schedules.run -->
|
||||
- **라우트명**: `api.admin.schedules.run`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\ScheduleController@run`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.schedules.run`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| schedule | path | string | 예 | — | 대상 schedule의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.schedules.run`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 스케줄을 예약 시각과 무관하게 즉시 실행합니다. `core.schedules.run` 권한이 필요합니다. 실제 명령이 수행되고 실행 이력 레코드가 생성되며, 그 이력(trigger_type=manual)을 반환합니다. 관리자가 대상 작업을 수동으로 즉시 돌려 결과를 확인하는 "지금 실행" 동작에 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# Search API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Search 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/search
|
||||
<!-- @generated:start:api.search -->
|
||||
- **라우트명**: `api.search`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicSearchController@search`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| q | query | string | 아니오 | min 2, max 200 | 검색어 (부분 일치) |
|
||||
| type | query | string | 아니오 | — | 유형 필터 (해당 유형의 항목만 조회) |
|
||||
| sort | query | string | 아니오 | `relevance`, `latest`, `oldest`, `views`, `popular`, `price_asc`, `price_desc` | 정렬 기준 (필드명, `-` 접두 시 내림차순) |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| board_slug | query | string | 아니오 | max 100 | 검색 범위를 특정 게시판으로 한정 (게시판 모듈이 `core.search.validation_rules` 훅으로 추가하는 파라미터, 해당 slug의 게시판 글만 검색) |
|
||||
| category_id | query | integer | 아니오 | — | category 식별자 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.search.validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| q | string | `` | 실제 검색에 사용된 검색어 (요청 `q` 를 trim 하여 에코, 검색어가 비어 있으면 빈 문자열) |
|
||||
| total | integer | `0` | 전체 개수 (집계) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
프론트엔드 통합 검색(`search/index.json`)이 호출하는 공개 엔드포인트입니다. 인증이 필요 없으며 게스트도 사용할 수 있습니다. 코어 컨트롤러는 검색 결과를 직접 생성하지 않고, 검증된 파라미터로 검색 컨텍스트(q/type/sort/page/per_page 및 요청 객체)를 구성한 뒤 `core.search.results` Filter 훅을 실행합니다. 게시판·상품 등 각 검색 대상 모듈이 이 훅에 리스너를 등록해 자신의 카테고리 결과를 추가하고, `core.search.build_response` 훅으로 응답 구조를 완성합니다. 따라서 활성 검색 모듈이 없으면 항상 빈 결과(`total: 0`)가 반환됩니다. 검색 엔진 자체는 Scout + `DatabaseFulltextEngine`(MySQL FULLTEXT) 기반이며, 상세는 `docs/backend/search-system.md`를 참고하세요.
|
||||
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
# Seo API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Seo 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/seo/cached-urls
|
||||
<!-- @generated:start:api.admin.seo.cached-urls -->
|
||||
- **라우트명**: `api.admin.seo.cached-urls`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SeoCacheController@cachedUrls`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| urls | array | `[]` | 현재 사전 렌더 캐시에 남아 있는 봇 대상 페이지 URL 목록 (SeoCacheManager 인덱스에서 조회). |
|
||||
| count | integer | `0` | 캐시된 URL 개수 (`urls` 배열 길이). |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
SeoCacheManager 인덱스에서 현재 캐시된 SEO 페이지 URL 목록과 개수를 조회합니다. 어떤 봇 대상 페이지가 사전 렌더 캐시로 남아 있는지 확인하는 진단 용도로 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/seo/clear-cache
|
||||
<!-- @generated:start:api.admin.seo.clear-cache -->
|
||||
- **라우트명**: `api.admin.seo.clear-cache`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SeoCacheController@clearCache`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| layout | body | string | 아니오 | — | 무효화 대상 레이아웃명. 지정 시 해당 레이아웃의 SEO 캐시만 삭제하고 무효화된 항목 수를 반환하며, 미지정 시 전체 SEO 캐시를 삭제한다. |
|
||||
| module | body | string | 아니오 | — | 모듈 식별자 필터. 검증 규칙에는 정의되어 있으나 현재 컨트롤러 로직에서는 사용되지 않는다(향후 모듈 단위 캐시 무효화 확장 예약 필드). |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
SEO 사전 렌더 캐시를 삭제합니다. `layout` 을 지정하면 해당 레이아웃 캐시만 무효화하고, 지정하지 않으면 전체 SEO 캐시를 삭제합니다. 응답의 `data.cleared` 는 `layout` 지정 시 무효화된 항목 수(정수), 미지정 시 문자열 `"all"` 입니다. 설정이나 콘텐츠 변경 후 오래된 봇 응답이 캐시로 남는 것을 방지할 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/seo/sitemap/regenerate
|
||||
<!-- @generated:start:api.admin.seo.sitemap.regenerate -->
|
||||
- **라우트명**: `api.admin.seo.sitemap.regenerate`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SeoCacheController@regenerateSitemap`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
sitemap.xml 을 즉시 재생성합니다. SitemapManager 에 위임하며 큐 드라이버와 무관하게 동기(즉시) 실행되고, 완료 후 마지막 생성 시각을 갱신합니다. SEO 설정에서 sitemap 기능이 비활성인 경우 400(`seo.sitemap_disabled`), 생성 실패 시 500 을 반환합니다. 관리자가 콘텐츠 변경 후 검색엔진에 노출할 sitemap 을 스케줄 대기 없이 즉시 갱신할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/admin/seo/stats
|
||||
<!-- @generated:start:api.admin.seo.stats -->
|
||||
- **라우트명**: `api.admin.seo.stats`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SeoCacheController@stats`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| overall | object | `{"total_entries":0,"hits":0,"misses":0,"hit_rate":0,"avg_…` | 최근 7일 전체 캐시 통계 집계. `total_entries`(기록 총 건수), `hits`(적중 건수), `misses`(미적중 건수), `hit_rate`(적중률 %, hits/total×100), `avg_response_time_ms`(미적중 시 평균 렌더링 소요 시간 ms, 데이터 없으면 null). |
|
||||
| by_layout | array | `[]` | 레이아웃별 통계 목록 (`layout_name` 으로 그룹핑). 각 원소는 `layout_name`·`total`·`hits`·`misses`·`hit_rate`·`avg_response_time_ms` 를 가지며, 레이아웃 단위로 캐시 효율을 비교하는 용도. |
|
||||
| by_module | array | `[]` | 모듈별 통계 목록 (`module_identifier` 로 그룹핑). 각 원소는 `module_identifier`·`total`·`hits`·`misses`·`hit_rate`·`avg_response_time_ms` 를 가지며, 어느 확장 모듈의 SEO 페이지가 캐시로 재사용되는지 파악하는 용도. |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
SEO 캐시 적중 현황을 최근 7일 기준으로 전체·레이아웃별·모듈별로 조회합니다. 봇 대상 사전 렌더 캐시가 얼마나 효과적으로 재사용되는지(적중률, 렌더 비용 절감)를 모니터링하는 관리자 대시보드용 통계입니다.
|
||||
|
||||
|
||||
### POST /api/admin/seo/warmup
|
||||
<!-- @generated:start:api.admin.seo.warmup -->
|
||||
- **라우트명**: `api.admin.seo.warmup`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SeoCacheController@warmup`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
SEO 캐시 워밍업(모든 SEO 레이아웃 사전 렌더)을 위한 엔드포인트입니다. 현재 컨트롤러는 실제 워밍업 로직 없이 `status: dispatched` 와 안내 메시지만 반환합니다(실 렌더링은 후속 구현 예정). 응답 성공은 요청 접수만을 의미하며 이 시점에 캐시가 채워지지는 않습니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,563 @@
|
||||
# Settings API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Settings 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/settings
|
||||
<!-- @generated:start:api.admin.settings.index -->
|
||||
- **라우트명**: `api.admin.settings.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| general | object | `{"site_name":"Test Site","site_url":"https:\/\/test.examp…` | 일반 탭 설정 그룹 (사이트명·사이트 URL·설명·관리자 이메일·타임존·기본 언어·통화·점검 모드·사이트 로고 첨부). site_logo 는 SettingsService 가 별도 주입한 첨부 정보 |
|
||||
| security | object | `{"force_https":true,"login_attempt_enabled":true,"auth_to…` | 보안 탭 설정 그룹 (HTTPS 강제·로그인 시도 제한 사용·인증 토큰 유지시간(분, 0=무한)·최대 로그인 시도 횟수·잠금 시간) |
|
||||
| mail | object | `{"mailer":"smtp","host":"","port":587,"username":"","pass…` | 메일 탭 설정 그룹 (메일러 종류(smtp/mailgun/ses)·SMTP 호스트/포트/인증 정보·암호화 방식·발신자 주소/이름·Mailgun/SES 자격 정보) |
|
||||
| upload | object | `{"max_file_size":10,"allowed_extensions":["jpg","jpeg","p…` | 업로드 탭 설정 그룹 (최대 파일 크기(MB)·허용 확장자 목록·이미지 최대 가로/세로·이미지 품질) |
|
||||
| seo | object | `{"meta_title_suffix":"","meta_description":"","meta_keywo…` | SEO 탭 설정 그룹 (메타 타이틀 접미사·메타 설명/키워드·검색엔진 인증 코드·봇 감지·OG/Twitter 기본값·SEO 캐시·사이트맵·생성기 설정) |
|
||||
| advanced | object | `{"cache_enabled":true,"cache_default_ttl":86400,"layout_c…` | 고급 탭 설정 그룹 (캐시·디버그·코어 업데이트·GeoIP 설정을 한 탭으로 합친 병합 뷰). cache/debug 카테고리 값이 함께 노출됨 |
|
||||
| cache | object | `{"cache_enabled":true,"cache_default_ttl":86400,"layout_c…` | 캐시 원본 카테고리 (전역 캐시 사용·기본 TTL·레이아웃/통계/SEO 캐시 사용 및 TTL). advanced 탭에 병합되면서 개별 접근용으로 별도 노출된 파생 뷰 |
|
||||
| debug | object | `{"debug_mode":true,"sql_query_log":false,"log_level":"err…` | 디버그 원본 카테고리 (디버그 모드·SQL 쿼리 로그·로그 레벨). advanced 탭에 병합되면서 개별 접근용으로 별도 노출된 파생 뷰 |
|
||||
| drivers | object | `{"storage_driver":"local","s3_bucket":null,"s3_region":"a…` | 드라이버 탭 설정 그룹 (스토리지/캐시/세션/큐/로그 드라이버 선택 + S3·Redis·Memcached·WebSocket·검색엔진 접속 파라미터) |
|
||||
| core_update | object | `{"core_update_github_url":"https:\/\/github.com\/custom\/…` | 코어 업데이트 원본 카테고리 (코어 업데이트를 받아올 GitHub 저장소 URL·비공개 저장소 접근용 토큰). advanced 탭에 병합된 파생 뷰 |
|
||||
| geoip | object | `{"geoip_enabled":false,"geoip_license_key":null,"geoip_au…` | GeoIP 원본 카테고리 (GeoIP 사용 여부·MaxMind 라이선스 키·DB 자동 갱신 사용). advanced 탭에 병합된 파생 뷰 |
|
||||
| notifications | object | `{"channels":[{"id":"mail","is_active":true,"sort_order":1…` | 알림 탭 설정 그룹. channels 는 알림 채널 목록으로 각 원소가 id(채널 식별자)·is_active(활성 여부)·sort_order(표시 순서)를 가짐 |
|
||||
| identity | object | `{"default_provider":"g7:core.mail","purpose_providers":{"…` | 본인인증(IDV) 탭 설정 그룹 (기본 provider·목적별 provider 매핑(purpose_providers)·챌린지 유효시간(분)·최대 시도 횟수) |
|
||||
| available_drivers | object | `{"storage":[{"id":"local","label":{"ko":"로컬","en":"Local"…` | 드라이버 선택지 카탈로그 (DriverRegistryService 산물). 종류별(storage/cache/session/queue 등) 선택 가능한 드라이버 목록을 id/다국어 label 형태로 제공 |
|
||||
| abilities | object | `{"can_update":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
관리자 통합 환경설정 화면(`admin_settings.json`)이 사용하는 전체 설정 조회 엔드포인트입니다. 각 탭에 해당하는 설정 그룹(general/security/mail/upload/seo/advanced/drivers/geoip/notifications/identity 등)과 드라이버 선택지 카탈로그(`available_drivers`)를 한 번에 반환합니다. 응답은 Eloquent 모델이 아니라 SettingsService 가 여러 설정 소스를 병합해 만든 집계 배열이며, 일부 그룹(cache/debug 등)은 원본 카테고리 값을 별도 키로 함께 노출한 파생 뷰입니다.
|
||||
|
||||
|
||||
### POST /api/admin/settings
|
||||
<!-- @generated:start:api.admin.settings.store -->
|
||||
- **라우트명**: `api.admin.settings.store`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| _tab | body | string | 아니오 | — | 활성 탭 식별자 (general/mail/upload/seo/security/drivers/advanced/notifications/identity). 지정 시 해당 탭 필드만 필수 검증되고 나머지 탭은 nullable 처리되어 탭 단위 부분 저장을 가능케 함 |
|
||||
| general | body | array | 아니오 | — | 일반 탭 설정 묶음 (사이트명·URL·설명·관리자 이메일·타임존·기본 언어·통화·점검 모드·사이트 로고) |
|
||||
| mail | body | array | 아니오 | — | 메일 탭 설정 묶음 (메일러 종류·SMTP 호스트/포트/인증·암호화·발신자 정보·Mailgun/SES 자격 정보) |
|
||||
| upload | body | array | 아니오 | — | 업로드 탭 설정 묶음 (최대 파일 크기·허용 확장자·이미지 최대 크기 및 품질) |
|
||||
| seo | body | array | 아니오 | — | SEO 탭 설정 묶음 (메타 태그·검색엔진 인증·봇 감지·OG/Twitter 기본값·SEO 캐시·사이트맵·생성기) |
|
||||
| security | body | array | 아니오 | — | 보안 탭 설정 묶음 (HTTPS 강제·로그인 시도 제한·인증 토큰 유지시간·최대 시도 횟수·잠금 시간) |
|
||||
| drivers | body | array | 아니오 | — | 드라이버 탭 설정 묶음 (스토리지/캐시/세션/큐/로그 드라이버 및 S3·Redis·Memcached·WebSocket·검색엔진 접속 정보) |
|
||||
| advanced | body | array | 아니오 | — | 고급 탭 설정 묶음 (캐시·디버그·코어 업데이트·GeoIP 설정) |
|
||||
| notifications | body | array | 아니오 | — | 알림 탭 설정 묶음. channels 배열로 각 알림 채널의 id·is_active(활성 여부)·sort_order(표시 순서)를 저장 |
|
||||
| identity | body | array | 아니오 | — | 본인인증(IDV) 탭 설정 묶음 (기본 provider·목적별 provider 매핑·챌린지 유효시간·최대 시도 횟수) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.settings.save_validation_rules`, `core.search.engine_drivers`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
통합 환경설정 화면에서 한 탭의 설정을 일괄 저장합니다. `_tab` 으로 활성 탭을 지정하면 해당 탭의 필드만 필수 검증되고 다른 탭 필드는 nullable 로 처리되므로, 탭 단위로 부분 저장할 수 있습니다. 저장 성공 시 응답 `data.settings` 에 갱신된 전체 설정과 `available_drivers` 를 함께 반환하여, 프론트엔드가 새로고침 없이 전역 상태를 갱신할 수 있습니다. 검증 실패 시 422, 그 외 오류 시 500 을 반환합니다.
|
||||
|
||||
|
||||
### GET /api/admin/settings/app-key
|
||||
<!-- @generated:start:api.admin.settings.app-key -->
|
||||
- **라우트명**: `api.admin.settings.app-key`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@getAppKey`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| app_key | string | `base64:97gZH*************************…` | 현재 애플리케이션 키(`APP_KEY`)를 마스킹한 문자열. 앞부분 일부만 노출하고 나머지는 별표로 가려 전체 원문은 반환하지 않음 |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 애플리케이션 키(`APP_KEY`)를 마스킹된 형태로 조회합니다. 관리자 화면에서 앱 키 존재/일부만 표시하는 용도이며, 전체 키 원문은 반환하지 않습니다.
|
||||
|
||||
|
||||
### POST /api/admin/settings/backup
|
||||
<!-- @generated:start:api.admin.settings.backup -->
|
||||
- **라우트명**: `api.admin.settings.backup`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@backup`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 설정을 백업 파일로 저장합니다. 응답 `data.backup_path` 에 생성된 백업 경로를 반환하며, 이 경로는 이후 `POST /restore` 의 `backup_path` 로 사용할 수 있습니다. 설정 변경 전 스냅샷을 남길 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/settings/backup-database
|
||||
<!-- @generated:start:api.admin.settings.backup-database -->
|
||||
- **라우트명**: `api.admin.settings.backup-database`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@backupDatabase`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
데이터베이스를 백업합니다. SettingsService 에 위임하며, 성공/실패를 메시지로 반환합니다. 설정 백업(`POST /backup`)이 설정 파일만 다루는 것과 달리, 이 엔드포인트는 DB 데이터를 백업 대상으로 합니다.
|
||||
|
||||
|
||||
### POST /api/admin/settings/clear-cache
|
||||
<!-- @generated:start:api.admin.settings.clear-cache -->
|
||||
- **라우트명**: `api.admin.settings.clear-cache`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@clearCache`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
시스템 캐시를 정리합니다. 시스템 정보 캐시를 지원 로케일별로 비운 뒤 `cache:clear`, `route:clear`, `view:clear` 를 실행하고, config 캐시는 비운 직후 즉시 재생성합니다(비워 두면 이후 모든 요청이 config 를 재파싱하므로). 설정/코드 변경 후 오래된 캐시를 초기화할 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/admin/settings/geoip/update
|
||||
<!-- @generated:start:api.admin.settings.geoip.update -->
|
||||
- **라우트명**: `api.admin.settings.geoip.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\GeoIpController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
MaxMind GeoLite2-City DB 를 즉시 재다운로드합니다. GeoIpDatabaseService 에 위임하며 동기(즉시) 실행되므로 웹서버/PHP-FPM 타임아웃(90초 이상)이 필요합니다. 라이선스 키 미설정 시 400, 키가 잘못된 경우 401, 연결 실패/기타 오류 시 500 을 반환합니다. 정기 갱신은 스케줄(`geoip:update`)이 담당하고, 이 엔드포인트는 수동 갱신 트리거입니다.
|
||||
|
||||
|
||||
### POST /api/admin/settings/optimize-system
|
||||
<!-- @generated:start:api.admin.settings.optimize-system -->
|
||||
- **라우트명**: `api.admin.settings.optimize-system`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@optimizeSystem`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
시스템을 최적화합니다. `config:cache`, `route:cache`, `view:cache` 를 실행해 설정·라우트·뷰 캐시를 생성함으로써 이후 요청의 부팅 비용을 줄입니다. 캐시를 비우는 `clear-cache` 와 반대로, 캐시를 사전 생성하는 프로덕션 성능용 작업입니다.
|
||||
|
||||
|
||||
### POST /api/admin/settings/regenerate-app-key
|
||||
<!-- @generated:start:api.admin.settings.regenerate-app-key -->
|
||||
- **라우트명**: `api.admin.settings.regenerate-app-key`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@regenerateAppKey`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| password | body | string | 예 | — | 비밀번호 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.settings.regenerate_app_key_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
애플리케이션 키(`APP_KEY`)를 재생성합니다. FormRequest 단계에서 `super_admin` 역할만 허용하고, Service 단계에서 요청자 본인의 비밀번호가 일치하는지 다시 확인합니다(불일치 시 401). 성공 시 새 키를 `.env` 의 `APP_KEY` 에 기록하고 config 캐시를 재생성하며, 응답 `data.app_key` 에 새 키를 반환합니다. 앱 키 변경은 기존 암호화 값/서명 무효화를 동반하므로 주의가 필요합니다.
|
||||
|
||||
|
||||
### POST /api/admin/settings/restore
|
||||
<!-- @generated:start:api.admin.settings.restore -->
|
||||
- **라우트명**: `api.admin.settings.restore`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@restore`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| backup_path | body | string | 예 | — | 복원할 백업 파일 경로. `POST /api/admin/settings/backup` 응답의 `backup_path` 로 받은 값을 그대로 지정 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.settings.restore_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
이전에 만든 설정 백업에서 설정을 복원합니다. `backup_path` 로 `POST /backup` 이 반환한 백업 경로를 지정합니다. 복원 성공 시 시스템 설정 캐시를 무효화합니다. 잘못된 설정을 되돌릴 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/admin/settings/system-info
|
||||
<!-- @generated:start:api.admin.settings.system-info -->
|
||||
- **라우트명**: `api.admin.settings.system-info`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@systemInfo`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| os_info | string | `Windows NT 10.0` | 운영체제 종류와 버전 (`php_uname` 산물). probe 차단 시 "알 수 없음" 폴백 |
|
||||
| web_server | string | `Apache/2.4.62 (Win64) OpenSSL/3.0.16 …` | 웹서버 소프트웨어 식별 문자열 (`$_SERVER['SERVER_SOFTWARE']`) |
|
||||
| php_version | string | `8.3.26` | 실행 중인 PHP 버전 (`PHP_VERSION`) |
|
||||
| mysql_version | string | `Mysql 8.4.3` | 연결된 데이터베이스 서버 종류와 버전 (DB 조회 산물). probe 실패 시 "알 수 없음" 폴백 |
|
||||
| g7_version | string | `7.0.1` | G7 코어 버전 (`config('app.version')`) |
|
||||
| g7_release_year | string | `2026` | G7 릴리즈 연도 (`config('app.release_year')`, 저작권 표기 등에 사용) |
|
||||
| laravel_version | string | `12.54.1` | 프레임워크 Laravel 버전 (`app()->version()`) |
|
||||
| environment | string | `local` | 현재 실행 환경 (`app()->environment()` — local/production/testing 등) |
|
||||
| cpu_info | string | `Intel(R) Core(TM) Ultra 5 225H` | CPU 모델명 (OS별 시스템 probe 산물). 수집 실패 시 "알 수 없음" 폴백 |
|
||||
| memory_usage | object | `{"total":"31.49 GB","used":"29.63 GB","free":"1.86 GB","p…` | 물리 메모리 사용량. total/used/free 는 사람이 읽기 쉬운 단위 문자열, percentage 는 사용률(%) |
|
||||
| disk_usage | object | `{"total":"474.72 GB","used":"360.2 GB","free":"114.51 GB"…` | 설치 볼륨 디스크 사용량. total/used/free 단위 문자열 + percentage 사용률(%) |
|
||||
| php_memory_limit | string | `512M` | PHP `memory_limit` ini 값 |
|
||||
| max_execution_time | string | `36000초` | PHP `max_execution_time` ini 값 (초 단위 접미사 부착) |
|
||||
| upload_max_filesize | string | `2G` | PHP `upload_max_filesize` ini 값 |
|
||||
| install_path | string | `C:\Users\HeuJung\htdocs\g7_2` | 애플리케이션 설치 루트 경로 (`base_path()`) |
|
||||
| config_path | string | `C:\Users\HeuJung\htdocs\g7_2\storage\…` | 설정 파일 저장 경로 (`storage/app/settings`) |
|
||||
| log_path | string | `C:\Users\HeuJung\htdocs\g7_2\storage\…` | 로그 파일 저장 경로 (`storage/logs`) |
|
||||
| upload_path | string | `C:\Users\HeuJung\htdocs\g7_2\storage\…` | 공개 업로드 파일 저장 경로 (`storage/app/public`) |
|
||||
| php_extensions | object | `{"required":{"openssl":true,"pdo":true,"mbstring":true,"t…` | PHP 확장 로드 상태. required(필수)·optional(선택) 두 그룹으로 나뉘며 각 확장명→로드 여부(bool) 매핑 |
|
||||
| database_config | object | `{"has_read_write_split":false,"write":{"host":"localhost"…` | DB 연결 구성 요약. has_read_write_split(읽기/쓰기 분리 여부)·write(쓰기 연결 정보)·read(읽기 replica 목록, write 와 동일하면 제외) |
|
||||
| timezone | string | `UTC` | 애플리케이션 기본 타임존 (`config('app.timezone')`) |
|
||||
| server_time | string | `2026-07-07 05:08:58` | 서버 현재 시각 (Y-m-d H:i:s) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
서버 실행 환경 정보를 한 번에 조회합니다. OS/웹서버/PHP/DB/Laravel/코어 버전, CPU·메모리·디스크 사용량, PHP 주요 설정값(memory_limit·max_execution_time·upload_max_filesize), 주요 경로, PHP 확장 로드 상태, DB 연결 구성 요약 등을 포함합니다. 관리자 시스템 정보 화면과 요구사항 점검용 진단 데이터로 사용됩니다.
|
||||
|
||||
|
||||
### POST /api/admin/settings/test-driver
|
||||
<!-- @generated:start:api.admin.settings.test-driver -->
|
||||
- **라우트명**: `api.admin.settings.test-driver`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@testDriverConnection`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| storage_driver | body | string | 아니오 | — | 스토리지 드라이버 (local/s3) |
|
||||
| cache_driver | body | string | 아니오 | — | 캐시 드라이버 (file/redis/memcached) |
|
||||
| session_driver | body | string | 아니오 | — | 세션 드라이버 (file/database/redis) |
|
||||
| queue_driver | body | string | 아니오 | — | 큐 드라이버 (sync/database/redis) |
|
||||
| websocket_enabled | body | boolean | 아니오 | — | WebSocket 사용 여부 |
|
||||
| s3_bucket | body | string | 아니오 | max 255 | S3 버킷명 |
|
||||
| s3_region | body | string | 아니오 | — | S3 리전 |
|
||||
| s3_access_key | body | string | 아니오 | max 255 | S3 액세스 키 |
|
||||
| s3_secret_key | body | string | 아니오 | max 255 | S3 시크릿 키 |
|
||||
| s3_url | body | string | 아니오 | max 500 | S3 엔드포인트 URL |
|
||||
| redis_host | body | string | 아니오 | max 255 | Redis 호스트 주소 |
|
||||
| redis_port | body | integer | 아니오 | min 1, max 65535 | Redis 포트 번호 |
|
||||
| redis_password | body | string | 아니오 | max 255 | Redis 비밀번호 |
|
||||
| redis_database | body | integer | 아니오 | min 0, max 15 | Redis 데이터베이스 번호 |
|
||||
| memcached_host | body | string | 아니오 | max 255 | Memcached 호스트 주소 |
|
||||
| memcached_port | body | integer | 아니오 | min 1, max 65535 | Memcached 포트 번호 |
|
||||
| websocket_app_key | body | string | 아니오 | max 255 | WebSocket 앱 키 |
|
||||
| websocket_host | body | string | 아니오 | max 255 | WebSocket 호스트 주소 |
|
||||
| websocket_port | body | integer | 아니오 | min 1, max 65535 | WebSocket 포트 번호 |
|
||||
| websocket_scheme | body | string | 아니오 | — | WebSocket 스킴 (http/https) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.settings.test_driver_connection_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
폼에 입력한 드라이버 접속 정보(S3·Redis·Memcached·Websocket 등)로 실제 연결을 시도해 결과를 반환합니다. 설정을 저장하기 전에 접속 정보가 유효한지 확인하는 용도입니다. 모든 테스트 통과 시 성공 메시지, 일부 실패 시에도 HTTP 성공 응답으로 항목별 결과(`all_passed=false` 포함)를 함께 반환합니다.
|
||||
|
||||
|
||||
### POST /api/admin/settings/test-mail
|
||||
<!-- @generated:start:api.admin.settings.test-mail -->
|
||||
- **라우트명**: `api.admin.settings.test-mail`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@testMail`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| to_email | body | email | 예 | max 255 | 테스트 수신 주소 |
|
||||
| mailer | body | string | 아니오 | `smtp`, `mailgun`, `ses` | 메일 발송 드라이버 (smtp/mailgun/ses) |
|
||||
| from_address | body | email | 예 | max 255 | 발신자 주소 |
|
||||
| from_name | body | string | 예 | max 255 | 발신자 이름 |
|
||||
| host | body | string | 예 | max 255 | 호스트 주소 |
|
||||
| port | body | integer | 예 | min 1, max 65535 | 포트 번호 |
|
||||
| username | body | string | 아니오 | max 255 | 사용자명 (로그인/인증 아이디) |
|
||||
| password | body | string | 아니오 | max 255 | 비밀번호 |
|
||||
| encryption | body | string | 아니오 | `tls`, `ssl`, `null` | 전송 암호화 방식 (tls/ssl) |
|
||||
| mailgun_domain | body | string | 아니오 | max 255 | Mailgun 도메인 |
|
||||
| mailgun_secret | body | string | 아니오 | max 255 | Mailgun 시크릿 키 |
|
||||
| mailgun_endpoint | body | string | 아니오 | max 255 | Mailgun 엔드포인트 |
|
||||
| ses_key | body | string | 아니오 | max 255 | SES 액세스 키 |
|
||||
| ses_secret | body | string | 아니오 | max 255 | SES 시크릿 키 |
|
||||
| ses_region | body | string | 아니오 | max 255 | SES 리전 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.settings.test_mail_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
폼에 입력한 메일 설정으로 지정한 주소에 테스트 메일을 발송합니다. 요청에서 전달한 값(호스트·포트·인증 정보 등)을 저장된 메일 설정 위에 임시로 덮어써 그 값으로만 발송을 시도하므로, 설정을 저장하기 전에 실제 발송 가능 여부를 검증할 수 있습니다. 성공 시 발송한 제목/본문을 응답에 포함하고, 실패 시 오류 사유와 함께 500 을 반환합니다.
|
||||
|
||||
|
||||
### GET /api/admin/settings/{key}
|
||||
<!-- @generated:start:api.admin.settings.show -->
|
||||
- **라우트명**: `api.admin.settings.show`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| key | path | string | 예 | — | 대상 설정/항목의 키 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
단일 설정 키의 값을 조회합니다. 응답의 `data.key` 는 요청한 키, `data.value` 는 해당 설정 값입니다. 통합 조회(`GET /api/admin/settings`)와 달리 특정 키 하나만 필요할 때 사용합니다.
|
||||
|
||||
|
||||
### PUT /api/admin/settings/{key}
|
||||
<!-- @generated:start:api.admin.settings.update -->
|
||||
- **라우트명**: `api.admin.settings.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\SettingsController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| key | path | string | 예 | — | 대상 설정/항목의 키 |
|
||||
| value | body | string | 예 | max 1000 | 값 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.settings.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
단일 설정 키의 값을 업데이트합니다. 경로의 `key` 로 대상 설정을, 본문의 `value` 로 새 값을 지정합니다. 탭 단위 일괄 저장(`POST /api/admin/settings`)과 달리 개별 키 하나만 변경할 때 사용합니다. 검증 실패 시 422, 그 외 오류 시 500 을 반환합니다.
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,607 @@
|
||||
# Users API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Users 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/admin/users
|
||||
<!-- @generated:start:api.admin.users.index -->
|
||||
- **라우트명**: `api.admin.users.index`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\UserController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.users.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| filters | query | array | 아니오 | max 10 | 추가 필터 조건 맵 (필드별 조건) |
|
||||
| start_date | query | date | 아니오 | — | 조회 기간 시작일 (이 날짜 이후 데이터) |
|
||||
| end_date | query | date | 아니오 | — | 조회 기간 종료일 (이 날짜 이전 데이터) |
|
||||
| date_filter | query | string | 아니오 | `all`, `week`, `month`, `custom` | 가입 기간 프리셋 (all: 전체, week: 최근 1주, month: 최근 1개월, custom: start_date/end_date 로 직접 지정) |
|
||||
| sort_by | query | string | 아니오 | `created_at`, `name`, `email`, `last_login_at` | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.user.list_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `156` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| uuid | string | `a231747f-e82e-4cf2-9ae1-a261849dce40` | 외부 노출용 UUID (URL/API 식별자, 내부 id 비노출) |
|
||||
| name | string | `API 문서 샘플 사용자` | 사용자 이름 |
|
||||
| nickname | string | `gunwoo.oh` | 닉네임 |
|
||||
| email | string | `apidoc-sample-user@example.com` | 이메일 주소 |
|
||||
| language | string | `ko` | 사용자 언어 설정 (ko: 한국어, en: 영어) |
|
||||
| language_label | string | `한국어` | 언어 코드의 현지화 라벨 (user.language.{code} 번역) |
|
||||
| country | string | `KR` | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| country_flag | string | `🇰🇷` | 국가 코드의 국기 이모지 (country 값에서 파생) |
|
||||
| country_name | string | `한국` | 국가 코드의 현지화 국가명 (country 값에서 파생) |
|
||||
| status | string | `active` | 계정 상태 (active: 활성, inactive: 비활성, blocked: 차단, withdrawn: 탈퇴) |
|
||||
| status_label | string | `활성` | 상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
|
||||
| status_variant | string | `success` | 상태 표시 색상/스타일 변형 키 (상태 Enum variant() 산물 — UI 배지용) |
|
||||
| mobile | string | `010-9070-5662` | 휴대폰 번호 |
|
||||
| roles | array | `[{"id":1,"identifier":"admin","name":"관리자"}]` | 사용자에게 부여된 역할 목록 (원소: id/identifier/name — 역할 관계 파생) |
|
||||
| email_verified_at | string | `2026-07-06 19:15:16` | email verified 일시 |
|
||||
| last_login_at | string | `2026-07-05 19:15:16` | last login 일시 |
|
||||
| created_at | string | `2026-07-06` | 생성 일시 |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":true,"can_create":true,"can_update":true,"can…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
관리자 사용자 관리 화면(`admin_user_list.json`)의 목록을 제공합니다. `filters` 로 이름/이메일 다중 검색(operator: like, eq, starts_with, ends_with), `date_filter`(all/week/month/custom)와 `start_date`/`end_date` 로 가입 기간 필터, `sort_by`/`sort_order` 로 정렬한다. 응답은 `data.data[]`(항목별 순번 `number` + 요약 필드)와 `data.pagination`(페이지 정보)에 더해 `data.statistics`(통계)와 `data.abilities`(컬렉션 레벨 권한)를 함께 반환한다. 기본값은 `per_page=15`, `page=1`, `sort_by=created_at`, `sort_order=desc`, `date_filter=all` 이다.
|
||||
|
||||
|
||||
### POST /api/admin/users
|
||||
<!-- @generated:start:api.admin.users.store -->
|
||||
- **라우트명**: `api.admin.users.store`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\UserController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.users.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | string | 예 | max 255 | 대상의 이름/명칭 |
|
||||
| nickname | body | string | 아니오 | max 50 | 닉네임 |
|
||||
| email | body | email | 예 | max 255 | 이메일 주소 |
|
||||
| password | body | string | 예 | — | 비밀번호 |
|
||||
| language | body | string | 아니오 | `ko`, `en`, `fr`, `ja` | 언어 코드 |
|
||||
| country | body | string | 아니오 | — | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| timezone | body | string | 아니오 | — | 타임존 식별자 |
|
||||
| status | body | string | 아니오 | `active`, `inactive`, `blocked`, `withdrawn` | 계정 상태 (미지정 시 active) |
|
||||
| homepage | body | string | 아니오 | max 255 | 홈페이지 URL |
|
||||
| mobile | body | string | 아니오 | max 20 | 휴대전화 번호 |
|
||||
| phone | body | string | 아니오 | max 20 | 전화번호 |
|
||||
| zipcode | body | string | 아니오 | max 10 | 우편번호 |
|
||||
| address | body | string | 아니오 | max 255 | 기본 주소 |
|
||||
| address_detail | body | string | 아니오 | max 255 | 상세 주소 |
|
||||
| signature | body | string | 아니오 | max 1000 | 서명 |
|
||||
| bio | body | string | 아니오 | max 5000 | 자기소개 |
|
||||
| admin_memo | body | string | 아니오 | max 5000 | 관리자 전용 메모 (해당 사용자에 대한 내부 기록, 사용자에게 노출 안 됨) |
|
||||
| roles | body | array | 아니오 | min 1 | 부여할 역할 객체 배열 `[{id}]` (role_ids 와 병용 시 role_ids 우선) |
|
||||
| role_ids | body | array | 아니오 | min 1 | role 식별자 배열 |
|
||||
| notify_post_complete | body | boolean | 아니오 | — | 게시글 작성 완료 알림 수신 여부 (게시판 모듈 알림 설정) |
|
||||
| notify_post_reply | body | boolean | 아니오 | — | 내 게시글에 답글이 달릴 때 알림 수신 여부 |
|
||||
| notify_comment | body | boolean | 아니오 | — | 내 게시글에 댓글이 달릴 때 알림 수신 여부 |
|
||||
| notify_reply_comment | body | boolean | 아니오 | — | 내 댓글에 대댓글이 달릴 때 알림 수신 여부 |
|
||||
| email_subscription | body | boolean | 아니오 | — | 광고성 이메일 수신 동의 여부 (marketing 플러그인 채널 동의, marketing_consents 테이블에 저장) |
|
||||
| marketing_consent | body | boolean | 아니오 | — | 마케팅 정보 수신 전체 동의 마스터 키 (marketing 플러그인이 검증 규칙 주입, 상세는 user-consent-injection.md) |
|
||||
| third_party_consent | body | boolean | 아니오 | — | 제3자 정보 제공 동의 여부 (marketing 플러그인 법적 동의 항목) |
|
||||
| info_disclosure | body | boolean | 아니오 | — | 개인정보 이용 안내 동의 여부 (marketing 플러그인 법적 동의 항목) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.user.create_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
관리자가 새 사용자를 생성합니다. `name`, `email`, `password`(8자 이상, `password_confirmation` 확인 필수), 그리고 역할이 필수이다 — 역할은 `roles`(객체 배열 `[{id}]`) 또는 `role_ids`(id 배열) 중 하나로 지정하며 둘 다 보내면 `role_ids` 가 우선한다. `language`(미지정 시 `ko`), `status`(미지정 시 `active`), 연락처/주소/자기소개 등은 선택 항목이다. 성공 시 201 과 함께 생성된 사용자를 `UserResource` 형태로 반환한다. `notify_*`/`marketing_consent`/`third_party_consent`/`info_disclosure`/`email_subscription` 파라미터는 확장(sirsoft-marketing)이 검증 규칙을 주입한 필드로, 상세는 해당 확장 문서를 참조한다.
|
||||
|
||||
|
||||
### PATCH /api/admin/users/bulk-status
|
||||
<!-- @generated:start:api.admin.users.bulk-status -->
|
||||
- **라우트명**: `api.admin.users.bulk-status`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\UserController@bulkUpdateStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.users.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
| status | body | string | 예 | — | 일괄 적용할 계정 상태 (UserStatus Enum 값: active/inactive/blocked/withdrawn/pending_verification) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.user.bulk_update_status_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
여러 사용자의 계정 상태를 한 번에 변경합니다. `ids` 는 대상 사용자 UUID 배열이며, `status` 는 `active`/`inactive`/`blocked`/`withdrawn`/`pending_verification`(UserStatus Enum 값) 중 하나이다. `ExcludeCurrentUser` 규칙으로 요청자 본인은 대상에서 제외된다. 목록 화면의 다중 선택 후 일괄 상태 변경에 사용한다.
|
||||
|
||||
|
||||
### POST /api/admin/users/check-email
|
||||
<!-- @generated:start:api.admin.users.check-email -->
|
||||
- **라우트명**: `api.admin.users.check-email`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\UserController@checkEmail`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.users.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| email | body | email | 예 | max 255 | 이메일 주소 |
|
||||
| exclude_user_id | body | uuid | 아니오 | — | exclude user 식별자 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.user.check_email_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
이메일 주소의 사용 가능 여부(중복 아님)를 확인합니다. `email` 은 필수, `exclude_user_id`(UUID)를 주면 해당 사용자를 중복 검사에서 제외한다 — 사용자 수정 화면에서 자기 자신의 이메일을 유지할 때 사용한다. 응답 `data.available` 이 true 면 사용 가능, false 면 이미 사용 중이다. 사용자 생성/수정 폼의 이메일 실시간 중복 확인에 쓰인다.
|
||||
|
||||
|
||||
### PATCH /api/admin/users/me/language
|
||||
<!-- @generated:start:api.admin.users.me.language -->
|
||||
- **라우트명**: `api.admin.users.me.language`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\UserController@updateMyLanguage`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| language | body | string | 예 | `ko`, `en`, `fr`, `ja` | 언어 코드 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.user.update_language_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 로그인한 사용자 본인의 언어 설정을 변경합니다. 별도 권한 없이 `auth:sanctum` 인증만 요구하며(다른 사용자를 대상으로 하지 않음), `language` 는 `config('app.supported_locales')`(예: ko, en, fr, ja) 중 하나여야 한다. 성공 시 갱신된 사용자를 `UserResource` 로 반환하며, 관리자 UI 의 언어 전환에 사용한다.
|
||||
|
||||
|
||||
### GET /api/admin/users/recent
|
||||
<!-- @generated:start:api.admin.users.recent -->
|
||||
- **라우트명**: `api.admin.users.recent`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\UserController@recent`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.users.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a231747f-e82e-4cf2-9ae1-a261849dce40` | 외부 노출용 UUID (URL/API 식별자, 내부 id 비노출) |
|
||||
| name | string | `API 문서 샘플 사용자` | 사용자 이름 |
|
||||
| nickname | string | `gunwoo.oh` | 닉네임 |
|
||||
| email | string | `apidoc-sample-user@example.com` | 이메일 주소 |
|
||||
| avatar | null | `null` | 프로필 아바타 이미지 URL (미설정 시 null) |
|
||||
| language | string | `ko` | 사용자 언어 설정 (ko: 한국어, en: 영어) |
|
||||
| language_label | string | `한국어` | 언어 코드의 현지화 라벨 (user.language.{code} 번역) |
|
||||
| country | string | `KR` | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| status | string | `active` | 계정 상태 (active: 활성, inactive: 비활성, blocked: 차단, withdrawn: 탈퇴) |
|
||||
| status_label | string | `활성` | 상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
|
||||
| status_variant | string | `success` | 상태 표시 색상/스타일 변형 키 (상태 Enum variant() 산물 — UI 배지용) |
|
||||
| is_admin | boolean | `true` | 관리자 역할 보유 여부 (User::isAdmin() — 역할 관계 기반 파생) |
|
||||
| homepage | string | `https://example.com` | 홈페이지 URL |
|
||||
| mobile | string | `010-9070-5662` | 휴대폰 번호 |
|
||||
| phone | string | `02-805-4759` | 전화번호 |
|
||||
| zipcode | string | `93153` | 우편번호 |
|
||||
| address | string | `대구광역시 북구 백제고분로 720` | 기본 주소 |
|
||||
| address_detail | string | `40동 835호` | 상세 주소 |
|
||||
| signature | string | `Ipsam rem amet expedita est.` | 서명 |
|
||||
| bio | string | `Tenetur omnis et amet omnis veniam to…` | 자기소개 |
|
||||
| last_login_at | string | `2026-07-05 19:15:16` | last login 일시 |
|
||||
| email_verified_at | string | `2026-07-06 19:15:16` | email verified 일시 |
|
||||
| timezone | string | `Asia/Seoul` | 사용자 시간대 (예: Asia/Seoul, UTC) |
|
||||
| created_at | string | `2026-07-06 19:15:16` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-06 19:15:16` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":true,"can_create":true,"can_update":true,"can…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
최근 가입한 사용자 10명을 최신순으로 반환합니다. 파라미터는 없으며, `UserResource` 전체 필드(관계형 데이터는 미로드)를 담은 컬렉션을 반환한다. 관리자 대시보드의 최근 가입자 위젯이 소비한다.
|
||||
|
||||
|
||||
### GET /api/admin/users/search
|
||||
<!-- @generated:start:api.admin.users.search -->
|
||||
- **라우트명**: `api.admin.users.search`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\UserController@search`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.users.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| keyword | query | string | 아니오 | max 255 | 검색 키워드 (부분 일치) |
|
||||
| uuid | query | uuid | 아니오 | — | 특정 사용자 UUID 로 단건 조회 (지정 시 keyword 무시하고 해당 UUID 사용자만 반환) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.user.search_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
사용자를 검색해 `UserResource` 컬렉션으로 반환합니다. `uuid` 를 주면 해당 UUID 의 단일 사용자(존재 시 1건, 없으면 빈 배열)를, 없으면 `keyword` 로 이름·닉네임·이메일을 부분 일치 검색한다(`keyword` 와 `uuid` 중 하나는 필수). 알림 템플릿 수신자 지정이나 활동 로그 필터의 사용자 선택 UI 에서 사용한다.
|
||||
|
||||
|
||||
### GET /api/admin/users/statistics
|
||||
<!-- @generated:start:api.admin.users.statistics -->
|
||||
- **라우트명**: `api.admin.users.statistics`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\UserController@statistics`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.users.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| total_users | integer | `156` | 전체 사용자 수 (통계 객체는 count/추이 포함) |
|
||||
| users_this_week | integer | `1` | 이번 주 신규 가입자 수 |
|
||||
| users_this_month | integer | `155` | 이번 달 신규 가입자 수 |
|
||||
| users_today | integer | `0` | 오늘 신규 가입자 수 |
|
||||
| active_users_this_week | integer | `2` | 이번 주 활동(로그인) 사용자 수 |
|
||||
| language_distribution | object | `{"ko":92,"en":64}` | 언어별 사용자 분포 (언어 코드 => 사용자 수) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자 대시보드의 사용자 통계 위젯이 소비하는 집계 API. 캐시 없이 실시간 집계.
|
||||
|
||||
|
||||
### DELETE /api/admin/users/{user}
|
||||
<!-- @generated:start:api.admin.users.destroy -->
|
||||
- **라우트명**: `api.admin.users.destroy`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\UserController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.users.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| user | path | string | 예 | — | 대상 user의 식별자 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.user.delete_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.delete`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
지정한 사용자(경로 파라미터는 UUID 로 바인딩)를 삭제합니다. 슈퍼관리자 계정은 삭제할 수 없으며 시도 시 422(`exceptions.cannot_delete_super_admin`)를 반환한다. 그 외 삭제 실패 시에는 실패 상세 사유가 담긴 422 를, 나머지 오류는 500 을 반환한다. 삭제는 Service 계층에서 관련 데이터 정리와 훅을 거쳐 처리된다.
|
||||
|
||||
|
||||
### GET /api/admin/users/{user}
|
||||
<!-- @generated:start:api.admin.users.show -->
|
||||
- **라우트명**: `api.admin.users.show`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\UserController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.users.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| user | path | string | 예 | — | 대상 user의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a231747f-e82e-4cf2-9ae1-a261849dce40` | 외부 노출용 UUID (URL/API 식별자, 내부 id 비노출) |
|
||||
| name | string | `API 문서 샘플 사용자` | 사용자 이름 |
|
||||
| nickname | string | `gunwoo.oh` | 닉네임 |
|
||||
| email | string | `apidoc-sample-user@example.com` | 이메일 주소 |
|
||||
| avatar | null | `null` | 프로필 아바타 이미지 URL (미설정 시 null) |
|
||||
| language | string | `ko` | 사용자 언어 설정 (ko: 한국어, en: 영어) |
|
||||
| language_label | string | `한국어` | 언어 코드의 현지화 라벨 (user.language.{code} 번역) |
|
||||
| country | string | `KR` | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| status | string | `active` | 계정 상태 (active: 활성, inactive: 비활성, blocked: 차단, withdrawn: 탈퇴) |
|
||||
| status_label | string | `활성` | 상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
|
||||
| status_variant | string | `success` | 상태 표시 색상/스타일 변형 키 (상태 Enum variant() 산물 — UI 배지용) |
|
||||
| is_admin | boolean | `true` | 관리자 역할 보유 여부 (User::isAdmin() — 역할 관계 기반 파생) |
|
||||
| homepage | string | `https://example.com` | 홈페이지 URL |
|
||||
| mobile | string | `010-9070-5662` | 휴대폰 번호 |
|
||||
| phone | string | `02-805-4759` | 전화번호 |
|
||||
| zipcode | string | `93153` | 우편번호 |
|
||||
| address | string | `대구광역시 북구 백제고분로 720` | 기본 주소 |
|
||||
| address_detail | string | `40동 835호` | 상세 주소 |
|
||||
| signature | string | `Ipsam rem amet expedita est.` | 서명 |
|
||||
| bio | string | `Tenetur omnis et amet omnis veniam to…` | 자기소개 |
|
||||
| last_login_at | string | `2026-07-05 19:15:16` | last login 일시 |
|
||||
| email_verified_at | string | `2026-07-06 19:15:16` | email verified 일시 |
|
||||
| timezone | string | `Asia/Seoul` | 사용자 시간대 (예: Asia/Seoul, UTC) |
|
||||
| modules_count | integer | `0` | modules 개수 (집계) |
|
||||
| plugins_count | integer | `0` | plugins 개수 (집계) |
|
||||
| menus_count | integer | `2` | menus 개수 (집계) |
|
||||
| modules | array | `[]` | 이 사용자가 접근 권한을 가진 모듈 목록 (역할 경유 권한 관계 파생) |
|
||||
| plugins | array | `[]` | 이 사용자가 접근 권한을 가진 플러그인 목록 (역할 경유 권한 관계 파생) |
|
||||
| menus | array | `[{"id":33,"title":"API 문서 샘플 메뉴","url":"\/admin\/apidoc-s…` | 이 사용자가 접근 가능한 관리자 메뉴 목록 (원소: id/title/url — 역할 경유 메뉴 관계 파생) |
|
||||
| roles | array | `[{"id":1,"identifier":"admin","name":"관리자"}]` | 사용자에게 부여된 역할 목록 (원소: id/identifier/name — 역할 관계 파생) |
|
||||
| permissions | array | `[]` | 연결된 권한 목록 (id/identifier/name — 역할 경유 권한 관계 파생) |
|
||||
| consents | array | `[]` | 사용자가 동의한 약관 동의 레코드 목록 (약관 관계 파생) |
|
||||
| terms_consent | null | `null` | 이용약관 동의 정보 (동의 시각 등, 미동의 시 null) |
|
||||
| privacy_consent | null | `null` | 개인정보 처리방침 동의 정보 (동의 시각 등, 미동의 시 null) |
|
||||
| created_at | string | `2026-07-06 19:15:16` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-06 19:15:16` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":true,"can_create":true,"can_update":true,"can…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
| admin_memo | string | `Perferendis ut suscipit quia unde sed.` | 관리자 메모 |
|
||||
| ip_address | string | `77.105.222.87` | 마지막 접속 IP 주소 |
|
||||
| withdrawn_at | null | `null` | withdrawn 일시 |
|
||||
| blocked_at | null | `null` | blocked 일시 |
|
||||
| notify_post_complete | boolean | `false` | 게시글 작성 완료 알림 수신 여부 (게시판 모듈 알림 설정) |
|
||||
| notify_post_reply | boolean | `false` | 내 게시글 답글 알림 수신 여부 |
|
||||
| notify_comment | boolean | `false` | 내 게시글 댓글 알림 수신 여부 |
|
||||
| notify_reply_comment | boolean | `false` | 내 댓글 대댓글 알림 수신 여부 |
|
||||
| email_subscription | boolean | `false` | 광고성 이메일 수신 동의 여부 (marketing 플러그인 채널 동의) |
|
||||
| email_subscription_at | null | `null` | email subscription 일시 |
|
||||
| marketing_consent | boolean | `false` | 마케팅 정보 수신 전체 동의 여부 (marketing 플러그인 마스터 키, 미동의 시 false) |
|
||||
| marketing_consent_at | null | `null` | marketing consent 일시 |
|
||||
| third_party_consent | boolean | `false` | 제3자 정보 제공 동의 여부 (marketing 플러그인 법적 동의 항목) |
|
||||
| third_party_consent_at | null | `null` | third party consent 일시 |
|
||||
| info_disclosure | boolean | `false` | 개인정보 이용 안내 동의 여부 (marketing 플러그인 법적 동의 항목) |
|
||||
| info_disclosure_at | null | `null` | info disclosure 일시 |
|
||||
| marketing_consent_enabled | boolean | `true` | 마케팅 동의 UI 노출 여부 (marketing 플러그인 활성화 플래그, 기본 true) |
|
||||
| marketing_consent_terms_slug | string | `marketing-terms` | 마케팅 약관 slug (연결된 약관 페이지 식별자, 미설정 시 null) |
|
||||
| marketing_consent_terms_slug_set | boolean | `true` | 마케팅 약관 연결 존재 여부 (프론트 약관 링크 표시 판정용) |
|
||||
| third_party_consent_enabled | boolean | `true` | 제3자 제공 동의 항목 노출 여부 (marketing 플러그인 활성화 플래그) |
|
||||
| third_party_consent_terms_slug | null | `null` | 제3자 제공 약관 slug (미설정 시 null) |
|
||||
| third_party_consent_terms_slug_set | boolean | `false` | 제3자 제공 약관 연결 존재 여부 |
|
||||
| info_disclosure_enabled | boolean | `true` | 정보 이용 안내 동의 항목 노출 여부 (marketing 플러그인 활성화 플래그) |
|
||||
| info_disclosure_terms_slug | null | `null` | 정보 이용 안내 약관 slug (미설정 시 null) |
|
||||
| info_disclosure_terms_slug_set | boolean | `false` | 정보 이용 안내 약관 연결 존재 여부 |
|
||||
| email_subscription_enabled | boolean | `true` | 이메일 수신 채널 노출 여부 (marketing 플러그인 활성화 플래그) |
|
||||
| email_subscription_terms_slug | null | `null` | 이메일 수신 약관 slug (미설정 시 null) |
|
||||
| email_subscription_terms_slug_set | boolean | `false` | 이메일 수신 약관 연결 존재 여부 |
|
||||
| channels | array | `[{"key":"email_subscription","label":"광고성 이메일 수신","enable…` | 관리자 정의 전체 마케팅 채널 목록 (원소: key/label/enabled/terms_slug — marketing 플러그인 주입, iteration 렌더링용) |
|
||||
| consent_histories | array | `[]` | 사용자 동의 변경 이력 (원소: channel_key/action/source/created_at — marketing 플러그인 주입) |
|
||||
| ecommerce_mileage | object | `{"enabled":false}` | 이커머스 마일리지 정보 (enabled 및 잔액 등 — sirsoft-ecommerce 모듈 주입) |
|
||||
| ecommerce_preferred_currency | null | `null` | 선호 결제 통화 (sirsoft-ecommerce 모듈 주입, 미설정 시 null) |
|
||||
| ecommerce_preferred_shipping_country | null | `null` | 선호 배송 국가 코드 (sirsoft-ecommerce 모듈 주입, 미설정 시 null) |
|
||||
| ecommerce_preferred_shipping_country_name | null | `null` | 선호 배송 국가명 (배송 국가 코드에서 파생, sirsoft-ecommerce 모듈 주입) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
특정 사용자의 상세 정보를 조회합니다(경로 파라미터는 UUID 로 바인딩). `withAdminInfo()` 를 통해 기본 필드에 더해 관리자 전용 필드(admin_memo, ip_address, withdrawn_at, blocked_at)와 관계형 데이터(modules, plugins, menus, roles, permissions, consents 및 개수 필드)를 함께 반환한다. `core.user.filter_resource_data` 필터로 확장이 자신의 필드(sirsoft-marketing 의 알림/동의 설정, sirsoft-ecommerce 의 마일리지/선호 통화·배송국 등)를 병합한다. 관리자 사용자 상세/수정 화면(`admin_user_detail.json`/`admin_user_form.json`)이 소비한다.
|
||||
|
||||
|
||||
### PUT /api/admin/users/{user}
|
||||
<!-- @generated:start:api.admin.users.update -->
|
||||
- **라우트명**: `api.admin.users.update`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Admin\UserController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:core.users.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| user | path | string | 예 | — | 대상 user의 식별자 |
|
||||
| name | body | string | 예 | max 255 | 대상의 이름/명칭 |
|
||||
| nickname | body | string | 아니오 | max 50 | 닉네임 |
|
||||
| email | body | email | 예 | max 255 | 이메일 주소 |
|
||||
| password | body | string | 아니오 | — | 비밀번호 |
|
||||
| language | body | string | 아니오 | `ko`, `en`, `fr`, `ja` | 언어 코드 |
|
||||
| country | body | string | 아니오 | — | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| timezone | body | string | 아니오 | — | 타임존 식별자 |
|
||||
| status | body | string | 아니오 | `active`, `inactive`, `blocked`, `withdrawn` | 계정 상태 (미지정 시 active) |
|
||||
| homepage | body | string | 아니오 | max 255 | 홈페이지 URL |
|
||||
| mobile | body | string | 아니오 | max 20 | 휴대전화 번호 |
|
||||
| phone | body | string | 아니오 | max 20 | 전화번호 |
|
||||
| zipcode | body | string | 아니오 | max 10 | 우편번호 |
|
||||
| address | body | string | 아니오 | max 255 | 기본 주소 |
|
||||
| address_detail | body | string | 아니오 | max 255 | 상세 주소 |
|
||||
| signature | body | string | 아니오 | max 1000 | 서명 |
|
||||
| bio | body | string | 아니오 | max 5000 | 자기소개 |
|
||||
| admin_memo | body | string | 아니오 | max 5000 | 관리자 전용 메모 (해당 사용자에 대한 내부 기록, 사용자에게 노출 안 됨) |
|
||||
| roles | body | array | 아니오 | min 1 | 부여할 역할 객체 배열 `[{id}]` (role_ids 와 병용 시 role_ids 우선) |
|
||||
| role_ids | body | array | 아니오 | min 1 | role 식별자 배열 |
|
||||
| notify_post_complete | body | boolean | 아니오 | — | 게시글 작성 완료 알림 수신 여부 (게시판 모듈 알림 설정) |
|
||||
| notify_post_reply | body | boolean | 아니오 | — | 내 게시글에 답글이 달릴 때 알림 수신 여부 |
|
||||
| notify_comment | body | boolean | 아니오 | — | 내 게시글에 댓글이 달릴 때 알림 수신 여부 |
|
||||
| notify_reply_comment | body | boolean | 아니오 | — | 내 댓글에 대댓글이 달릴 때 알림 수신 여부 |
|
||||
| email_subscription | body | boolean | 아니오 | — | 광고성 이메일 수신 동의 여부 (marketing 플러그인 채널 동의, marketing_consents 테이블에 저장) |
|
||||
| marketing_consent | body | boolean | 아니오 | — | 마케팅 정보 수신 전체 동의 마스터 키 (marketing 플러그인이 검증 규칙 주입, 상세는 user-consent-injection.md) |
|
||||
| third_party_consent | body | boolean | 아니오 | — | 제3자 정보 제공 동의 여부 (marketing 플러그인 법적 동의 항목) |
|
||||
| info_disclosure | body | boolean | 아니오 | — | 개인정보 이용 안내 동의 여부 (marketing 플러그인 법적 동의 항목) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.user.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`core.users.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
기존 사용자 정보를 수정합니다(경로 파라미터는 UUID 로 바인딩). `name`, `email` 은 필수이며 `email` 은 해당 사용자를 제외한 고유성 검사를 거친다. `password` 는 선택이며 값을 주면 8자 이상·`password_confirmation` 확인을 요구한다(미전송 시 기존 비밀번호 유지). 역할은 `roles` 또는 `role_ids` 중 하나로 지정하고 둘 다 오면 `role_ids` 가 우선한다. 성공 시 갱신된 사용자를 `UserResource` 로 반환한다. `notify_*`/`marketing_consent`/`third_party_consent`/`info_disclosure`/`email_subscription` 파라미터는 확장(sirsoft-marketing)이 검증 규칙을 주입한 필드로, 상세는 해당 확장 문서를 참조한다.
|
||||
|
||||
|
||||
### GET /api/users/{user}/profile
|
||||
<!-- @generated:start:api.public.users.profile -->
|
||||
- **라우트명**: `api.public.users.profile`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Public\PublicProfileController@show`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| user | path | string | 예 | — | 대상 user의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| uuid | string | `a231747f-e82e-4cf2-9ae1-a261849dce40` | 외부 노출용 UUID (URL/API 식별자, 내부 id 비노출) |
|
||||
| name | string | `API 문서 샘플 사용자` | 사용자 이름 |
|
||||
| status | string | `active` | 계정 상태 (active: 활성, inactive: 비활성, blocked: 차단, withdrawn: 탈퇴) |
|
||||
| status_label | string | `활성` | 상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
|
||||
| avatar | null | `null` | 프로필 아바타 이미지 URL (미설정 시 null) |
|
||||
| bio | string | `Tenetur omnis et amet omnis veniam to…` | 자기소개 |
|
||||
| created_at | string | `2026-07-06` | 생성 일시 |
|
||||
| is_withdrawn | boolean | `false` | withdrawn 여부 |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
타인의 공개 프로필을 인증 없이 조회합니다(경로 파라미터는 UUID 로 바인딩, `users/show.json` 이 소비). 사용자 상태에 따라 노출 필드가 달라진다 — active 는 name/avatar/bio/created_at 전체, inactive 는 bio 를 제외, blocked 는 avatar/bio/created_at 를 모두 제외한다. withdrawn 사용자는 이름을 익명 표기로 대체하고 `is_withdrawn=true` 로 반환하며, 미존재 사용자는 404(`user.not_found`)를 반환한다. 게시글 통계는 게시판 모듈 API 로 별도 조회한다.
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
# Verify Password API 레퍼런스
|
||||
|
||||
> **소유**: 코어 · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Verify Password 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### POST /api/me/verify-password
|
||||
<!-- @generated:start:api.me.verify-password -->
|
||||
- **라우트명**: `api.me.verify-password`
|
||||
- **컨트롤러**: `App\Http\Controllers\Api\Auth\ProfileController@verifyPassword`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| password | body | string | 예 | — | 비밀번호 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`core.auth.verify_password_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
현재 로그인한 사용자의 비밀번호를 재확인한다. 민감한 작업 직전 본인 확인 게이트로 사용되며, 프론트의 `_password_verify_section.json` 이 호출한다. 요청의 `password` 를 `Hash::check` 로 저장된 해시와 대조해, 일치하면 성공 응답(`user.password_verified`)을, 틀리면 401(`user.password_incorrect`)을 반환한다. 비밀번호를 변경하지 않고 신원만 확인하므로 사용자 데이터는 바뀌지 않는다.
|
||||
|
||||
|
||||
+23
-16
@@ -68,7 +68,8 @@
|
||||
| 코어 | `/admin/[기능명]` | `/admin/users` |
|
||||
| 모듈 | `/admin/[vendor-module]/[기능명]` | `/admin/sirsoft-ecommerce/products` |
|
||||
| 플러그인 | `/admin/[vendor-plugin]/[기능명]` | `/admin/sirsoft-payment/settings` |
|
||||
| 공개 API | `/api/[vendor-module]/[기능명]` | `/api/sirsoft-ecommerce/products` |
|
||||
| 모듈 공개 API | `/api/modules/[vendor-module]/[기능명]` | `/api/modules/sirsoft-ecommerce/products` |
|
||||
| 플러그인 공개 API | `/api/plugins/[vendor-plugin]/[기능명]` | `/api/plugins/sirsoft-gdpr/consent` |
|
||||
|
||||
### 리소스 URL 규칙
|
||||
|
||||
@@ -149,32 +150,35 @@ sirsoft-ecommerce.products.delete
|
||||
### 모듈 라우트 파일
|
||||
|
||||
```php
|
||||
// modules/sirsoft-ecommerce/src/routes/api.php
|
||||
// modules/_bundled/sirsoft-ecommerce/src/routes/api.php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Modules\Sirsoft\Ecommerce\Controllers\Api\Admin\ProductController;
|
||||
|
||||
Route::prefix('admin/sirsoft-ecommerce')->middleware(['auth:sanctum', 'admin'])->group(function () {
|
||||
// 상품 관리 (권한 체크 포함)
|
||||
// ModuleRouteServiceProvider 가 URL prefix('api/modules/sirsoft-ecommerce')와
|
||||
// name prefix('api.modules.sirsoft-ecommerce.')를 자동 적용한다.
|
||||
// 라우트 파일 내부 group 에는 관리자 세그먼트('admin')만 두고, 접두는 중복 입력하지 않는다.
|
||||
Route::prefix('admin')->middleware(['auth:sanctum', 'admin'])->group(function () {
|
||||
// 상품 관리 (권한 체크 포함) → 최종 URL: /api/modules/sirsoft-ecommerce/admin/products
|
||||
Route::get('/products', [ProductController::class, 'index'])
|
||||
->middleware('permission:sirsoft-ecommerce.products.view')
|
||||
->name('api.sirsoft-ecommerce.products.index');
|
||||
->name('products.index'); // 최종 name: api.modules.sirsoft-ecommerce.products.index
|
||||
|
||||
Route::post('/products', [ProductController::class, 'store'])
|
||||
->middleware('permission:sirsoft-ecommerce.products.create')
|
||||
->name('api.sirsoft-ecommerce.products.store');
|
||||
->name('products.store');
|
||||
|
||||
Route::get('/products/{id}', [ProductController::class, 'show'])
|
||||
->middleware('permission:sirsoft-ecommerce.products.view')
|
||||
->name('api.sirsoft-ecommerce.products.show');
|
||||
->name('products.show');
|
||||
|
||||
Route::put('/products/{id}', [ProductController::class, 'update'])
|
||||
->middleware('permission:sirsoft-ecommerce.products.edit')
|
||||
->name('api.sirsoft-ecommerce.products.update');
|
||||
->name('products.update');
|
||||
|
||||
Route::delete('/products/{id}', [ProductController::class, 'destroy'])
|
||||
->middleware('permission:sirsoft-ecommerce.products.delete')
|
||||
->name('api.sirsoft-ecommerce.products.destroy');
|
||||
->name('products.destroy');
|
||||
});
|
||||
```
|
||||
|
||||
@@ -253,17 +257,20 @@ Route::middleware('auth:sanctum')->prefix('user')->group(function () {
|
||||
### 공개 API 라우트
|
||||
|
||||
```php
|
||||
// modules/sirsoft-ecommerce/src/routes/api.php
|
||||
// modules/_bundled/sirsoft-ecommerce/src/routes/api.php
|
||||
|
||||
use Modules\Sirsoft\Ecommerce\Controllers\Api\Public\ProductController;
|
||||
|
||||
Route::prefix('api/sirsoft-ecommerce')->group(function () {
|
||||
// 공개 상품 API (인증 불필요)
|
||||
Route::get('/products', [ProductController::class, 'index'])
|
||||
->name('api.sirsoft-ecommerce.public.products.index');
|
||||
// ModuleRouteServiceProvider 가 URL prefix('api/modules/sirsoft-ecommerce')와
|
||||
// name prefix('api.modules.sirsoft-ecommerce.')를 자동 적용한다.
|
||||
// 라우트 파일에서 prefix/name 접두를 중복 입력하지 않는다.
|
||||
Route::prefix('products')->group(function () {
|
||||
// 공개 상품 API (인증 불필요) → 최종 URL: /api/modules/sirsoft-ecommerce/products
|
||||
Route::get('/', [ProductController::class, 'index'])
|
||||
->name('public.products.index'); // 최종 name: api.modules.sirsoft-ecommerce.public.products.index
|
||||
|
||||
Route::get('/products/{id}', [ProductController::class, 'show'])
|
||||
->name('api.sirsoft-ecommerce.public.products.show');
|
||||
Route::get('/{id}', [ProductController::class, 'show'])
|
||||
->name('public.products.show');
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
# Memos API 레퍼런스
|
||||
|
||||
> **소유**: module `gnuboard7-hello_module` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Memos 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/gnuboard7-hello_module/memos
|
||||
<!-- @generated:start:api.modules.gnuboard7-hello_module.memos.index -->
|
||||
- **라우트명**: `api.modules.gnuboard7-hello_module.memos.index`
|
||||
- **컨트롤러**: `Modules\Gnuboard7\HelloModule\Http\Controllers\Api\MemoController@index`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-404 — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). <!-- TODO: 도메인 특이 에러가 있으면 보강 -->_
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
메모 목록을 페이지네이션으로 조회하는 공개 엔드포인트다. 라우트는 `optional.sanctum` 미들웨어를 쓰므로 **비로그인 사용자도 조회할 수 있다**(생성기 표기 `auth:sanctum` 은 실제와 다르며, 실제로는 토큰이 있으면 인증 컨텍스트를 붙이되 없어도 통과한다). 이 확장은 학습용 샘플로, 공개 읽기 API 의 표준 패턴(`PublicBaseController` + `throttle:600,1`)을 보여준다.
|
||||
|
||||
- **요청 파라미터**: query `per_page`(정수, 기본 10)로 페이지 크기를 조절한다. FormRequest 를 쓰지 않고 컨트롤러가 `$request->query('per_page', 10)` 로 직접 읽는다.
|
||||
- **응답**: `data` 는 `MemoCollection`(`BaseApiCollection`) 산물로, `data.data` 에 `MemoResource` 배열, `data.meta.pagination` 에 페이지 메타(`current_page`/`last_page`/`per_page`/`total`/`from`/`to`/`has_more_pages`)를 담는다. 각 메모 항목 필드는 아래 상세 조회와 동일하다.
|
||||
- **미설치 주의**: 이 문서는 확장이 미설치인 상태에서 라우트 파일 정적 분석으로 생성되어 실측 응답이 없다(`http-404`). 설치 후 `api:docgen --scope=module:gnuboard7-hello_module --seed` 로 실측하면 응답 예시가 채워진다.
|
||||
|
||||
**응답 예시** (정적 — MemoResource 구조 기준)
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"data": [
|
||||
{ "id": 1, "uuid": "…", "title": "샘플 메모", "content": "본문", "created_at": "…", "updated_at": "…", "is_owner": false, "abilities": { "can_create": false, "can_update": false, "can_delete": false } }
|
||||
],
|
||||
"meta": { "pagination": { "current_page": 1, "last_page": 1, "per_page": 10, "total": 1, "from": 1, "to": 1, "has_more_pages": false } }
|
||||
},
|
||||
"message": "메모를 조회했습니다.",
|
||||
"error": null
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### GET /api/modules/gnuboard7-hello_module/memos/{id}
|
||||
<!-- @generated:start:api.modules.gnuboard7-hello_module.memos.show -->
|
||||
- **라우트명**: `api.modules.gnuboard7-hello_module.memos.show`
|
||||
- **컨트롤러**: `Modules\Gnuboard7\HelloModule\Http\Controllers\Api\MemoController@show`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명**
|
||||
|
||||
단일 메모를 조회하는 공개 엔드포인트다. 목록과 마찬가지로 `optional.sanctum` 이라 비로그인 조회가 허용된다(생성기 표기 `auth:sanctum` 은 실제와 다름).
|
||||
|
||||
- **path 파라미터** `{id}`: 메모의 정수 PK. 라우트 제약 `whereNumber('id')` 로 숫자만 매칭된다. 라우트-모델 바인딩 없이 컨트롤러가 `MemoService::getMemo($id)` 로 직접 조회하므로, 존재하지 않으면 `ModelNotFoundException` → `messages.memo.not_found`(404).
|
||||
- **응답**: `data` 는 단건 `MemoResource` 다. 필드는 `id`(integer), `uuid`(string), `title`(string), `content`(string), 타임스탬프(`created_at`/`updated_at`), 그리고 `BaseApiResource` 공통 메타 `is_owner`(boolean) + `abilities`(`can_create`/`can_update`/`can_delete` — 각 권한 보유 여부). 권한 능력은 `gnuboard7-hello_module.memos.{create,update,delete}` 권한 매핑에서 파생된다.
|
||||
- **미설치 주의**: 이 문서는 미설치 상태 정적 분석으로 생성되어 실측 응답이 없다(`unresolved-path-param` — 실측할 실제 메모 레코드가 없음). 설치 후 `--seed` 실측 시 실제 값으로 채워진다.
|
||||
|
||||
**응답 예시** (정적 — MemoResource 구조 기준)
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"id": 1,
|
||||
"uuid": "…",
|
||||
"title": "샘플 메모",
|
||||
"content": "본문",
|
||||
"created_at": "…",
|
||||
"updated_at": "…",
|
||||
"is_owner": false,
|
||||
"abilities": { "can_create": false, "can_update": false, "can_delete": false }
|
||||
},
|
||||
"message": "메모를 조회했습니다.",
|
||||
"error": null
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# Activity Stats API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-board` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Activity Stats 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/me/activity-stats
|
||||
<!-- @generated:start:api.modules.sirsoft-board.me.activity-stats -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.me.activity-stats`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\User\UserActivityController@stats`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| total_posts | integer | `1` | 회원 본인이 작성한 게시글 총수입니다. 비활성 게시판의 글은 제외하며 소프트 삭제된 글도 집계에서 빠집니다. |
|
||||
| total_comments | integer | `0` | 회원 본인이 작성한 게시글들의 댓글 수 합계(SUM of comments_count)입니다. 비활성 게시판 글은 제외됩니다. |
|
||||
| total_views | integer | `42` | 회원 본인이 작성한 게시글들의 누적 조회수 합계(SUM of view_count)입니다. 비활성 게시판 글은 제외됩니다. |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원 본인의 게시판 활동 통계(작성 글 수, 작성 댓글 수, 누적 조회수)를 마이페이지 요약 카드에 표시하기 위해 반환합니다. `auth:sanctum` 인증이 필요한 회원 전용 엔드포인트로, 대상은 항상 인증된 본인(`Auth::id()`)입니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# Board Activities API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-board` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Board Activities 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/me/board-activities
|
||||
<!-- @generated:start:api.modules.sirsoft-board.me.board-activities.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.me.board-activities.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\User\UserActivityController@index`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `237` | 기본 키 (내부 식별자) |
|
||||
| board_slug | string | `apidoc-sample-board` | 게시글이 속한 게시판의 슬러그(URL 식별자)입니다. 게시판 상세 링크 구성에 사용합니다. |
|
||||
| board_name | string | `API 문서 샘플 게시판` | 게시글이 속한 게시판의 표시 이름입니다. 현재 로케일에 맞는 다국어 이름(`getLocalizedName()`)이 적용됩니다. |
|
||||
| activity_type | string | `authored` | 활동 유형입니다. `authored`(본인이 작성한 글) 또는 `commented`(본인이 댓글을 단 글)로, 요청의 `activity_type` 필터(기본 authored)에 대응합니다. |
|
||||
| activity_count | integer | `0` | activity 개수 (집계) |
|
||||
| title | string | `API 문서 샘플 게시글` | 제목 |
|
||||
| is_secret | boolean | `false` | secret 여부 |
|
||||
| status | string | `published` | 게시글 상태입니다. `published`(공개), `blinded`(블라인드 처리), `deleted`(삭제) 등 PostStatus 값이며, UI에서 블라인드/삭제 배지 표시에 사용합니다. |
|
||||
| view_count | integer | `43` | view 개수 (집계) |
|
||||
| comment_count | integer | `0` | comment 개수 (집계) |
|
||||
| created_at | string | `2026-07-07 09:34:50` | 생성 일시 |
|
||||
| created_at_formatted | string | `4시간 전` | `created_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| content_plain | string | `API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.` | 게시글 본문의 순수 텍스트입니다. HTML 모드 글은 태그를 제거한 평문으로 변환되며, 목록 미리보기용으로 사용합니다. |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원 본인의 게시글 활동을 마이페이지에 표시하기 위해 반환합니다. `auth:sanctum` 인증이 필요한 회원 전용 엔드포인트로, 대상 사용자는 항상 인증된 본인(`Auth::id()`)입니다. `board_slug`·`search`·`activity_type`·`sort`(latest/oldest/views) 필터와 `per_page`(기본 20) 페이지네이션을 지원하며, 응답에는 적용된 필터가 `query` 로 함께 담깁니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
# Board Types API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-board` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Board Types 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/board-types
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board-types.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board-types.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\BoardTypeController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.boards.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| slug | string | `basic` | 유형 식별자 (basic, card, gallery 등) |
|
||||
| name | object | `{"ko":"기본형","en":"Basic List","ja":"基本形"}` | 유형명 (다국어: {"ko": "기본형", "en": "Basic List"}) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.boards.create`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 게시판 생성/편집 화면에서 선택할 수 있는 게시판 유형(basic, card, gallery 등) 목록을 반환합니다. `auth:sanctum` 인증과 `sirsoft-board.boards.create` 권한이 필요하며, 게시판 생성 권한을 재사용해 접근을 통제합니다. `name` 은 다국어 객체로 반환되므로 표시 시 현재 로케일 키를 선택해야 합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-board/admin/board-types
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board-types.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board-types.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\BoardTypeController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.boards.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | body | string | 예 | max 50 | URL 친화 식별자 (slug) |
|
||||
| name | body | string | 예 | — | 대상의 이름/명칭 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.boards.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 새 게시판 유형을 생성합니다. `slug` 는 유형을 식별하는 고유 문자열(최대 50자)이고 `name` 은 유형명입니다. `auth:sanctum` 인증과 `sirsoft-board.boards.create` 권한이 필요하며, 성공 시 생성된 유형 리소스와 함께 201 을 반환합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-board/admin/board-types/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board-types.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board-types.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\BoardTypeController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.boards.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.boards.create`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 지정한 `id` 의 게시판 유형을 삭제합니다. `auth:sanctum` 인증과 `sirsoft-board.boards.create` 권한이 필요합니다. 존재하지 않는 id 는 404, 해당 유형을 사용 중인 게시판이 있는 등 삭제할 수 없는 경우 422 를 반환합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-board/admin/board-types/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board-types.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board-types.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\BoardTypeController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.boards.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| name | body | string | 예 | — | 대상의 이름/명칭 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.boards.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 지정한 `id` 의 게시판 유형명을 수정합니다. `slug` 는 변경되지 않으며 `name` 만 갱신합니다. `auth:sanctum` 인증과 `sirsoft-board.boards.create` 권한이 필요하고, 존재하지 않는 id 는 404 를 반환합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,674 @@
|
||||
# Board API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-board` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Board 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-board/admin/board/{slug}/attachments
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.attachments.upload -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.attachments.upload`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\AttachmentController@upload`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.attachments.upload`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| file | body | file | 예 | — | 업로드 파일 |
|
||||
| post_id | body | integer | 아니오 | min 1 | post 식별자 |
|
||||
| collection | body | string | 아니오 | max 100 | 첨부 컬렉션 그룹명 (첨부를 용도별로 묶는 키, 미지정 시 default) |
|
||||
| temp_key | body | string | 아니오 | max 64 | 게시글 작성 전 임시 업로드 세션 키. `post_id`가 없을 때 이 키로 첨부를 임시 보관했다가 게시글 저장 시점에 연결합니다 (쿼리스트링으로 보내면 body로 병합). |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-board.attachment.upload_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.attachments.upload`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 게시글 첨부파일 1건을 업로드합니다. `auth:sanctum` + admin + 게시판별 `attachments.upload` 권한이 필요하며, `AttachmentService::upload()`가 게시판별 동적 첨부 테이블에 저장합니다. `post_id`가 있으면 해당 게시글에 즉시 귀속되고, 없으면 `temp_key`로 임시 업로드되어 게시글 작성/수정 저장 시점에 연결됩니다. 응답은 FileUploader 컴포넌트 호환을 위해 `data.data`로 한 번 더 감싸 파일 메타(hash·url·order 등)를 반환합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/board/{slug}/attachments/download/{hash}
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.attachments.download -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.attachments.download`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\AttachmentController@download`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.attachments.download`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| hash | path | string | 예 | — | 대상 리소스의 해시 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-404 — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.attachments.download`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 첨부파일을 해시로 조회해 다운로드합니다. `auth:sanctum` + admin + 게시판별 `attachments.download` 권한이 필요하며, `AttachmentService::getByHash()`로 대상을 찾은 뒤 `download()`가 파일 스트림 응답을 생성합니다. 해시에 해당하는 첨부가 없거나 실제 파일이 없으면 404를 반환하고, JSON이 아닌 `StreamedResponse`로 파일 본문을 직접 전송합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-board/admin/board/{slug}/attachments/reorder
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.attachments.reorder -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.attachments.reorder`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\AttachmentController@reorder`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.attachments.upload`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| order | body | array | 예 | min 1 | 첨부파일 순서 배열. FileUploader가 보내는 `[{id, order}]` 형태로, 각 원소의 `id`(첨부 ID)와 `order`(0 이상 정수)를 담아 표시 순서를 지정합니다. |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-board.attachment.reorder_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.attachments.upload`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 게시글 첨부파일들의 표시 순서를 일괄 변경합니다. `auth:sanctum` + admin + 게시판별 `attachments.upload` 권한이 필요하며, FileUploader가 보낸 `[{id, order}]` 배열을 `[ID => order]` 매핑으로 변환해 `AttachmentService::reorder()`가 게시판별 첨부 테이블의 order 값을 갱신합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-board/admin/board/{slug}/attachments/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.attachments.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.attachments.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\AttachmentController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.attachments.upload`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.attachments.upload`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 첨부파일 1건을 삭제합니다. `auth:sanctum` + admin + 게시판별 `attachments.upload` 권한이 필요하며, `AttachmentService::getById()`로 대상 존재를 확인한 뒤 `delete()`가 게시판별 첨부 테이블 레코드와 실제 파일을 함께 제거합니다. 첨부가 없으면 404, 삭제 실패 시 500을 반환합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/board/{slug}/posts
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.posts.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `237` | 기본 키 (내부 식별자) |
|
||||
| category | null | `null` | 게시글 분류(카테고리) 문자열. 게시판이 카테고리를 쓰지 않거나 미지정 시 null (최대 50자). |
|
||||
| author | object | `{"uuid":"a231747f-e82e-4cf2-9ae1-a261849dce40","name":"AP…` | 작성자 사용자 객체 (uuid/name — author 관계 파생) |
|
||||
| is_notice | boolean | `false` | notice 여부 |
|
||||
| is_secret | boolean | `false` | secret 여부 |
|
||||
| content_mode | string | `html` | 본문 편집 모드. `html`(위지윅/HTML) 또는 `text`(평문)이며, 요약·썸네일 추출과 렌더링 방식을 결정합니다. 미지정 시 `text`. |
|
||||
| is_new | boolean | `true` | new 여부 |
|
||||
| status | string | `published` | 게시글 상태 코드. `published`(게시됨) / `blinded`(블라인드) / `deleted`(삭제됨) 중 하나이며, `status_label`이 사람이 읽는 라벨입니다. |
|
||||
| status_label | string | `게시됨` | 상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
|
||||
| view_count | integer | `43` | view 개수 (집계) |
|
||||
| comment_count | integer | `0` | comment 개수 (집계) |
|
||||
| reply_count | integer | `0` | reply 개수 (집계) |
|
||||
| attachment_count | integer | `0` | attachment 개수 (집계) |
|
||||
| has_attachment | boolean | `false` | attachment 여부 |
|
||||
| thumbnail | string | `/api/modules/sirsoft-board/boards/api…` | 썸네일 이미지 URL/경로 |
|
||||
| parent_id | null | `null` | parent 식별자 (연관 리소스 참조) |
|
||||
| depth | integer | `0` | 계층 트리에서의 깊이 (0 = 최상위, 하위로 갈수록 증가) |
|
||||
| is_reply | boolean | `false` | reply 여부 |
|
||||
| created_at | string | `2026-07-07 09:34:50` | 생성 일시 |
|
||||
| created_at_formatted | string | `4시간 전` | `created_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| is_author | boolean | `true` | author 여부 |
|
||||
| is_guest_post | boolean | `false` | guest post 여부 |
|
||||
| slug | string | `apidoc-sample-board` | 게시판 슬러그 (URL/테이블명) |
|
||||
| title | string | `API 문서 샘플 게시글` | 제목 |
|
||||
| deleted_at | null | `null` | 소프트 삭제 일시 (미삭제 시 null) |
|
||||
| content_preview | string | `API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.` | 목록용 본문 요약(태그 제거 후 앞 150자). 블라인드·비밀글은 원문 유출 방지를 위해 권한과 무관하게 빈 문자열을 반환합니다. |
|
||||
| row_type | string | `normal` | 목록 행 유형. `notice`(공지) / `reply`(답변글) / `normal`(일반) 중 하나로, 목록 렌더링 시 행 스타일과 순번 표시를 분기합니다. |
|
||||
| number | integer | `1` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| show_category | boolean | `false` | 목록에 카테고리 열을 노출할지 여부. 게시판 설정(`show_category`)에서 파생되어 각 행에 부여됩니다. |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.posts.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 특정 게시판의 게시글 목록을 조회합니다. `auth:sanctum` + admin + 게시판별 `posts.read` 권한이 필요하며, 요청 파라미터로 검색·상태·정렬·페이지네이션이 적용됩니다(`PostService::buildListParams`). 추가로 `admin.manage` 권한이 있으면 소프트 삭제된 게시글까지 포함해 조회하며, 응답에는 공지 고정 처리 후의 일반 게시글 총 건수(캐시 기반)와 관리자용 게시판 정보(`boardInfo`)가 함께 담깁니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-board/admin/board/{slug}/posts
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.posts.write`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-board.post.store_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.posts.write`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 새 게시글을 작성합니다. `auth:sanctum` + admin + 게시판별 `posts.write` 권한이 필요하며, `StorePostRequest` 검증을 거친 값에 작성자(`Auth::id()`)와 요청 IP가 자동으로 채워집니다. 업로드 파일과 첨부파일 ID 배열은 본문에서 분리되어 `PostService::createPost()`로 전달되고, 성공 시 생성된 게시글 리소스를 201로 반환합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/board/{slug}/posts/form-data
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.form-data -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.form-data`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@getFormData`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.posts.write`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| title | string | `` | 제목 |
|
||||
| content | string | `` | 본문 내용 |
|
||||
| content_mode | string | `text` | 본문 편집 모드. `html`(위지윅/HTML) 또는 `text`(평문)이며, 폼 초기값은 `text`입니다. |
|
||||
| category | null | `null` | 게시글 분류(카테고리) 문자열. 게시판이 카테고리를 쓰지 않거나 미지정 시 null (최대 50자). |
|
||||
| is_notice | boolean | `false` | notice 여부 |
|
||||
| is_secret | boolean | `false` | secret 여부 |
|
||||
| parent_id | null | `null` | parent 식별자 (연관 리소스 참조) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.posts.write`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시글 작성/수정/답변글 폼에 미리 채울 입력 데이터를 반환합니다. `auth:sanctum` + admin + 게시판별 `posts.write` 권한이 필요하며, 쿼리 파라미터에 따라 분기합니다. `post_id`가 있으면 기존 게시글 데이터(수정 모드), `parent_id`가 있으면 제목에 `Re:`를 붙이고 원글 카테고리·비밀글 여부를 물려받은 답변글 기본값(답글 허용 게시판만, 아니면 404), 둘 다 없으면 빈 폼(게시판 `secret_mode`가 `always`면 비밀글 기본값)을 돌려줍니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/board/{slug}/posts/form-meta
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.form-meta -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.form-meta`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@getFormMeta`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.posts.write`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| board | object | `{"id":12,"name":"API 문서 샘플 게시판","slug":"apidoc-sample-boa…` | 폼 화면 표시에 필요한 게시판 정보 객체(이름·슬러그·댓글/답글/비밀글 설정 등). 사용자 권한(abilities)과 함께 항상 포함됩니다. |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.posts.write`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시글 폼 화면 표시용 메타 데이터(읽기 전용)를 반환합니다. `auth:sanctum` + admin + 게시판별 `posts.write` 권한이 필요하며, 게시판 정보와 사용자 권한(abilities)을 항상 포함합니다. `post_id`가 있으면 작성자·작성일·첨부파일과 원글 정보를 덧붙이고(수정 모드), `parent_id`가 있으면 원글 정보를 포함하되 블라인드/삭제된 원글에는 답글 작성이 차단됩니다(각각 403).
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-board/admin/board/{slug}/posts/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.posts.write|sirsoft-board.{slug}.admin.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.posts.write|sirsoft-board.{slug}.admin.manage`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 게시글 1건을 소프트 삭제합니다. `auth:sanctum` + admin 인증이 필요하며, 라우트 권한은 `posts.write` 또는 `manage`입니다. 컨트롤러가 대상 게시글을 조회한 뒤 세분화된 권한 분기를 적용합니다: `admin.manage`는 모든 글(비회원 글 포함)을, `admin.posts.write`는 본인 글만 삭제할 수 있으며 이미 삭제된 글의 재처리는 `admin.manage`가 필요합니다. `PostService::deletePost()`가 'admin' 컨텍스트로 소프트 삭제를 수행합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/board/{slug}/posts/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.posts.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `237` | 기본 키 (내부 식별자) |
|
||||
| category | null | `null` | 게시글 분류(카테고리) 문자열. 게시판이 카테고리를 쓰지 않거나 미지정 시 null (최대 50자). |
|
||||
| author | object | `{"uuid":"a231747f-e82e-4cf2-9ae1-a261849dce40","name":"AP…` | 작성자 사용자 객체 (uuid/name — author 관계 파생) |
|
||||
| is_notice | boolean | `false` | notice 여부 |
|
||||
| is_secret | boolean | `false` | secret 여부 |
|
||||
| content_mode | string | `html` | 본문 편집 모드. `html`(위지윅/HTML) 또는 `text`(평문)이며, 요약·썸네일 추출과 렌더링 방식을 결정합니다. 미지정 시 `text`. |
|
||||
| is_new | boolean | `true` | new 여부 |
|
||||
| status | string | `published` | 게시글 상태 코드. `published`(게시됨) / `blinded`(블라인드) / `deleted`(삭제됨) 중 하나이며, `status_label`이 사람이 읽는 라벨입니다. |
|
||||
| status_label | string | `게시됨` | 상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
|
||||
| view_count | integer | `43` | view 개수 (집계) |
|
||||
| comment_count | integer | `0` | comment 개수 (집계) |
|
||||
| reply_count | integer | `0` | reply 개수 (집계) |
|
||||
| attachment_count | integer | `0` | attachment 개수 (집계) |
|
||||
| has_attachment | boolean | `false` | attachment 여부 |
|
||||
| thumbnail | string | `/api/modules/sirsoft-board/boards/api…` | 썸네일 이미지 URL/경로 |
|
||||
| parent_id | null | `null` | parent 식별자 (연관 리소스 참조) |
|
||||
| depth | integer | `0` | 계층 트리에서의 깊이 (0 = 최상위, 하위로 갈수록 증가) |
|
||||
| is_reply | boolean | `false` | reply 여부 |
|
||||
| created_at | string | `2026-07-07 09:34:50` | 생성 일시 |
|
||||
| created_at_formatted | string | `4시간 전` | `created_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| is_author | boolean | `true` | author 여부 |
|
||||
| is_guest_post | boolean | `false` | guest post 여부 |
|
||||
| title | string | `API 문서 샘플 게시글` | 제목 |
|
||||
| content | string | `<p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p>` | 본문 내용 |
|
||||
| user_id | string | `a231747f-e82e-4cf2-9ae1-a261849dce40` | user 식별자 (연관 리소스 참조) |
|
||||
| trigger_type | string | `user` | 상태 변경(삭제/블라인드 등)을 유발한 주체. `report`(신고) / `admin`(관리자 직권) / `system`(시스템) / `auto_hide`(신고 누적 자동 블라인드) / `user`(사용자 직접) / `cascade`(상위 삭제 연쇄) 중 하나입니다. |
|
||||
| updated_at | string | `2026-07-07 09:39:03` | 최종 수정 일시 |
|
||||
| deleted_at | null | `null` | 소프트 삭제 일시 (미삭제 시 null) |
|
||||
| ip_address | string | `127.0.0.1` | 요청/행위가 발생한 IP 주소 |
|
||||
| action_logs | array | `[]` | 블라인드/복원/삭제 등 처리 이력 목록(항목별 action·reason·admin_name·created_at). `admin.manage` 권한 보유자에게만 노출되며, 민감 필드(admin_id·ip_address)는 제외됩니다. 비권한자에게는 null. |
|
||||
| board | object | `{"slug":"apidoc-sample-board","name":"API 문서 샘플 게시판","typ…` | 소속 게시판 정보 객체(슬러그·이름·유형·댓글/답글/신고 사용 여부·조회수 표시·최대 답글/댓글 깊이·신고 사유 목록). board 관계가 로드된 경우에만 채워지며, 아니면 null. |
|
||||
| navigation | object | `{"prev":null,"next":null}` | 이전/다음 게시글 이동 정보. `prev`·`next` 키에 인접 게시글 요약(없으면 null)이 담기며, 상세 로드 시 함께 계산됩니다. |
|
||||
| parent | null | `null` | 상위 항목 객체 (parent 관계 파생) |
|
||||
| comments | array | `[{"id":760,"post_id":237,"parent_id":null,"content":"API …` | 게시글에 달린 댓글 목록(CommentResource 컬렉션). comments 관계가 로드된 경우에만 채워지며, 각 항목에 신고 여부가 사전 로드되어 담깁니다. |
|
||||
| attachments | array | `[{"id":155,"hash":"apidocsmpl1","original_filename":"apid…` | 게시글 첨부파일 목록(AttachmentResource 컬렉션). 비밀글은 열람 권한이 없으면 빈 배열, 삭제된 게시글은 관리 권한이 없으면 연쇄 삭제된 첨부만 노출됩니다. |
|
||||
| replies | array | `[]` | 이 게시글에 달린 답변글 목록(PostResource 컬렉션, 재귀). replies 관계가 로드된 경우에만 채워지며, 아니면 null. |
|
||||
| is_already_reported | boolean | `false` | already reported 여부 |
|
||||
| is_owner | boolean | `true` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":true,"can_write":true,"can_read_secret":true,…` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.posts.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 게시글 상세를 조회합니다. `auth:sanctum` + admin + 게시판별 `posts.read` 권한이 필요하며, 삭제된 게시글은 `admin.manage` 권한이 있어야 열람할 수 있습니다(없으면 403). `PostService::loadPostDetail()`이 조회수 증가·댓글·이전/다음 게시글까지 로드하며, 응답에는 댓글별 신고 여부를 N+1 없이 일괄 사전 로드해 담습니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-board/admin/board/{slug}/posts/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.posts.write`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-board.post.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.posts.write`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 게시글을 수정합니다. `auth:sanctum` + admin + 게시판별 `posts.write` 권한이 필요하며, 컨트롤러가 대상 게시글을 조회한 뒤 세분화된 권한을 적용합니다: 일반 글은 `admin.manage`(타인 글) 또는 `admin.write`(본인 글), 이미 삭제된 글은 `admin.manage`가 필요합니다. `UpdatePostRequest` 검증 값에서 첨부파일 ID 배열을 분리해 `PostService::updatePost()`로 전달하고, 갱신된 게시글 리소스를 반환합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-board/admin/board/{slug}/posts/{id}/blind
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.blind -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.blind`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@blind`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| reason | body | string | 아니오 | max 1000 | 블라인드 처리 사유(최대 1000자). 처리 이력(action_logs)에 기록되며, 미지정 시 빈 문자열로 저장됩니다. |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.manage`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 게시글을 블라인드 처리합니다. `auth:sanctum` + admin + 게시판별 `admin.manage` 권한이 필요하며, 선택적 `reason`(최대 1000자)을 사유로 받아 `PostService::blindPost()`가 게시글 상태를 블라인드로 전환합니다. 소프트 삭제와 달리 게시글을 숨기되 관리 목적으로 보존하는 처리이며, 복원(restore)으로 되돌릴 수 있습니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-board/admin/board/{slug}/posts/{id}/restore
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.restore -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.restore`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\PostController@restore`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| reason | body | string | 아니오 | max 1000 | 블라인드 복원 사유(최대 1000자). 처리 이력(action_logs)에 기록되며, 미지정 시 null로 전달됩니다. |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.manage`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 블라인드 처리된 게시글을 복원합니다. `auth:sanctum` + admin + 게시판별 `admin.manage` 권한이 필요하며, 선택적 `reason`(최대 1000자)을 사유로 받아 `PostService::restorePost()`가 블라인드 상태를 해제해 게시글을 다시 노출합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.comments.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.comments.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\CommentController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.comments.write`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| postId | path | string | 예 | — | 대상 post의 식별자 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-board.comment.store_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.comments.write`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 특정 게시글에 댓글을 작성합니다. `auth:sanctum` + admin + 게시판별 `comments.write` 권한이 필요하며, 게시판의 `use_comment`가 꺼져 있으면 403으로 차단됩니다. 검증된 값에 게시글 ID·작성자(`Auth::id()`)·요청 IP가 자동으로 채워져 `CommentService::createComment()`로 전달되고, 성공 시 생성된 댓글 리소스를 201로 반환합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.comments.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.comments.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\CommentController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.comments.write|sirsoft-board.{slug}.admin.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| postId | path | string | 예 | — | 대상 post의 식별자 |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.comments.write|sirsoft-board.{slug}.admin.manage`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 댓글 1건을 삭제합니다. `auth:sanctum` + admin 인증이 필요하며, 라우트 권한은 `comments.write` 또는 `manage`입니다. 컨트롤러가 댓글을 조회한 뒤 권한을 적용합니다: `admin.manage`는 모든 댓글(비회원 댓글 포함), `admin.write`는 본인 댓글만 삭제할 수 있습니다. 게시판의 `use_comment`가 꺼져 있으면 403이며, `CommentService::deleteComment()`가 'admin' 컨텍스트로 삭제를 수행합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.comments.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.comments.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\CommentController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.comments.write`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| postId | path | string | 예 | — | 대상 post의 식별자 |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-board.comment.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.comments.write`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 댓글 1건을 수정합니다. `auth:sanctum` + admin + 게시판별 `comments.write` 권한이 필요하며, 컨트롤러가 댓글을 조회한 뒤 권한을 적용합니다: `admin.manage`는 모든 댓글, `admin.write`는 본인 댓글만 수정할 수 있습니다. 게시판의 `use_comment`가 꺼져 있으면 403이며, `UpdateCommentRequest` 검증 값으로 `CommentService::updateComment()`가 갱신을 수행합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments/{id}/blind
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.comments.blind -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.comments.blind`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\CommentController@blind`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| postId | path | string | 예 | — | 대상 post의 식별자 |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| reason | body | string | 아니오 | max 1000 | 댓글 블라인드 처리 사유(최대 1000자). 처리 이력에 기록되며, 미지정 시 빈 문자열로 저장됩니다. |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.manage`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 댓글을 블라인드 처리합니다. `auth:sanctum` + admin + 게시판별 `admin.manage` 권한이 필요하며, 게시판의 `use_comment`가 꺼져 있으면 403으로 차단됩니다. 선택적 `reason`(최대 1000자)을 사유로 받아 `CommentService::blindComment()`가 댓글을 숨김 처리하되 관리 목적으로 보존하며, 복원(restore)으로 되돌릴 수 있습니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-board/admin/board/{slug}/posts/{postId}/comments/{id}/restore
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.board.posts.comments.restore -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.board.posts.comments.restore`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\CommentController@restore`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.{slug}.admin.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
| postId | path | string | 예 | — | 대상 post의 식별자 |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.{slug}.admin.manage`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 관리자가 블라인드 처리된 댓글을 복원합니다. `auth:sanctum` + admin + 게시판별 `admin.manage` 권한이 필요하며, 게시판의 `use_comment`가 꺼져 있으면 403으로 차단됩니다. 요청 본문의 선택적 `reason`을 사유로 받아 `CommentService::restoreComment()`가 블라인드 상태를 해제해 댓글을 다시 노출합니다.
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,153 @@
|
||||
# Dashboard API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-board` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Dashboard 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/dashboard/overview
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.dashboard.overview -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.dashboard.overview`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\DashboardController@overview`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| today_posts | integer | `0` | 오늘 등록된 새 게시글 수입니다. board_stats 집계 테이블의 오늘 행에서 읽으며, 행이 없으면 0 을 반환합니다(최대 1시간 지연). |
|
||||
| today_comments | integer | `0` | 오늘 등록된 새 댓글 수입니다. board_stats 집계 테이블의 오늘 행에서 읽으며, 행이 없으면 0 을 반환합니다(최대 1시간 지연). |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자 대시보드 위젯에 표시할 오늘의 게시판 현황을 반환합니다. `auth:sanctum` 인증이 필요하며(대시보드 진입은 코어 `core.dashboard.read` 가드로 보호), 오늘 등록된 새 글 수(today_posts)와 새 댓글 수(today_comments)를 집계하여 반환합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/dashboard/pending-reports
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.dashboard.pending-reports -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.dashboard.pending-reports`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\DashboardController@pendingReports`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| limit | query | integer | 아니오 | min 1, max 50 | 반환할 최대 항목 수 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| items | array | `[{"id":7,"board_slug":"qna","board_name":"Q&A","target_ty…` | 전체 게시판을 가로질러 조회한 미처리 신고 항목 목록입니다. 각 항목은 신고 대상 게시판(board_slug/board_name), 대상 종류(target_type), 대상 제목/발췌(target_title/target_excerpt), 상태, 신고 시각을 포함합니다. `limit` 개까지 반환됩니다. |
|
||||
| total | integer | `16` | 전체 개수 (집계) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 전체 게시판의 미처리 신고 목록과 총 건수를 대시보드 위젯에 표시하기 위해 반환합니다. `auth:sanctum` 인증이 필요하며(대시보드 진입은 코어 `core.dashboard.read` 가드로 보호), `limit`(1~50, 기본 5)으로 표시 건수를 제어합니다. 응답은 미처리 신고 항목(items)과 전체 미처리 건수(total)를 포함합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/dashboard/post-graph
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.dashboard.post-graph -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.dashboard.post-graph`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\DashboardController@postGraph`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| days | array | `[{"date":"2026-07-01","post_count":0,"comment_count":0},{…` | 최근 7일간 일자별 집계 막대 배열입니다. 각 원소는 날짜(date)와 해당 일의 게시글 수(post_count)/댓글 수(comment_count)를 담으며, 집계 행이 없는 날은 0 으로 채워집니다. |
|
||||
| total_posts | integer | `0` | 이번 7일 기간의 게시글 합계입니다. days 의 post_count 를 합산한 값입니다. |
|
||||
| total_comments | integer | `0` | 이번 7일 기간의 댓글 합계입니다. days 의 comment_count 를 합산한 값입니다. |
|
||||
| posts_change | null | `null` | 직전 동일 7일 기간 대비 게시글 증감율(%)입니다. 소수점 첫째 자리까지 계산하며, 직전 기간 합이 0 이면 비교 기준이 없으므로 null 을 반환합니다(화면에서 '—' 폴백). |
|
||||
| comments_change | null | `null` | 직전 동일 7일 기간 대비 댓글 증감율(%)입니다. 소수점 첫째 자리까지 계산하며, 직전 기간 합이 0 이면 비교 기준이 없으므로 null 을 반환합니다(화면에서 '—' 폴백). |
|
||||
| updated_at | null | `null` | 최종 수정 일시 |
|
||||
| updated_at_display | string | `` | 집계 행의 최종 갱신 시각(updated_at)을 모듈 날짜 표시 형식(display.date_display_format 설정)으로 포맷한 표시용 문자열입니다. 집계 행이 없으면 빈 문자열입니다. |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 대시보드 위젯의 추세 그래프에 표시할 최근 7일간 게시글/댓글 추이를 반환합니다. `auth:sanctum` 인증이 필요하며(대시보드 진입은 코어 `core.dashboard.read` 가드로 보호), 일자별 막대(days), 기간 합계(total_posts/total_comments), 이전 기간 대비 변화율(posts_change/comments_change), 갱신 시각(updated_at)을 포함합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/dashboard/recent-posts
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.dashboard.recent-posts -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.dashboard.recent-posts`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\DashboardController@recentPosts`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| limit | query | integer | 아니오 | min 1, max 50 | 반환할 최대 항목 수 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `237` | 기본 키 (내부 식별자) |
|
||||
| board_slug | string | `apidoc-sample-board` | 게시글이 속한 게시판의 슬러그입니다. 대시보드에서 해당 게시판으로 이동할 때 식별자로 사용됩니다. |
|
||||
| board_name | string | `API 문서 샘플 게시판` | 게시글이 속한 게시판의 현재 로케일 표시명입니다(getLocalizedName). |
|
||||
| title | string | `API 문서 샘플 게시글` | 제목 |
|
||||
| author_name | string | `API 문서 샘플 사용자` | 작성자 이름입니다. 회원 게시글은 연결된 사용자 이름을, 비회원 게시글은 작성 시 입력한 이름(author_name)을 사용합니다. |
|
||||
| comments_count | integer | `0` | comments 개수 (집계) |
|
||||
| created_at | string | `4시간 전` | 생성 일시 |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 전체 게시판에서 최신 게시글을 대시보드 위젯에 표시하기 위해 반환합니다. `auth:sanctum` 인증이 필요하며(대시보드 진입은 코어 `core.dashboard.read` 가드로 보호), `limit`(1~50, 기본 5)으로 표시 건수를 제어합니다. 각 항목은 게시판(board_slug/board_name), 제목, 작성자, 댓글 수, 작성 시각(상대 시간 표기)을 포함합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# My Comments API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-board` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 My Comments 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/me/my-comments
|
||||
<!-- @generated:start:api.modules.sirsoft-board.me.my-comments.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.me.my-comments.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\User\UserActivityController@myComments`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `760` | 기본 키 (내부 식별자) |
|
||||
| board_slug | string | `apidoc-sample-board` | 댓글이 달린 게시글이 속한 게시판의 슬러그(URL 식별자)입니다. 게시판 링크 구성에 사용합니다. |
|
||||
| board_name | string | `API 문서 샘플 게시판` | 댓글이 달린 게시글이 속한 게시판의 표시 이름입니다. 현재 로케일에 맞는 다국어 이름(`getLocalizedName()`)이 적용됩니다. |
|
||||
| post_title | string | `API 문서 샘플 게시글` | 댓글이 달린 원 게시글의 제목입니다. 목록에서 어느 글에 남긴 댓글인지 식별하는 데 사용합니다. |
|
||||
| post_id_val | integer | `237` | 댓글이 달린 원 게시글의 ID입니다. 원 게시글 상세로 이동하는 링크 구성에 사용합니다. |
|
||||
| content | string | `API 문서 샘플 댓글입니다.` | 본문 내용 |
|
||||
| created_at | string | `2026-07-07 09:34:50` | 생성 일시 |
|
||||
| created_at_formatted | string | `4시간 전` | `created_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원 본인이 작성한 댓글 목록을 마이페이지에 표시하기 위해 반환하며, 각 항목에 댓글 내용과 함께 원 게시글 제목·게시판 정보를 포함합니다. `auth:sanctum` 인증이 필요한 회원 전용 엔드포인트로, 대상은 항상 인증된 본인(`Auth::id()`)입니다. `board_slug`·`search`·`sort`(기본 latest) 필터와 `per_page`(1~100, 기본 20) 페이지네이션을 지원합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
# Reports API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-board` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Reports 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/reports
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.reports.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.reports.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\ReportController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.reports.view`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| filters | query | array | 아니오 | — | 추가 필터 조건 맵 (필드별 조건) |
|
||||
| status | query | string | 아니오 | — | 상태 필터 (해당 상태의 항목만 조회) |
|
||||
| target_type | query | string | 아니오 | — | 신고 대상 타입 필터 (`post`/`comment`). 단일 문자열 또는 배열로 여러 타입을 전달할 수 있습니다. |
|
||||
| target_status | query | string | 아니오 | — | 신고 대상 콘텐츠의 현재 상태 필터 (게시글/댓글의 status 기준). 단일 문자열 또는 배열로 전달하며 `all`은 무시됩니다. |
|
||||
| board_id | query | integer | 아니오 | — | board 식별자 |
|
||||
| reported_at_from | query | string | 아니오 | — | 신고 접수 기간 시작일 (`YYYY-MM-DD`). 마지막 신고일시(`last_reported_at`) 기준으로 이 날짜 00:00:00 이후 건만 조회합니다. |
|
||||
| reported_at_to | query | string | 아니오 | — | 신고 접수 기간 종료일 (`YYYY-MM-DD`). 마지막 신고일시(`last_reported_at`) 기준으로 이 날짜 23:59:59 이전 건만 조회합니다. |
|
||||
| sort_by | query | string | 아니오 | — | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| per_page | query | integer | 아니오 | — | 페이지당 항목 수 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `7` | 기본 키 (내부 식별자) |
|
||||
| board_id | integer | `6` | 게시판 ID (게시판 삭제 시 NULL) |
|
||||
| board | object | `{"id":6,"name":"Q&A","slug":"qna","title":"파일 업로드 오류","cu…` | 신고 대상이 속한 게시판 정보 (id/name/slug/대상 제목/현재 상태). 게시판 삭제 시 관계 대신 첫 신고 로그의 스냅샷 값으로 폴백합니다. |
|
||||
| target_type | string | `comment` | 신고 대상 타입 (post, comment) |
|
||||
| target_type_label | string | `댓글` | `target_type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| target_id | integer | `282` | 신고 대상 ID (동적 테이블의 ID) |
|
||||
| post_id | integer | `99` | post 식별자 (연관 리소스 참조) |
|
||||
| content | null | `null` | 본문 내용 |
|
||||
| content_mode | string | `text` | 대상 본문의 형식 모드 (`text`/`html` 등). 목록에서는 미리보기 표시 방식을 결정하며 스냅샷이 없으면 `text`로 기본 설정됩니다. |
|
||||
| content_preview | string | `저도 비슷한 경험이 있어요.` | 대상 본문의 미리보기 (앞 100자로 잘린 발췌). 목록 응답에서만 채워지고 상세 응답에서는 null 입니다. |
|
||||
| author | object | `{"uuid":"a1e0a91a-fba6-491c-a53e-7285a5686857","name":"관리…` | 작성자 사용자 객체 (uuid/name — author 관계 파생) |
|
||||
| reporter | object | `{"uuid":"a1e0a91a-fba6-491c-a53e-7285a5686857","name":"관리…` | 대표 신고자 정보 (uuid/name/email/is_guest). 첫 번째 신고 로그에서 추출하며, 비회원 신고 시 게스트로 표시됩니다. |
|
||||
| reason_type | string | `abuse` | 대표 신고 사유 코드 (첫 번째 신고 로그의 사유 Enum 값 — 예: abuse, spam). |
|
||||
| reason_type_label | string | `욕설/비방` | `reason_type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| status | string | `review` | 신고 상태 (pending, review, rejected, suspended) |
|
||||
| status_label | string | `검토` | 상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
|
||||
| status_variant | string | `info` | 상태 표시 색상/스타일 변형 키 (상태 Enum variant() 산물 — UI 배지용) |
|
||||
| processor | object | `{"uuid":"a1e0a91a-fba6-491c-a53e-7285a5686857","name":"관리자"}` | 신고를 처리한 관리자 정보 (uuid/name). 처리자가 지정되지 않은 경우 null 입니다. |
|
||||
| processed_at | string | `2026-06-01 09:35:42` | processed 일시 |
|
||||
| metadata | null | `null` | 메타데이터 (IP, User Agent 등) |
|
||||
| report_count | integer | `1` | report 개수 (집계) |
|
||||
| last_reported_at | string | `2026-06-02 09:35:42` | last reported 일시 |
|
||||
| is_reactivated | boolean | `false` | reactivated 여부 |
|
||||
| target_status | string | `published` | 신고 대상 콘텐츠(게시글/댓글)의 현재 상태. 대상 테이블의 status 컬럼을 서브쿼리로 조인한 값입니다 (예: published, blinded). |
|
||||
| target_trigger_type | string | `admin` | 신고 대상의 현재 상태를 유발한 트리거 유형. 대상 테이블의 trigger_type 값으로, 블라인드 처리가 자동(auto_hide)/관리자 수동(admin) 중 무엇에 의한 것인지 구분합니다. |
|
||||
| target_status_label | string | `게시중` | `target_status` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| created_at | string | `2026-06-04 09:35:42` | 생성 일시 |
|
||||
| updated_at | string | `2026-06-04 09:35:42` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `false` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_view":true,"can_manage":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.reports.view`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 신고 관리 화면의 목록을 조회합니다. `auth:sanctum` 인증과 `sirsoft-board.reports.view` 권한이 필요합니다. 동일 대상(게시글/댓글)에 대한 여러 신고는 그룹화되어 최초 신고 1건만 목록에 노출되며, `filters`/`status`/`target_type`/`target_status`/`board_id`/기간(`reported_at_from`~`reported_at_to`)으로 필터링하고 `sort_by`/`sort_order`로 정렬합니다. `per_page`는 10~20 범위로 강제 제한되며, 응답에는 상태별 통계와 사용자 권한 정보가 함께 포함됩니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-board/admin/reports/bulk-status
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.reports.bulk-status -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.reports.bulk-status`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\ReportController@bulkUpdateStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.reports.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
| status | body | string | 예 | — | 일괄 전환할 신고 상태 (`ReportStatus` 허용값: pending/review/rejected/suspended 등). 지정한 모든 신고를 이 상태로 변경합니다. |
|
||||
| process_note | body | string | 아니오 | max 1000 | 처리 메모 (최대 1000자). 상태 변경 사유나 조치 내용을 처리 이력에 함께 기록합니다. |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.reports.manage`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 여러 신고의 상태를 한 번에 변경합니다. `auth:sanctum` 인증과 `sirsoft-board.reports.manage` 권한이 필요합니다. `ids`로 지정한 신고들만 대상으로 하며(그룹 확장 없음) `status`로 지정한 상태로 일괄 전환하고, 선택적으로 `process_note`(최대 1000자)를 처리 메모로 남깁니다. 응답은 실제 변경된 건수(`affected_count`), 대상 콘텐츠 복구 건수(`restored_count`), 수동 블라인드 복구 건수(`manual_blind_restored`)와 안내 메시지를 반환합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-board/admin/reports/status-counts
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.reports.status-counts -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.reports.status-counts`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\ReportController@getStatusCounts`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.reports.view`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
| target_status | body | string | 아니오 | — | 집계 기준이 되는 전환 대상 상태 (`ReportStatus` 허용값). 지정 시 해당 상태로의 일괄 전환을 가정한 상태별 건수 요약을 계산합니다. |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.reports.view`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 선택된 신고들의 상태별 건수를 집계하여 반환합니다. `auth:sanctum` 인증과 `sirsoft-board.reports.view` 권한이 필요합니다. 대량 상태 변경을 실행하기 전에 사용자에게 선택한 신고들의 상태 분포를 미리 보여주기 위한 조회용 API로, `ids` 배열(최소 1개)과 선택적 `target_status`를 받아 상태별 건수와 요약 정보를 계산합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-board/admin/reports/{report}
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.reports.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.reports.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\ReportController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.reports.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| report | path | string | 예 | — | 대상 report의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.reports.manage`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 신고를 삭제합니다(소프트 삭제). `auth:sanctum` 인증과 `sirsoft-board.reports.manage` 권한이 필요합니다. 경로의 `report`(신고 ID)에 해당하는 신고 케이스를 소프트 삭제하며, 존재하지 않으면 404, 스코프 권한 위반 시 403을 반환합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/reports/{report}
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.reports.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.reports.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\ReportController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.reports.view`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| report | path | string | 예 | — | 대상 report의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| board_id | integer | `4` | 게시판 ID (게시판 삭제 시 NULL) |
|
||||
| board | object | `{"id":4,"name":"갤러리","slug":"gallery"}` | 신고 대상이 속한 게시판 정보 (id/name/slug). 게시판이 삭제된 경우 관계 대신 첫 신고 로그 스냅샷의 게시판명으로 폴백합니다. |
|
||||
| target_type | string | `post` | 신고 대상 타입 (post, comment) |
|
||||
| target_id | integer | `55` | 신고 대상 ID (동적 테이블의 ID) |
|
||||
| post | object | `{"id":55,"title":"작업물 공유합니다","content":"최근에 작업한 결과물입니다.피드…` | 신고 대상 게시글 상세 (id/title/content/작성일시/작성자). 대상이 댓글이면 해당 댓글의 상위 게시글 정보가 담기며, 조회 불가 시 null 입니다. |
|
||||
| comment | null | `null` | 신고 대상 댓글 상세 (id/content/작성일시/작성자). 대상 타입이 comment 일 때만 채워지고 게시글 신고에서는 null 입니다. |
|
||||
| target_status | string | `published` | 신고 대상 콘텐츠의 현재 상태 (reportable의 current_status — 예: published, blinded). |
|
||||
| target_status_label | string | `게시중` | `target_status` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| blind_trigger_type | string | `admin` | 대상 콘텐츠의 블라인드/상태 변경을 유발한 트리거 유형 (reportable의 trigger_type — 예: 자동/관리자 수동). |
|
||||
| blind_trigger_type_label | string | `관리자 수동` | `blind_trigger_type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| status | string | `pending` | 신고 상태 (pending, review, rejected, suspended) |
|
||||
| available_actions | array | `["review","rejected","suspended","deleted"]` | 현재 상태에서 전환 가능한 다음 신고 상태 목록 (상태 Enum의 getAvailableTransitions() 산물). 상태 변경 UI의 선택지로 사용됩니다. |
|
||||
| abilities | object | `{"can_view":true,"can_manage":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
| reporters | array | `[{"id":1,"reporter":{"uuid":"a1e0a91a-fba6-491c-a53e-7285…` | 이 케이스에 접수된 개별 신고 로그 목록. 각 항목은 신고자(reporter)·사유(reason_type/reason_detail)·신고 시점 스냅샷(snapshot)·신고 일시를 포함합니다. |
|
||||
| report_count | integer | `1` | report 개수 (집계) |
|
||||
| reason_summary | string | `욕설/비방 1건` | 신고 사유 요약 문자열. 상위 2개 사유를 "사유 N건" 형식으로 나열하고 나머지는 "외 N건"으로 합산해 표시합니다. |
|
||||
| first_reported_at | string | `2026-06-04 09:35:42` | first reported 일시 |
|
||||
| last_reported_at | string | `2026-05-13 09:35:42` | last reported 일시 |
|
||||
| histories | array | `[{"id":1,"type":"reported","action_label":"신고 접수","proces…` | 신고 처리 이력 타임라인 (process_histories JSON 기반, 최신순). 각 항목은 이벤트 유형·라벨·처리자·사유·신고자 수·발생 일시를 포함하며, 접수 이벤트에는 처리자가 없습니다. |
|
||||
| metadata | object | `{"ip":"127.0.0.1","user_agent":"Mozilla\/5.0 (Windows NT …` | 메타데이터 (IP, User Agent 등) |
|
||||
| created_at | string | `2026-06-04 09:35:42` | 생성 일시 |
|
||||
| updated_at | string | `2026-06-04 09:35:42` | 최종 수정 일시 |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.reports.view`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 신고 케이스 1건의 상세 정보를 조회합니다. `auth:sanctum` 인증과 `sirsoft-board.reports.view` 권한이 필요합니다. 경로의 `report`(신고 ID)를 기준으로 동일 대상에 대한 모든 신고를 그룹화한 상세 정보와 신고 대상 콘텐츠(reportable) 데이터를 함께 반환하며, 처리 이력(histories), 신고자 목록(reporters), 사유 요약(reason_summary), 전환 가능한 상태(available_actions) 등을 포함합니다. 대상이 없으면 404, 스코프 권한 위반 시 403을 반환합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/reports/{report}/reporters
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.reports.reporters -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.reports.reporters`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\ReportController@reporters`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.reports.view`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| report | path | string | 예 | — | 대상 report의 식별자 |
|
||||
| per_page | query | integer | 아니오 | min 1 | 페이지당 항목 수 |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| reporter | object | `{"uuid":"a1e0a91a-fba6-491c-a53e-7285a5686857","name":"관리…` | 개별 신고자 정보 (uuid/name/email). 비회원(게스트) 신고 로그인 경우 null 입니다. |
|
||||
| reason_type | string | `abuse` | 신고 사유 코드 (사유 Enum 값 — 예: abuse, spam). |
|
||||
| reason_type_label | string | `욕설/비방` | `reason_type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| reason_detail | string | `욕설과 비방이 포함된 게시글입니다. 다른 사용자를 모욕하는 내용이 …` | 신고자가 직접 입력한 상세 사유 텍스트. 입력하지 않은 경우 null 입니다. |
|
||||
| snapshot | object | `{"board_name":"갤러리","title":"작업물 공유합니다","content":"최근에 작업…` | 신고 접수 시점의 대상 콘텐츠 스냅샷 (게시판명/제목/본문/작성자 등). 이후 대상이 수정·삭제되어도 신고 당시 내용을 보존합니다. |
|
||||
| reported_at | string | `2026-06-04 09:35:42` | reported 일시 |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.reports.view`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 신고 케이스에 접수된 개별 신고자 목록을 페이지네이션으로 반환합니다. `auth:sanctum` 인증과 `sirsoft-board.reports.view` 권한이 필요합니다. 경로의 `report`(신고 케이스 ID)에 대해 각 신고자의 신고 사유(reason_type/reason_detail)와 신고 시점 스냅샷(snapshot)을 포함한 항목을 반환하며, `per_page`(최대 50)와 `page`로 페이지를 제어합니다. 대상이 없으면 404를 반환합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-board/admin/reports/{report}/status
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.reports.update-status -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.reports.update-status`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\ReportController@updateStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.reports.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| report | path | string | 예 | — | 대상 report의 식별자 |
|
||||
| status | body | string | 예 | — | 전환할 신고 상태 (`ReportStatus` 허용값). 현재 상태에서 전환 불가한 값(영구삭제 등)은 검증에서 422로 차단됩니다. |
|
||||
| process_note | body | string | 아니오 | max 1000 | 처리 메모 (최대 1000자). 상태 변경 사유나 조치 내용을 처리 이력에 함께 기록합니다. |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.reports.manage`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 단건 신고의 상태를 변경합니다. `auth:sanctum` 인증과 `sirsoft-board.reports.manage` 권한이 필요합니다. 경로의 `report`(신고 ID)에 대해 `status`로 지정한 상태로 전환하고 선택적으로 `process_note`(최대 1000자)를 처리 메모로 남깁니다. 영구삭제(deleted) 등 전환 불가 상태는 FormRequest 검증에서 422로 선차단되고 서비스의 deleted 가드가 2차 방어선으로 동작하며, 대상이 없으면 404를 반환합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
# Settings API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-board` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Settings 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/settings
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.settings.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.settings.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\BoardSettingsController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| basic_defaults | object | `{"type":"basic","per_page":20,"per_page_mobile":15,"order…` | 게시판 생성 시 적용되는 기본 설정 카테고리. 게시판 타입, 페이지당 글 수(PC/모바일), 정렬 기준/방향, 댓글·답글 사용 여부와 깊이, 제목·내용·댓글 길이 제한, 파일 업로드 허용/용량/개수/확장자, 새 글 표시 시간, 게시판 기본 권한(default_board_permissions) 등을 포함합니다. |
|
||||
| report_policy | object | `{"auto_hide_threshold":5,"auto_hide_target":"both","daily…` | 신고 정책 카테고리. 자동 숨김 임계치(auto_hide_threshold)와 대상(auto_hide_target: post/comment/both), 사용자별 일일 신고 한도, 신고 거부 누적 제한(횟수/기간), 관리자·작성자 신고 알림 발송 여부와 채널을 포함합니다. |
|
||||
| spam_security | object | `{"post_cooldown_seconds":0,"comment_cooldown_seconds":0,"…` | 스팸·보안 카테고리. 글·댓글·신고 작성 사이의 도배 방지 쿨다운 시간(초)과 조회수 캐시 TTL을 포함합니다. |
|
||||
| display | object | `{"date_display_format":"standard"}` | 표시 설정 카테고리. 날짜 표시 형식(date_display_format: standard 절대 표기 / relative 상대 표기)을 포함합니다. |
|
||||
| seo | object | `{"meta_boards_title":"{site_name}","meta_boards_descripti…` | SEO 메타 태그 설정 카테고리. 게시판 목록/개별 게시판/글 상세 페이지의 메타 제목·설명 템플릿과 각 페이지의 SEO 생성 활성화 여부(seo_boards, seo_board, seo_post_detail)를 포함합니다. |
|
||||
| notifications | object | `{"channels":[{"id":"mail","is_active":true,"sort_order":0…` | 알림 채널 설정 카테고리. 각 채널(mail, database 등)의 식별자, 활성화 여부(is_active), 정렬 순서(sort_order)를 담은 channels 배열을 포함합니다. |
|
||||
| report_permissions | object | `{"view_roles":["admin","manager"],"manage_roles":["admin"]}` | 신고 관리 권한 역할. 신고 내역을 조회할 수 있는 역할(view_roles)과 신고를 처리·관리할 수 있는 역할(manage_roles)의 식별자 배열이며, 설정값이 아닌 DB 권한 데이터로 관리됩니다. |
|
||||
| abilities | object | `{"can_update":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
| _meta | object | `{"limits":{"per_page_min":5,"per_page_max":100,"min_title…` | 편집 UI 보조 메타데이터. `limits`에 `config('sirsoft-board.limits')` 기반 입력 제한값(페이지당 글 수·답글/댓글 깊이의 최소·최대 등)이 담겨 프론트 입력 검증 범위로 사용됩니다. |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.settings.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 모듈의 전체 환경설정을 조회합니다. `auth:sanctum` 인증과 `sirsoft-board.settings.read` 권한이 필요합니다. 기본값(basic_defaults)/신고정책(report_policy)/스팸·보안(spam_security)/표시(display)/SEO/알림(notifications) 등 모든 카테고리 설정과 신고 권한 역할(report_permissions)을 함께 반환하며, 현재 사용자의 수정 가능 여부(abilities)와 입력 제한값(`_meta.limits`, `config('sirsoft-board.limits')`)을 포함합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-board/admin/settings
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.settings.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.settings.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\BoardSettingsController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| _tab | body | string | 아니오 | `basic_defaults`, `report_policy`, `spam_security`, `general`, `seo`, `notifications`, `notification_definitions` | 현재 편집 중인 탭을 나타내는 메타 값. 탭 단위 부분 저장의 컨텍스트를 식별하는 용도이며 설정값으로는 저장되지 않습니다. |
|
||||
| notifications | body | array | 아니오 | — | 알림 채널 설정. `channels` 배열의 각 항목에 채널 식별자(id), 활성화 여부(is_active), 정렬 순서(sort_order)를 담아 저장합니다. |
|
||||
| basic_defaults | body | array | 아니오 | — | 기본 설정 카테고리 값. 게시판 타입·페이지당 글 수·정렬·댓글/답글·길이 제한·파일 업로드·기본 권한 등 basic_defaults 하위 키를 저장합니다. |
|
||||
| report_policy | body | array | 아니오 | — | 신고 정책 카테고리 값. 자동 숨김 임계치/대상, 일일 신고 한도, 거부 누적 제한, 관리자·작성자 신고 알림 설정을 저장합니다. |
|
||||
| report_permissions | body | array | 아니오 | — | 신고 관리 권한 역할. `view_roles`(조회 역할)와 `manage_roles`(관리 역할)의 역할 식별자 배열이며, 포함 시 설정 저장과 별개로 DB 권한 역할이 동기화됩니다. |
|
||||
| display | body | array | 아니오 | — | 표시 설정 카테고리 값. 날짜 표시 형식(date_display_format: standard/relative) 등을 저장합니다. |
|
||||
| spam_security | body | array | 아니오 | — | 스팸·보안 카테고리 값. 글·댓글·신고 작성 쿨다운 시간(초)과 조회수 캐시 TTL을 저장합니다. |
|
||||
| seo | body | array | 아니오 | — | SEO 설정 카테고리 값. 게시판 목록/개별/글 상세 페이지의 메타 제목·설명 템플릿과 각 페이지 SEO 활성화 여부를 저장합니다. |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 모듈의 환경설정을 저장합니다. `auth:sanctum` 인증과 `sirsoft-board.settings.update` 권한이 필요합니다. `_tab`으로 지정한 탭 단위로 검증된 설정을 저장하며, `report_permissions`가 포함된 경우 신고 권한 역할도 함께 동기화합니다. 저장 성공 시 갱신된 전체 설정과 신고 권한 역할을 반환합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-board/admin/settings/bulk-apply
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.settings.bulk-apply -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.settings.bulk-apply`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\BoardSettingsController@bulkApply`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| fields | body | array | 예 | min 1 | 대상 게시판에 일괄 적용할 필드 목록(최소 1개). boards 테이블 컬럼(type, per_page, use_comment, allowed_extensions 등)이나 권한 필드(default_board_permissions, manager), 점(.)을 포함한 개별 권한 키(예: `posts.read`)를 허용합니다. |
|
||||
| apply_all | body | boolean | 예 | — | 전체 게시판 적용 여부. true면 모든 게시판에 적용하고, false면 `board_ids`로 지정한 게시판에만 적용합니다(false 시 board_ids 필수). |
|
||||
| board_ids | body | array | 아니오 | — | board 식별자 배열 |
|
||||
| override_values | body | array | 아니오 | — | 환경설정 기본값 대신 사용할 재정의 값 맵. 지정한 필드에 대해 기본값이 아닌 임의의 값으로 일괄 적용할 때 사용합니다. |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 환경설정의 기본값을 기존 게시판들에 일괄 적용합니다. `auth:sanctum` 인증과 `sirsoft-board.settings.update` 권한이 필요합니다. `fields`(적용할 필드, 최소 1개)와 `apply_all`(전체 적용 여부)을 받으며, `apply_all`이 false이면 `board_ids`로 대상을 지정하고 `override_values`로 값을 재정의할 수 있습니다. 적용 도중 실패하면 전체가 롤백되며, 이 경우에도 HTTP 200으로 `rolled_back: true`와 실패 지점 정보를 반환하여 프론트에서 안내 처리합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-board/admin/settings/clear-cache
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.settings.clear-cache -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.settings.clear-cache`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\BoardSettingsController@clearCache`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.settings.update`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 게시판 모듈 설정 캐시를 초기화합니다. `auth:sanctum` 인증과 `sirsoft-board.settings.update` 권한이 필요합니다. ModuleSettings 캐시와 게시판 캐시를 모두 초기화하며, 응답으로 `cleared: true`를 반환합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/admin/settings/{category}
|
||||
<!-- @generated:start:api.modules.sirsoft-board.admin.settings.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.admin.settings.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\Admin\BoardSettingsController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-board.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| category | path | string | 예 | — | 분류 필터 (해당 분류의 항목만 조회) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-board.settings.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 카테고리의 설정만 조회합니다. `auth:sanctum` 인증과 `sirsoft-board.settings.read` 권한이 필요합니다. 경로의 `category`에 해당하는 설정만 반환하며, 응답에는 카테고리명(category), 설정값(settings), 현재 사용자의 수정 가능 여부(abilities)가 포함됩니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
# Users API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-board` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Users 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/users/{user}/posts
|
||||
<!-- @generated:start:api.modules.sirsoft-board.users.posts.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.users.posts.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\User\PostController@userPosts`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| user | path | string | 예 | — | 대상 user의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `237` | 기본 키 (내부 식별자) |
|
||||
| board_slug | string | `apidoc-sample-board` | 게시글이 속한 게시판의 슬러그(URL 식별자)입니다. 게시판 상세 링크 구성에 사용합니다. |
|
||||
| board_name | string | `API 문서 샘플 게시판` | 게시글이 속한 게시판의 표시 이름입니다. 현재 로케일에 맞는 다국어 이름(`getLocalizedName()`)이 적용됩니다. |
|
||||
| activity_type | string | `authored` | 활동 유형입니다. 공개 프로필의 게시글 목록은 작성글만 반환하므로 항상 `authored`(본인이 작성한 글)입니다. |
|
||||
| activity_count | integer | `0` | activity 개수 (집계) |
|
||||
| title | string | `API 문서 샘플 게시글` | 제목 |
|
||||
| is_secret | boolean | `false` | secret 여부 |
|
||||
| status | string | `published` | 계정 상태 (active: 활성, inactive: 비활성, blocked: 차단, withdrawn: 탈퇴) |
|
||||
| view_count | integer | `43` | view 개수 (집계) |
|
||||
| comment_count | integer | `0` | comment 개수 (집계) |
|
||||
| created_at | string | `2026-07-07 09:34:50` | 생성 일시 |
|
||||
| created_at_formatted | string | `4시간 전` | `created_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| content_plain | string | `API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.` | 게시글 본문의 순수 텍스트입니다. HTML 모드 글은 태그를 제거한 평문으로 변환되며, 목록 미리보기용으로 사용합니다. |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 사용자(`{user}` 는 회원 uuid 로 라우트 바인딩)의 공개 프로필 페이지에 표시할 게시글 목록을 모든 게시판에 걸쳐 반환합니다. 비밀글은 제외되며, `optional.sanctum` 이 적용되어 비로그인 상태에서도 조회할 수 있습니다. `per_page`(1~100, 기본 20)와 `sort`(latest 등) 쿼리 파라미터로 페이지네이션·정렬을 제어합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-board/users/{user}/posts/stats
|
||||
<!-- @generated:start:api.modules.sirsoft-board.users.posts.stats -->
|
||||
- **라우트명**: `api.modules.sirsoft-board.users.posts.stats`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Board\Http\Controllers\User\PostController@userPostsStats`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| user | path | string | 예 | — | 대상 user의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| posts_count | integer | `1` | posts 개수 (집계) |
|
||||
| comments_count | integer | `1` | comments 개수 (집계) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 공개 프로필 페이지 상단에 표시할 특정 사용자(`{user}` 는 회원 uuid)의 게시글·댓글 수 요약을 반환합니다. `status=published` 인 항목만 집계하며, `optional.sanctum` 이 적용되어 비로그인 상태에서도 조회할 수 있습니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Sirsoft\Board\Support\ApiDoc;
|
||||
|
||||
use App\Contracts\ApiDoc\ApiDocSampleSeeder;
|
||||
use App\Models\User;
|
||||
use Modules\Sirsoft\Board\Enums\PostStatus;
|
||||
use Modules\Sirsoft\Board\Enums\ReportReasonType;
|
||||
use Modules\Sirsoft\Board\Enums\ReportStatus;
|
||||
use Modules\Sirsoft\Board\Enums\ReportType;
|
||||
use Modules\Sirsoft\Board\Enums\TriggerType;
|
||||
use Modules\Sirsoft\Board\Models\Attachment;
|
||||
use Modules\Sirsoft\Board\Models\Board;
|
||||
use Modules\Sirsoft\Board\Models\BoardType;
|
||||
use Modules\Sirsoft\Board\Models\Comment;
|
||||
use Modules\Sirsoft\Board\Models\Post;
|
||||
use Modules\Sirsoft\Board\Models\Report;
|
||||
use Modules\Sirsoft\Board\Services\BoardPermissionService;
|
||||
|
||||
/**
|
||||
* sirsoft-board API 문서 실측용 완전 샘플 시더
|
||||
*
|
||||
* 게시판 도메인은 라우트가 route-model binding 대신 게시판 slug·게시글 id 를
|
||||
* 문자열 path 파라미터로 받으므로(boards/{slug}/posts/{id}), docgen 의 route key
|
||||
* 자동 치환이 상세 GET 에서 동작하지 않습니다. 이 시더는 완전 샘플 게시판
|
||||
* (공개 게시글 + 댓글 + 첨부)을 멱등 생성하고, 각 도메인의 `path_params` 맵으로
|
||||
* slug/id/hash 를 실제 값으로 치환할 수 있게 하여 상세 조회를 실측 가능하게 합니다.
|
||||
*
|
||||
* `api:docgen --scope=module:sirsoft-board` 실행 시 커맨드가 규약 위치
|
||||
* (`Modules\Sirsoft\Board\Support\ApiDoc\ApiDocSampleService`)로 자동 발견합니다.
|
||||
*/
|
||||
class ApiDocSampleService implements ApiDocSampleSeeder
|
||||
{
|
||||
/**
|
||||
* @var string 샘플 게시판 식별용 슬러그 마커
|
||||
*/
|
||||
private const SAMPLE_SLUG = 'apidoc-sample-board';
|
||||
|
||||
/**
|
||||
* 게시판 도메인 완전 샘플을 멱등 생성하고 도메인별 대표 route key + path_params 맵을 반환합니다.
|
||||
*
|
||||
* @return array<string, array{model: class-string, key: string, value: string, path_params?: array<string, string>}> 도메인 => 대표 레코드 정보
|
||||
*/
|
||||
public function seed(): array
|
||||
{
|
||||
$board = $this->seedBoard();
|
||||
$post = $this->seedPost($board);
|
||||
$comment = $this->seedComment($board, $post);
|
||||
$attachment = $this->seedAttachment($board, $post);
|
||||
|
||||
// 게시판 slug 라우팅(boards/{slug}/posts/{id}...)을 실측하기 위한 path 파라미터 맵.
|
||||
// route-model binding 이 없는 문자열 param 을 실제 값으로 정확 일치 치환한다.
|
||||
$boardParams = [
|
||||
'slug' => (string) $board->slug,
|
||||
'board' => (string) $board->getKey(),
|
||||
'id' => (string) $post->getKey(),
|
||||
'postId' => (string) $post->getKey(),
|
||||
'commentId' => (string) $comment->getKey(),
|
||||
'hash' => (string) $attachment->hash,
|
||||
];
|
||||
|
||||
$map = [];
|
||||
|
||||
// boards: 공개(User) 게시판/게시글/댓글/첨부 라우트
|
||||
$map['boards'] = [
|
||||
'model' => Board::class,
|
||||
'key' => $board->getRouteKeyName(),
|
||||
'value' => (string) $board->getRouteKey(),
|
||||
'path_params' => $boardParams,
|
||||
];
|
||||
|
||||
// board: 관리자 게시글/첨부/댓글 라우트(admin/board/{slug}/posts/{id}...)
|
||||
$map['board'] = [
|
||||
'model' => Board::class,
|
||||
'key' => $board->getRouteKeyName(),
|
||||
'value' => (string) $board->getRouteKey(),
|
||||
'path_params' => $boardParams,
|
||||
];
|
||||
|
||||
// reports: 신고 상세(admin/reports/{report}) 실측용 대표 신고
|
||||
if ($report = $this->representativeReport($board, $post)) {
|
||||
$map['reports'] = [
|
||||
'model' => Report::class,
|
||||
'key' => $report->getRouteKeyName(),
|
||||
'value' => (string) $report->getRouteKey(),
|
||||
'path_params' => ['report' => (string) $report->getKey()],
|
||||
];
|
||||
}
|
||||
|
||||
// board-types: 게시판 유형(GET 상세는 없으나 대표 키 노출)
|
||||
if ($boardType = $this->representativeBoardType()) {
|
||||
$map['board-types'] = [
|
||||
'model' => BoardType::class,
|
||||
'key' => $boardType->getRouteKeyName(),
|
||||
'value' => (string) $boardType->getRouteKey(),
|
||||
'path_params' => ['id' => (string) $boardType->getKey()],
|
||||
];
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전 샘플 게시판을 멱등 생성합니다(신고/파일 업로드 활성).
|
||||
*
|
||||
* @return Board 대표 게시판 레코드
|
||||
*/
|
||||
private function seedBoard(): Board
|
||||
{
|
||||
$board = Board::query()->where('slug', self::SAMPLE_SLUG)->first()
|
||||
?? Board::factory()->create([
|
||||
'slug' => self::SAMPLE_SLUG,
|
||||
'name' => ['ko' => 'API 문서 샘플 게시판', 'en' => 'API Doc Sample Board'],
|
||||
'is_active' => true,
|
||||
'use_report' => true,
|
||||
'use_file_upload' => true,
|
||||
'show_view_count' => true,
|
||||
]);
|
||||
|
||||
// factory 직접 생성은 BoardService::create 의 권한 등록 훅을 우회하므로,
|
||||
// 게시판별 권한(sirsoft-board.{slug}.{action})을 멱등 등록한다. 기본 role
|
||||
// 매핑에 admin 이 포함(posts.read/comments.read 등)되어 실측 사용자(admin)가
|
||||
// slug 라우트(boards/{slug}/posts...)를 403 없이 실측할 수 있게 한다.
|
||||
(new BoardPermissionService)->ensureBoardPermissions($board);
|
||||
|
||||
return $board;
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전 샘플 공개 게시글을 멱등 생성합니다.
|
||||
*
|
||||
* @param Board $board 대표 게시판
|
||||
* @return Post 대표 게시글 레코드
|
||||
*/
|
||||
private function seedPost(Board $board): Post
|
||||
{
|
||||
$post = Post::query()
|
||||
->where('board_id', $board->id)
|
||||
->where('title', 'API 문서 샘플 게시글')
|
||||
->first();
|
||||
|
||||
if ($post) {
|
||||
return $post;
|
||||
}
|
||||
|
||||
$actor = $this->sampleActor();
|
||||
|
||||
return Post::query()->create([
|
||||
'board_id' => $board->id,
|
||||
'title' => 'API 문서 샘플 게시글',
|
||||
'content' => '<p>API 레퍼런스 실측용 완전 샘플 게시글 본문입니다.</p>',
|
||||
'content_mode' => 'html',
|
||||
'user_id' => $actor?->id,
|
||||
'author_name' => $actor?->name ?? '관리자',
|
||||
'ip_address' => '127.0.0.1',
|
||||
'is_notice' => false,
|
||||
'is_secret' => false,
|
||||
'status' => PostStatus::Published,
|
||||
'trigger_type' => TriggerType::User,
|
||||
'view_count' => 42,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전 샘플 댓글을 멱등 생성합니다.
|
||||
*
|
||||
* @param Board $board 대표 게시판
|
||||
* @param Post $post 대표 게시글
|
||||
* @return Comment 대표 댓글 레코드
|
||||
*/
|
||||
private function seedComment(Board $board, Post $post): Comment
|
||||
{
|
||||
$comment = Comment::query()
|
||||
->where('post_id', $post->id)
|
||||
->where('content', 'API 문서 샘플 댓글입니다.')
|
||||
->first();
|
||||
|
||||
if ($comment) {
|
||||
return $comment;
|
||||
}
|
||||
|
||||
$actor = $this->sampleActor();
|
||||
|
||||
return Comment::query()->create([
|
||||
'board_id' => $board->id,
|
||||
'post_id' => $post->id,
|
||||
'user_id' => $actor?->id,
|
||||
'author_name' => $actor?->name ?? '관리자',
|
||||
'content' => 'API 문서 샘플 댓글입니다.',
|
||||
'is_secret' => false,
|
||||
'status' => PostStatus::Published,
|
||||
'trigger_type' => TriggerType::User,
|
||||
'depth' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 완전 샘플 첨부파일 레코드를 멱등 생성합니다(실파일 없이 메타만).
|
||||
*
|
||||
* @param Board $board 대표 게시판
|
||||
* @param Post $post 대표 게시글
|
||||
* @return Attachment 대표 첨부 레코드
|
||||
*/
|
||||
private function seedAttachment(Board $board, Post $post): Attachment
|
||||
{
|
||||
$attachment = Attachment::query()
|
||||
->where('post_id', $post->id)
|
||||
->where('original_filename', 'apidoc-sample.png')
|
||||
->first();
|
||||
|
||||
if ($attachment) {
|
||||
return $attachment;
|
||||
}
|
||||
|
||||
$actor = $this->sampleActor();
|
||||
|
||||
return Attachment::query()->create([
|
||||
'board_id' => $board->id,
|
||||
'post_id' => $post->id,
|
||||
'hash' => 'apidocsmpl1',
|
||||
'original_filename' => 'apidoc-sample.png',
|
||||
'stored_filename' => 'apidoc-sample.png',
|
||||
'disk' => 'public',
|
||||
'path' => 'board/apidoc-sample.png',
|
||||
'mime_type' => 'image/png',
|
||||
'size' => 2048,
|
||||
'collection' => 'default',
|
||||
'order' => 0,
|
||||
'created_by' => $actor?->id,
|
||||
'trigger_type' => TriggerType::User,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 신고 상세 실측용 대표 신고를 반환합니다(기존 우선, 없으면 멱등 생성).
|
||||
*
|
||||
* @param Board $board 대표 게시판
|
||||
* @param Post $post 대표 게시글
|
||||
* @return Report|null 대표 신고 (생성 실패 시 null)
|
||||
*/
|
||||
private function representativeReport(Board $board, Post $post): ?Report
|
||||
{
|
||||
if ($report = Report::query()->orderBy('id')->first()) {
|
||||
return $report;
|
||||
}
|
||||
|
||||
$actor = $this->sampleActor();
|
||||
|
||||
return Report::query()->create([
|
||||
'board_id' => $board->id,
|
||||
'target_type' => ReportType::Post,
|
||||
'target_id' => $post->id,
|
||||
'author_id' => $actor?->id,
|
||||
'status' => ReportStatus::Pending,
|
||||
'process_histories' => [],
|
||||
'metadata' => ['reason' => ReportReasonType::Spam->value],
|
||||
'last_reported_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 대표 게시판 유형을 반환합니다(기존 우선, 없으면 멱등 생성).
|
||||
*
|
||||
* @return BoardType|null 대표 게시판 유형 (없으면 null)
|
||||
*/
|
||||
private function representativeBoardType(): ?BoardType
|
||||
{
|
||||
if ($boardType = BoardType::query()->orderBy('id')->first()) {
|
||||
return $boardType;
|
||||
}
|
||||
|
||||
return BoardType::query()->create([
|
||||
'slug' => 'apidoc-sample-type',
|
||||
'name' => ['ko' => 'API 문서 샘플 유형', 'en' => 'API Doc Sample Type'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 샘플 작성자로 쓸 사용자를 반환합니다.
|
||||
*
|
||||
* 코어 완전 샘플 사용자(먼저 시드됨)를 우선하고, 없으면 첫 사용자로 폴백합니다.
|
||||
*
|
||||
* @return User|null 샘플 사용자 (없으면 null)
|
||||
*/
|
||||
private function sampleActor(): ?User
|
||||
{
|
||||
return User::query()->where('email', 'apidoc-sample-user@example.com')->first()
|
||||
?? User::query()->orderBy('id')->first();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Sirsoft\Board\Tests\Unit\Support;
|
||||
|
||||
// ModuleTestCase를 수동으로 require (autoload 전에 로드 필요)
|
||||
require_once __DIR__.'/../../ModuleTestCase.php';
|
||||
|
||||
use App\Contracts\ApiDoc\ApiDocSampleSeeder;
|
||||
use Modules\Sirsoft\Board\Models\Attachment;
|
||||
use Modules\Sirsoft\Board\Models\Board;
|
||||
use Modules\Sirsoft\Board\Models\Comment;
|
||||
use Modules\Sirsoft\Board\Models\Post;
|
||||
use Modules\Sirsoft\Board\Support\ApiDoc\ApiDocSampleService;
|
||||
use Modules\Sirsoft\Board\Tests\ModuleTestCase;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
|
||||
/**
|
||||
* sirsoft-board API 문서 실측용 완전 샘플 시더 테스트.
|
||||
*
|
||||
* 게시판 도메인 대표 샘플(공개 게시글 + 댓글 + 첨부)이 생성되고, slug 라우팅
|
||||
* 실측을 위한 도메인별 path_params 맵이 반환되며, 재실행 시 멱등한지 검증한다.
|
||||
*/
|
||||
class ApiDocSampleServiceTest extends ModuleTestCase
|
||||
{
|
||||
/**
|
||||
* @var string 샘플 게시판 슬러그 마커
|
||||
*/
|
||||
private const SAMPLE_SLUG = 'apidoc-sample-board';
|
||||
|
||||
#[Test]
|
||||
public function 시더는_계약을_구현한다(): void
|
||||
{
|
||||
$this->assertInstanceOf(ApiDocSampleSeeder::class, new ApiDocSampleService);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function 게시판_도메인_대표_샘플_맵을_반환한다(): void
|
||||
{
|
||||
$map = (new ApiDocSampleService)->seed();
|
||||
|
||||
// 공개(boards)/관리자(board) 두 도메인 키가 모두 존재
|
||||
$this->assertArrayHasKey('boards', $map);
|
||||
$this->assertArrayHasKey('board', $map);
|
||||
$this->assertSame(Board::class, $map['boards']['model']);
|
||||
$this->assertNotEmpty($map['boards']['value']);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function slug_라우팅_실측용_path_params_맵을_제공한다(): void
|
||||
{
|
||||
$map = (new ApiDocSampleService)->seed();
|
||||
|
||||
// boards 도메인은 slug/board/id/postId/commentId/hash 를 실제 값으로 제공
|
||||
$params = $map['boards']['path_params'];
|
||||
|
||||
$this->assertSame(self::SAMPLE_SLUG, $params['slug']);
|
||||
$this->assertArrayHasKey('id', $params);
|
||||
$this->assertArrayHasKey('postId', $params);
|
||||
$this->assertArrayHasKey('commentId', $params);
|
||||
$this->assertArrayHasKey('hash', $params);
|
||||
|
||||
// 각 값은 실제 시드된 레코드의 키와 일치
|
||||
$post = Post::query()->where('title', 'API 문서 샘플 게시글')->firstOrFail();
|
||||
$comment = Comment::query()->where('content', 'API 문서 샘플 댓글입니다.')->firstOrFail();
|
||||
$attachment = Attachment::query()->where('original_filename', 'apidoc-sample.png')->firstOrFail();
|
||||
|
||||
$this->assertSame((string) $post->getKey(), $params['id']);
|
||||
$this->assertSame((string) $post->getKey(), $params['postId']);
|
||||
$this->assertSame((string) $comment->getKey(), $params['commentId']);
|
||||
$this->assertSame((string) $attachment->hash, $params['hash']);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function 대표_샘플_게시판은_공개_게시글과_댓글과_첨부를_갖는다(): void
|
||||
{
|
||||
(new ApiDocSampleService)->seed();
|
||||
|
||||
$board = Board::query()->where('slug', self::SAMPLE_SLUG)->firstOrFail();
|
||||
$post = Post::query()->where('board_id', $board->id)->where('title', 'API 문서 샘플 게시글')->firstOrFail();
|
||||
|
||||
$this->assertTrue((bool) $board->is_active);
|
||||
$this->assertFalse((bool) $post->is_secret);
|
||||
$this->assertSame('published', $post->status->value);
|
||||
$this->assertSame(1, Comment::query()->where('post_id', $post->id)->count());
|
||||
$this->assertSame(1, Attachment::query()->where('post_id', $post->id)->count());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function 게시판별_권한이_admin_역할에_등록되어_실측_사용자가_접근할_수_있다(): void
|
||||
{
|
||||
(new ApiDocSampleService)->seed();
|
||||
|
||||
// ensureBoardPermissions 로 게시판별 권한이 생성됨 (posts.read 등)
|
||||
$this->assertDatabaseHas('permissions', [
|
||||
'identifier' => 'sirsoft-board.'.self::SAMPLE_SLUG.'.posts.read',
|
||||
]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function 재실행_시_샘플이_중복_생성되지_않는다(): void
|
||||
{
|
||||
$service = new ApiDocSampleService;
|
||||
|
||||
$service->seed();
|
||||
$service->seed();
|
||||
|
||||
$this->assertSame(1, Board::query()->where('slug', self::SAMPLE_SLUG)->count());
|
||||
$this->assertSame(1, Post::query()->where('title', 'API 문서 샘플 게시글')->count());
|
||||
$this->assertSame(1, Comment::query()->where('content', 'API 문서 샘플 댓글입니다.')->count());
|
||||
$this->assertSame(1, Attachment::query()->where('original_filename', 'apidoc-sample.png')->count());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
# Addresses API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Addresses 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/addresses
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.addresses.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.addresses.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserAddressController@index`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| addresses | object | `{"data":[{"id":263,"user_id":"a1e0a91a-fba6-491c-a53e-728…` | 회원 본인 소유 배송지 컬렉션 (`data[]` 배송지 항목 배열 + `abilities.can_create` — UserAddressCollection 파생) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원 본인의 배송지 목록을 조회합니다. `auth:sanctum` 인증이 필요하며, `UserAddressService::getUserAddresses()`가 현재 사용자(`Auth::id()`) 소유의 배송지를 조회해 `UserAddressCollection`으로 반환합니다. 마이페이지 배송지 관리 화면이나 주문 시 배송지 선택 목록을 채우는 용도이며, 다른 회원의 배송지는 노출되지 않습니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/user/addresses
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.addresses.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.addresses.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserAddressController@store`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | string | 예 | max 100 | 대상의 이름/명칭 |
|
||||
| recipient_name | body | string | 예 | max 50 | 수령인 이름 |
|
||||
| recipient_phone | body | string | 예 | max 20 | 수령인 연락처 |
|
||||
| country_code | body | string | 아니오 | — | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| zipcode | body | string | 아니오 | max 10 | 우편번호 |
|
||||
| province_code | body | string | 아니오 | max 10 | 광역 시·도 코드 (국내 주소 지역 구분) |
|
||||
| city | body | string | 아니오 | max 100 | 시·군·구 등 도시명 |
|
||||
| address | body | string | 아니오 | max 255 | 기본 주소 |
|
||||
| address_detail | body | string | 아니오 | max 255 | 상세 주소 |
|
||||
| address_type_code | body | string | 아니오 | `R`, `J` | 국내 주소 표기 방식 (`R` 도로명 / `J` 지번) |
|
||||
| address_line_1 | body | string | 아니오 | max 255 | 주소 1행 (기본 주소) |
|
||||
| address_line_2 | body | string | 아니오 | max 255 | 주소 2행 (상세 주소) |
|
||||
| intl_city | body | string | 아니오 | max 100 | 도시 (국제 주소) |
|
||||
| intl_state | body | string | 아니오 | max 100 | 주/도 (국제 주소) |
|
||||
| intl_postal_code | body | string | 아니오 | max 20 | 우편번호 (국제 주소) |
|
||||
| is_default | body | boolean | 아니오 | — | 기본값 지정 여부 |
|
||||
| force_overwrite | body | boolean | 아니오 | — | 동일 배송지명 존재 시 기존 항목 덮어쓰기 허용 (미지정 시 중복이면 409) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.user_address.store_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원 본인의 새 배송지를 등록합니다. `auth:sanctum` 인증이 필요하며, `UserAddressService::createAddress()`가 검증된 요청에 현재 사용자 ID를 결합해 배송지를 생성하고 성공 시 `201`로 반환합니다. 국내(우편번호/도로명·지번)·해외(intl_* 필드) 주소를 모두 지원하고 `is_default`로 기본 배송지 지정이 가능합니다. 같은 이름의 배송지가 있으면 `409`(중복 ID 포함)를, `force_overwrite`로 덮어쓰기를 허용할 수 있으며, 최대 배송지 개수를 초과하면 `422`를 반환합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/user/addresses/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.addresses.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.addresses.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserAddressController@destroy`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원 본인의 배송지 1건을 삭제합니다. `auth:sanctum` 인증이 필요하며, `UserAddressService::deleteAddress()`가 현재 사용자 소유 여부를 확인한 뒤 path의 `{id}` 배송지를 삭제합니다. 본인 소유가 아니거나 존재하지 않는 배송지이면 `404`를 반환합니다. 마이페이지 배송지 관리에서 더 이상 사용하지 않는 배송지를 제거하는 용도입니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/addresses/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.addresses.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.addresses.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserAddressController@show`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원 본인의 배송지 1건 상세를 조회합니다. `auth:sanctum` 인증이 필요하며, `UserAddressService::getAddress()`가 현재 사용자 소유의 path `{id}` 배송지를 조회해 `UserAddressResource`로 반환합니다. 본인 소유가 아니거나 존재하지 않는 배송지이면 `404`를 반환합니다. 배송지 수정 화면 진입 시 기존 값을 불러오는 용도입니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/user/addresses/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.addresses.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.addresses.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserAddressController@update`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| name | body | string | 아니오 | max 100 | 대상의 이름/명칭 |
|
||||
| recipient_name | body | string | 아니오 | max 50 | 수령인 이름 |
|
||||
| recipient_phone | body | string | 아니오 | max 20 | 수령인 연락처 |
|
||||
| country_code | body | string | 아니오 | — | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| zipcode | body | string | 아니오 | max 10 | 우편번호 |
|
||||
| province_code | body | string | 아니오 | max 10 | 광역 시·도 코드 (국내 주소 지역 구분) |
|
||||
| city | body | string | 아니오 | max 100 | 시·군·구 등 도시명 |
|
||||
| address | body | string | 아니오 | max 255 | 기본 주소 |
|
||||
| address_detail | body | string | 아니오 | max 255 | 상세 주소 |
|
||||
| address_type_code | body | string | 아니오 | `R`, `J` | 국내 주소 표기 방식 (`R` 도로명 / `J` 지번) |
|
||||
| address_line_1 | body | string | 아니오 | max 255 | 주소 1행 (기본 주소) |
|
||||
| address_line_2 | body | string | 아니오 | max 255 | 주소 2행 (상세 주소) |
|
||||
| intl_city | body | string | 아니오 | max 100 | 도시 (국제 주소) |
|
||||
| intl_state | body | string | 아니오 | max 100 | 주/도 (국제 주소) |
|
||||
| intl_postal_code | body | string | 아니오 | max 20 | 우편번호 (국제 주소) |
|
||||
| is_default | body | boolean | 아니오 | — | 기본값 지정 여부 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.user_address.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원 본인의 배송지 1건을 수정합니다. `auth:sanctum` 인증이 필요하며, `UserAddressService::updateAddress()`가 현재 사용자 소유의 path `{id}` 배송지를 검증된 값으로 갱신하고 `UserAddressResource`로 반환합니다. 모든 본문 필드는 선택이며 전달된 필드만 갱신되고, 국내·해외 주소 필드와 `is_default`(기본 배송지 지정)를 모두 지원합니다. 본인 소유가 아니거나 존재하지 않는 배송지이면 `404`를 반환합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/user/addresses/{id}/default
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.addresses.set-default -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.addresses.set-default`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserAddressController@setDefault`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원 본인의 배송지 1건을 기본 배송지로 지정합니다. `auth:sanctum` 인증이 필요하며, `UserAddressService::setDefaultAddress()`가 현재 사용자 소유의 path `{id}` 배송지를 기본으로 설정하고 기존 기본 배송지는 자동 해제됩니다. 본인 소유가 아니거나 존재하지 않는 배송지이면 `404`를 반환합니다. 마이페이지 배송지 목록에서 기본 배송지를 전환하는 용도입니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
# Brands API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Brands 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/brands
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.brands.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.brands.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\BrandController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.brands.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| is_active | query | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| search | query | string | 아니오 | max 100 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
|
||||
| sort | query | string | 아니오 | `name_asc`, `name_desc`, `created_asc`, `created_desc` | 정렬 기준 (필드명, `-` 접두 시 내림차순) |
|
||||
| sort_by | query | string | 아니오 | `name`, `sort_order` | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| locale | query | string | 아니오 | `ko`, `en`, `fr`, `ja` | 로케일 코드 (표시 언어/지역) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `43` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | integer | `127` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"API 문서 샘플 브랜드","en":"API Doc Sample Brand"}` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| localized_name | string | `API 문서 샘플 브랜드` | `name` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| slug | string | `apidoc-sample-brand` | URL 친화 식별자 (slug) |
|
||||
| url | string | `apidoc-sample-brand` | SortableMenuItem 표시용 URL (slug 값을 그대로 노출) |
|
||||
| website | string | `https://www.asus.com` | 브랜드 공식 웹사이트 URL |
|
||||
| sort_order | integer | `0` | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| icon | string | `tag` | 아이콘 식별자 (아이콘 클래스/이름) |
|
||||
| created_at | string | `2026-07-07 14:47:31` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-07 14:47:31` | 최종 수정 일시 |
|
||||
| creator | array | `[]` | 생성자 정보 객체 (uuid/name/email — creator 관계 파생) |
|
||||
| updater | array | `[]` | 수정자 정보 객체 (id/name — updater 관계 파생, 로드 시에만 포함) |
|
||||
| products_count | integer | `0` | products 개수 (집계) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.brands.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자용 브랜드 목록을 조회합니다. `auth:sanctum` + `sirsoft-ecommerce.brands.read` 권한이 필요하며, `BrandService::getAllBrands()`가 검증된 필터를 받아 조회합니다. `is_active`·`search`로 필터링하고 `sort`(name_asc/desc, created_asc/desc) 또는 `sort_by`+`sort_order` 조합으로 정렬하며, `locale`로 표시 언어를 지정할 수 있습니다. 각 항목에는 `products_count` 집계와 현재 사용자의 `abilities` 맵이 포함됩니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/brands
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.brands.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.brands.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\BrandController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.brands.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| slug | body | string | 예 | max 200 | URL 친화 식별자 (slug) |
|
||||
| website | body | string | 아니오 | max 500 | 브랜드 공식 웹사이트 URL |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.brand.create_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.brands.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 새 브랜드를 생성합니다. `auth:sanctum` + `sirsoft-ecommerce.brands.create` 권한이 필요하며, `BrandService::createBrand()`가 트랜잭션 내에서 저장하고 생성자/수정자(`created_by`/`updated_by`)를 현재 사용자로 기록한 뒤 `BrandResource`를 201로 반환합니다. `name`(다국어 배열)과 `slug`가 필수이며 `website`·`sort_order`·`is_active`는 선택입니다. `sirsoft-ecommerce.brand.create_validation_rules` 필터로 확장이 검증 규칙을 추가할 수 있습니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/brands/{brand}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.brands.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.brands.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\BrandController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.brands.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| brand | path | string | 예 | — | 대상 brand의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.brands.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 브랜드 1건을 삭제합니다. `auth:sanctum` + `sirsoft-ecommerce.brands.delete` 권한이 필요하며, `BrandService::deleteBrand()`가 삭제 전 연결된 상품 수를 확인합니다. 연결된 상품이 1개 이상이면 예외가 발생해 삭제가 차단되고 400 오류가 반환되므로, 해당 브랜드의 상품을 먼저 정리하거나 다른 브랜드로 이전해야 삭제할 수 있습니다. 대상이 없으면 404를 반환합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/brands/{brand}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.brands.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.brands.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\BrandController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.brands.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| brand | path | string | 예 | — | 대상 brand의 식별자 |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| slug | body | string | 아니오 | — | URL 친화 식별자 (slug) |
|
||||
| website | body | string | 아니오 | max 500 | 브랜드 공식 웹사이트 URL |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.brand.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.brands.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 기존 브랜드(path의 `brand`)를 수정합니다. `auth:sanctum` + `sirsoft-ecommerce.brands.update` 권한이 필요하며, `BrandService::updateBrand()`가 검증된 데이터로 갱신한 뒤 `BrandResource`를 반환합니다. `name`은 필수이고 `slug`·`website`·`sort_order`·`is_active`는 선택입니다. 대상이 없거나 처리 중 예외가 발생하면 404 또는 400을 반환하며, `sirsoft-ecommerce.brand.update_validation_rules` 필터로 확장이 검증 규칙을 추가할 수 있습니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/brands/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.brands.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.brands.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\BrandController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.brands.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.brands.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 브랜드 1건의 상세 정보를 조회합니다. `auth:sanctum` + `sirsoft-ecommerce.brands.read` 권한이 필요하며, path의 `id`로 `BrandService::getBrand()`를 호출해 단건을 `BrandResource`로 반환합니다. 응답에는 다국어 이름, 로컬라이즈된 이름(`localized_name`), `website`, `products_count` 집계, 현재 사용자의 `abilities` 맵이 포함됩니다. 대상 브랜드가 없으면 404를 반환합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/brands/{id}/toggle-status
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.brands.toggle-status -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.brands.toggle-status`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\BrandController@toggleStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.brands.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.brands.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 브랜드의 활성 상태를 토글합니다. `auth:sanctum` + `sirsoft-ecommerce.brands.update` 권한이 필요하며, path의 `id`로 `BrandService::toggleStatus()`를 호출해 트랜잭션 내에서 현재 `is_active` 값을 반전시킨 뒤 갱신된 `BrandResource`를 반환합니다. 관리자 목록에서 브랜드 노출/비노출을 빠르게 전환할 때 사용하며, 대상이 없거나 처리 중 예외가 발생하면 404 또는 400을 반환합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,338 @@
|
||||
# Cart API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Cart 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/cart
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.cart.destroy-multiple -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.cart.destroy-multiple`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CartController@destroyMultiple`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | query | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.cart.delete_items_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 장바구니에서 선택한 여러 아이템(`ids`)을 한 번에 삭제합니다. `optional.sanctum`으로 회원은 `Auth::id()`, 비회원은 cart_key(`X-Cart-Key`)로 소유를 식별하며, `CartController@destroyMultiple`이 `CartService::deleteItems()`를 호출해 삭제된 건수(`deleted_count`)를 반환합니다. 장바구니 화면에서 체크박스로 선택한 항목들을 "선택 삭제"할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/cart
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.cart.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.cart.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CartController@index`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| selected_ids | query | array | 아니오 | — | selected 식별자 배열 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.cart.get_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| items | array | `[{"id":962,"product_id":201,"product_option_id":1086,"qua…` | 장바구니 라인 아이템 목록 (상품·옵션·수량 등 — CartItemResource 파생) |
|
||||
| item_ids | array | `[962]` | item 식별자 배열 (연관 리소스 참조) |
|
||||
| item_count | integer | `1` | item 개수 (집계) |
|
||||
| calculation | object | `{"items":[{"product_id":201,"product_option_id":1086,"pro…` | 선택 아이템 기준 금액 계산 결과 (상품 소계·할인·배송비 등 — OrderCalculationResult 파생) |
|
||||
| has_unshippable_items | boolean | `false` | unshippable items 여부 |
|
||||
| selected_shipping_country | string | `KR` | 배송비 계산에 적용된 배송 국가 코드 (ResolveShippingCountry 해석 결과) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 장바구니 목록과 함께 가격 정보(소계·할인·배송비 등 `calculation`)를 계산해 반환합니다. `optional.sanctum`으로 회원은 `Auth::id()`, 비회원은 cart_key(`X-Cart-Key`)로 장바구니를 식별하며, `CartController@index`가 `CartService::getCartWithCalculation()`을 호출합니다. `selected_ids`를 전달하면 해당 아이템만 계산에 포함되고(미전달=전체, 빈 배열=계산 생략), 선택된 배송 국가로 배송 불가한 상품이 있으면 `has_unshippable_items`가 true가 됩니다. 비회원인데 cart_key가 없거나 형식(`ck_`+32자)이 틀리면 400을 반환합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/cart
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.cart.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.cart.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CartController@store`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| product_id | body | integer | 예 | — | product 식별자 |
|
||||
| items | body | array | 예 | min 1 | 처리 대상 항목 배열 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.cart.bulk_add_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 하나의 상품에 대해 단일 또는 여러 옵션 조합을 `items[]` 배열로 한 번에 장바구니에 담습니다. `optional.sanctum`으로 회원/비회원 모두 접근하며, `CartController@store`가 `CartService::bulkAddToCart()`를 호출한 뒤 추가된 아이템 목록과 총 담긴 수량(`cart_count`)을 201로 반환합니다. 재고 부족·판매 중지·구매 대상 제한·구매 수량 한도 위반은 사유별 422(cart_unavailable/purchase_not_allowed), 항목/권한/옵션 문제는 404/403/422로 매핑됩니다. 비회원은 cart_key(`X-Cart-Key`) 검증을 통과해야 합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/cart/all
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.cart.destroy-all -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.cart.destroy-all`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CartController@destroyAll`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). <!-- TODO: 도메인 특이 에러가 있으면 보강 -->_
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 현재 회원/비회원 장바구니의 모든 아이템을 삭제해 장바구니를 비웁니다. `optional.sanctum`으로 회원은 `Auth::id()`, 비회원은 cart_key로 대상을 식별하며, `CartController@destroyAll`이 `CartService::deleteAll()`을 호출해 삭제된 건수(`deleted_count`)를 반환합니다. 장바구니 화면의 "전체 비우기" 동작에 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/cart/count
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.cart.count -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.cart.count`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CartController@count`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| selected_ids | query | array | 아니오 | — | selected 식별자 배열 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.cart.get_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| count | integer | `1` | 장바구니에 담긴 아이템 개수 (`selected_ids` 지정 시 해당 항목만 집계) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 장바구니에 담긴 아이템 개수(`count`)만 가볍게 조회합니다. `optional.sanctum`으로 회원/비회원 모두 접근하며, `CartController@count`가 `CartService::getItemCount()`를 호출합니다. 전체 목록·계산 결과가 필요 없는 헤더의 장바구니 배지 카운트 갱신 등에 사용하며, `selected_ids`로 특정 아이템만 집계할 수도 있습니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/cart/key
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.cart.key -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.cart.key`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CartController@issueCartKey`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). <!-- TODO: 도메인 특이 에러가 있으면 보강 -->_
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 비회원 장바구니를 식별하기 위한 cart_key(`ck_`+32자 영숫자)를 발급합니다. 인증이 필요 없으며(`optional.sanctum`), `CartController@issueCartKey`가 `CartService::issueCartKey()`로 키를 생성해 반환합니다. 비회원은 이 키를 `X-Cart-Key` 헤더에 실어 이후 장바구니 담기·조회·수정 요청에서 자신의 장바구니를 식별합니다. 비회원 쇼핑 시작 시점(첫 장바구니 담기 전)에 한 번 호출해 클라이언트에 저장해 둡니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/cart/merge
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.cart.merge -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.cart.merge`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CartController@merge`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). <!-- TODO: 도메인 특이 에러가 있으면 보강 -->_
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 비회원 상태에서 담아 둔 장바구니를 로그인한 회원 계정으로 병합합니다. 로그인 직후 클라이언트가 보유한 cart_key(`X-Cart-Key`)를 실어 호출하면, `CartController@merge`가 `CartService::mergeGuestCartToUser()`로 해당 cart_key의 비회원 아이템을 회원 장바구니로 옮기고 병합된 건수(`merged_count`)를 반환합니다. 비회원으로 담던 상품이 로그인 후 사라지지 않도록 인증 성공 시점에 1회 호출합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/cart/query
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.cart.query -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.cart.query`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CartController@index`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| selected_ids | body | array | 아니오 | — | selected 식별자 배열 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.cart.get_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** GET `/cart`와 동일하게 장바구니 목록과 가격 계산 결과를 반환하되, `selected_ids`를 GET 쿼리 대신 POST 본문으로 전달하는 변형 엔드포인트입니다(같은 `CartController@index` 처리). 선택 아이템 배열이 커서 URL 길이 제한이 우려되는 경우에 사용합니다. `optional.sanctum`으로 회원/비회원 모두 접근하며, 응답 구조(`items`·`calculation`·`has_unshippable_items` 등)는 GET 조회와 동일합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/cart/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.cart.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.cart.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CartController@destroy`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 장바구니에서 단일 아이템(`id`)을 삭제합니다. `optional.sanctum`으로 회원은 `Auth::id()`, 비회원은 cart_key(`X-Cart-Key`)로 소유를 식별하며, `CartController@destroy`가 `CartService::deleteItem()`을 호출합니다. 존재하지 않는 항목은 404, 타인 소유 항목 삭제 시도는 403(사유별 `CartOperationException` 매핑)으로 반환합니다. 장바구니 각 행의 개별 삭제 버튼에 사용합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/cart/{id}/option
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.cart.change-option -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.cart.change-option`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CartController@changeOption`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| product_option_id | body | integer | 예 | — | product option 식별자 |
|
||||
| quantity | body | integer | 예 | min 1, max 9999 | 변경할 구매 수량 (1~9999) |
|
||||
| additional_option_selections | body | array | 아니오 | — | 추가 옵션 재선택 목록 (항목별 additional_option_id/value_id, 직접입력 custom_text — 미전달 시 기존 선택 유지) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.cart.change_option_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 장바구니 아이템(`id`)의 선택 옵션과 수량을 변경합니다. `optional.sanctum`으로 회원/비회원 모두 접근하며, `CartController@changeOption`이 `CartService::changeOption()`으로 `product_option_id`·`quantity`(및 추가 옵션 선택)를 반영한 뒤 수정된 아이템을 반환합니다. 다른 상품의 옵션으로 바꾸려 하거나 옵션이 없는 경우, 재고/판매상태/구매수량 한도 위반은 사유별 422/404/403으로 매핑됩니다. 장바구니에서 옵션(예: 색상/사이즈)을 바꿀 때 사용합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/cart/{id}/quantity
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.cart.update-quantity -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.cart.update-quantity`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CartController@updateQuantity`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| quantity | body | integer | 예 | min 1, max 9999 | 변경할 구매 수량 (1~9999) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.cart.update_quantity_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 장바구니 아이템(`id`)의 수량만 변경합니다. `optional.sanctum`으로 회원/비회원 모두 접근하며, `CartController@updateQuantity`가 `CartService::updateQuantity()`로 수량을 반영한 뒤 프론트가 별도 refetch 없이 화면을 갱신할 수 있도록 `index`와 동일한 전체 목록·계산 결과(`items`·`calculation`)를 함께 반환합니다. 수량은 1~9999 범위이며, 재고 부족·판매 중지·구매수량 한도 위반은 사유별 422, 항목/권한 문제는 404/403으로 매핑됩니다. 장바구니의 수량 증감(+/-) 컨트롤에 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,513 @@
|
||||
# Categories API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Categories 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/categories
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.categories.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.categories.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CategoryController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.categories.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| parent_id | query | string | 아니오 | — | parent 식별자 |
|
||||
| is_active | query | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| search | query | string | 아니오 | max 100 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
|
||||
| hierarchical | query | boolean | 아니오 | — | true 면 자식을 중첩한 트리 구조로 반환 |
|
||||
| flat | query | boolean | 아니오 | — | true 면 깊이 들여쓰기를 포함한 평면 리스트로 반환 (TagInput 등에 사용) |
|
||||
| max_depth | query | integer | 아니오 | min 1, max 10 | 조회할 최대 계층 깊이 제한 (1~10) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `87` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"의류","en":"Clothing"}` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| description | object | `{"ko":"다양한 스타일의 의류 제품","en":"Various styles of clothing p…` | 설명 (다국어 필드는 로케일별 값 객체) |
|
||||
| localized_name | string | `의류` | `name` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| parent_id | null | `null` | parent 식별자 (연관 리소스 참조) |
|
||||
| path | string | `87` | 조상부터 자기 자신까지의 ID를 `/`로 이은 materialized path (조상 조회·하위 일괄 선택에 사용) |
|
||||
| depth | integer | `0` | 계층 트리에서의 깊이 (0 = 최상위, 하위로 갈수록 증가) |
|
||||
| sort_order | integer | `0` | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| slug | string | `clothing` | URL 친화 식별자 (slug) |
|
||||
| url | string | `clothing` | SortableMenuItem 표시용 URL (slug 값을 그대로 사용) |
|
||||
| icon | string | `folder` | 아이콘 식별자 (아이콘 클래스/이름) |
|
||||
| meta_title | null | `null` | SEO 메타 제목 (검색엔진/소셜 공유 표시 제목, 미설정 시 null) |
|
||||
| meta_description | null | `null` | SEO 메타 설명 (검색엔진/소셜 공유 표시 요약, 미설정 시 null) |
|
||||
| created_at | string | `2026-06-15 02:24:00` | 생성 일시 |
|
||||
| updated_at | string | `2026-06-15 02:24:00` | 최종 수정 일시 |
|
||||
| images | array | `[]` | 카테고리 이미지 배열 (images 관계 로드 시 — id/hash/download_url/alt_text 등) |
|
||||
| products_count | integer | `22` | products 개수 (집계) |
|
||||
| children_count | integer | `0` | children 개수 (집계) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.categories.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자용 카테고리 목록을 조회합니다. `auth:sanctum` + `sirsoft-ecommerce.categories.read` 권한이 필요하며, `CategoryService::getHierarchicalCategories()`가 검증된 필터(`parent_id`/`is_active`/`search`/`max_depth`)를 받아 조회합니다. `hierarchical=true`면 자식을 중첩한 트리, `flat=true`면 평면 리스트(TagInput 등에 사용), 둘 다 없으면 기본 계층 구조를 반환합니다. 각 항목에는 `products_count`·`children_count` 집계와 현재 사용자의 `abilities` 맵이 포함됩니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/categories
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.categories.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.categories.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CategoryController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.categories.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| description | body | array | 아니오 | — | 설명 |
|
||||
| parent_id | body | string | 아니오 | — | parent 식별자 |
|
||||
| slug | body | string | 예 | max 200 | URL 친화 식별자 (slug) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| meta_title | body | string | 아니오 | max 200 | SEO 메타 제목 (검색엔진/소셜 공유 표시 제목) |
|
||||
| meta_description | body | string | 아니오 | — | SEO 메타 설명 (검색엔진/소셜 공유 표시 요약) |
|
||||
| temp_key | body | string | 아니오 | max 64 | 저장 전 임시 업로드한 이미지를 이 카테고리에 연결하기 위한 FileUploader temp_key |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.category.create_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.categories.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 새 카테고리를 생성합니다. `auth:sanctum` + `sirsoft-ecommerce.categories.create` 권한이 필요하며, `CategoryService::createCategory()`가 검증된 데이터로 저장한 뒤 `CategoryResource`를 201로 반환합니다. `name`(다국어 배열)과 `slug`는 필수이고, `parent_id`를 지정하면 해당 카테고리의 하위로 배치되어 path/depth가 계산됩니다. `temp_key`로 사전 업로드해 둔 임시 이미지를 이 시점에 카테고리에 연결할 수 있으며, `sirsoft-ecommerce.category.create_validation_rules` 필터로 확장이 추가 파라미터를 검증에 주입할 수 있습니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/categories/images
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.categories.images.upload-temp -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.categories.images.upload-temp`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CategoryController@uploadImage`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.categories.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| file | body | file | 예 | max 10240 | 업로드 파일 |
|
||||
| temp_key | body | string | 아니오 | max 64 | 사전 업로드한 임시 이미지를 이 카테고리에 연결하기 위한 FileUploader temp_key |
|
||||
| collection | body | string | 아니오 | max 100 | 첨부 컬렉션 그룹명 (첨부를 용도별로 묶는 키, 미지정 시 default) |
|
||||
| alt_text | body | array | 아니오 | — | 이미지 대체 텍스트 (접근성/이미지 미표시 시 대체 문구) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.category-image.filter_upload_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.categories.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 카테고리에 아직 귀속되지 않은 이미지를 임시로 업로드합니다. `auth:sanctum` + `sirsoft-ecommerce.categories.update` 권한이 필요하며, path에 `categoryId`가 없으므로 `CategoryImageService::upload()`가 `temp_key` 기준의 임시 이미지로 저장합니다. 카테고리 생성/수정 폼에서 저장 전에 이미지를 먼저 올릴 때 사용하며, 이후 store/update 요청에 같은 `temp_key`를 전달하면 해당 카테고리에 연결됩니다. 응답은 FileUploader 컴포넌트가 기대하는 `data.data` 형식으로 업로드 이미지의 id/hash/download_url 등을 201로 반환합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/categories/images/reorder
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.categories.images.reorder -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.categories.images.reorder`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CategoryController@reorderImages`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.categories.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order | body | array | 예 | min 1 | 이미지 순서 배열 (각 항목 `{id, order}` — 이미지 id별 새 정렬 순서) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.category-image.filter_reorder_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.categories.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 카테고리 이미지들의 표시 순서를 일괄 변경합니다. `auth:sanctum` + `sirsoft-ecommerce.categories.update` 권한이 필요하며, `order` 배열(각 항목 `{id, order}`)을 받아 컨트롤러가 `id => order` 맵으로 변환한 뒤 `CategoryImageService::reorder()`에 전달합니다. 여러 이미지를 등록한 카테고리에서 드래그로 순서를 재배열할 때 사용하며, `sirsoft-ecommerce.category-image.filter_reorder_validation_rules` 필터로 확장이 검증 규칙을 추가할 수 있습니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/categories/images/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.categories.images.delete -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.categories.images.delete`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CategoryController@deleteImage`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.categories.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.categories.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 카테고리 이미지 1건을 삭제합니다. `auth:sanctum` + `sirsoft-ecommerce.categories.update` 권한이 필요하며, path의 이미지 `id`로 `CategoryImageService::delete()`를 호출해 레코드와 저장 파일을 제거합니다. 대상 이미지가 존재하지 않으면 404를 반환합니다. 카테고리 편집 화면에서 등록된 이미지나 임시 업로드 이미지를 개별 제거할 때 사용합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/categories/order
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.categories.reorder -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.categories.reorder`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CategoryController@reorder`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.categories.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| parent_menus | body | array | 아니오 | — | 최상위 카테고리 순서 배열 (SortableMenuList — 각 항목 `{id, order}`, child_menus 없으면 필수) |
|
||||
| child_menus | body | array | 아니오 | — | 부모 ID별 자식 카테고리 순서 맵 (`{부모id: [{id, order}, ...]}`, parent_menus 없으면 필수) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.category.reorder_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.categories.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 카테고리 트리 전체의 배치(부모-자식 관계와 정렬 순서)를 일괄 갱신합니다. `auth:sanctum` + `sirsoft-ecommerce.categories.update` 권한이 필요하며, SortableMenuList 컴포넌트가 보내는 `parent_menus`/`child_menus` 형식을 컨트롤러가 `{id, parent_id, sort_order}` 목록으로 변환해 `CategoryService::reorder()`(트랜잭션)에 전달합니다. `parent_id`가 바뀐 항목은 depth와 materialized path가 함께 재계산됩니다. 관리자 카테고리 관리 화면에서 드래그 앤 드롭으로 계층 구조를 재정렬할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/categories/tree
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.categories.tree -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.categories.tree`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CategoryController@tree`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.categories.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `87` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"의류","en":"Clothing"}` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| description | object | `{"ko":"다양한 스타일의 의류 제품","en":"Various styles of clothing p…` | 설명 (다국어 필드는 로케일별 값 객체) |
|
||||
| localized_name | string | `의류` | `name` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| parent_id | null | `null` | parent 식별자 (연관 리소스 참조) |
|
||||
| path | string | `87` | 조상부터 자기 자신까지의 ID를 `/`로 이은 materialized path (조상 조회·하위 일괄 선택에 사용) |
|
||||
| depth | integer | `0` | 계층 트리에서의 깊이 (0 = 최상위, 하위로 갈수록 증가) |
|
||||
| sort_order | integer | `0` | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| slug | string | `clothing` | URL 친화 식별자 (slug) |
|
||||
| url | string | `clothing` | SortableMenuItem 표시용 URL (slug 값을 그대로 사용) |
|
||||
| icon | string | `folder` | 아이콘 식별자 (아이콘 클래스/이름) |
|
||||
| meta_title | null | `null` | SEO 메타 제목 (검색엔진/소셜 공유 표시 제목, 미설정 시 null) |
|
||||
| meta_description | null | `null` | SEO 메타 설명 (검색엔진/소셜 공유 표시 요약, 미설정 시 null) |
|
||||
| created_at | string | `2026-06-15 02:24:00` | 생성 일시 |
|
||||
| updated_at | string | `2026-06-15 02:24:00` | 최종 수정 일시 |
|
||||
| parent | null | `null` | 상위 항목 객체 (parent 관계 파생) |
|
||||
| children | array | `[{"id":88,"name":{"ko":"남성","en":"Men"},"description":{"k…` | 하위 항목 배열 (계층 트리 — children 관계 파생) |
|
||||
| images | array | `[]` | 카테고리 이미지 배열 (images 관계 로드 시 — id/hash/download_url/alt_text 등) |
|
||||
| products_count | integer | `22` | products 개수 (집계) |
|
||||
| children_count | integer | `2` | children 개수 (집계) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.categories.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 상품 등록 폼용 카테고리 트리를 조회합니다. `auth:sanctum` + `sirsoft-ecommerce.categories.read` 권한이 필요하며, 별도 파라미터 없이 `CategoryService::getHierarchicalCategories(['hierarchical' => true, 'is_active' => true])`를 호출해 활성 카테고리만 자식을 중첩한 트리로 반환합니다. index 엔드포인트와 달리 필터를 받지 않고 항상 활성 트리를 반환하므로, 상품 작성/수정 시 카테고리 선택 UI를 채우는 용도로 사용됩니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/categories/{categoryId}/images
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.categories.images.upload -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.categories.images.upload`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CategoryController@uploadImage`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.categories.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| categoryId | path | string | 예 | — | 대상 category의 식별자 |
|
||||
| file | body | file | 예 | max 10240 | 업로드 파일 |
|
||||
| temp_key | body | string | 아니오 | max 64 | 사전 업로드한 임시 이미지를 이 카테고리에 연결하기 위한 FileUploader temp_key |
|
||||
| collection | body | string | 아니오 | max 100 | 첨부 컬렉션 그룹명 (첨부를 용도별로 묶는 키, 미지정 시 default) |
|
||||
| alt_text | body | array | 아니오 | — | 이미지 대체 텍스트 (접근성/이미지 미표시 시 대체 문구) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.category-image.filter_upload_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.categories.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 카테고리(path의 `categoryId`)에 이미지 1건을 업로드해 즉시 귀속시킵니다. `auth:sanctum` + `sirsoft-ecommerce.categories.update` 권한이 필요하며, `CategoryImageService::upload()`가 `categoryId`와 함께 파일을 저장하므로 임시 업로드와 달리 해당 카테고리에 바로 연결됩니다. 대상 카테고리가 없으면 404를 반환하고, 응답은 FileUploader가 기대하는 `data.data` 형식으로 업로드 이미지 정보를 201로 반환합니다. 이미 존재하는 카테고리를 편집하며 이미지를 추가할 때 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/categories/{category}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.categories.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.categories.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CategoryController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.categories.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| category | path | string | 예 | — | 분류 필터 (해당 분류의 항목만 조회) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.categories.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 카테고리 1건을 삭제합니다. `auth:sanctum` + `sirsoft-ecommerce.categories.delete` 권한이 필요하며, `CategoryService::deleteCategory()`가 삭제 전 안전 검사를 수행합니다. 하위 카테고리가 있거나 연결된 상품이 존재하면 예외가 발생해 삭제가 차단되고 400 오류가 반환되므로, 자식과 상품을 먼저 정리해야 삭제할 수 있습니다. 대상이 없으면 404를 반환합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/categories/{category}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.categories.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.categories.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CategoryController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.categories.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| category | path | string | 예 | — | 분류 필터 (해당 분류의 항목만 조회) |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| description | body | array | 아니오 | — | 설명 |
|
||||
| parent_id | body | string | 아니오 | — | parent 식별자 |
|
||||
| slug | body | string | 예 | max 200 | URL 친화 식별자 (slug) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| meta_title | body | string | 아니오 | max 200 | SEO 메타 제목 (검색엔진/소셜 공유 표시 제목) |
|
||||
| meta_description | body | string | 아니오 | — | SEO 메타 설명 (검색엔진/소셜 공유 표시 요약) |
|
||||
| temp_key | body | string | 아니오 | max 64 | 저장 전 임시 업로드한 이미지를 이 카테고리에 연결하기 위한 FileUploader temp_key |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.category.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.categories.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 기존 카테고리(path의 `category`)를 수정합니다. `auth:sanctum` + `sirsoft-ecommerce.categories.update` 권한이 필요하며, `CategoryService::updateCategory()`가 검증된 데이터로 갱신한 뒤 `CategoryResource`를 반환합니다. `name`과 `slug`는 필수이고, `parent_id`를 변경하면 계층 위치(path/depth)가 재계산됩니다. `temp_key`로 임시 업로드한 이미지를 이 시점에 연결할 수 있으며, 대상이 없거나 처리 중 예외가 발생하면 404 또는 400을 반환합니다. `sirsoft-ecommerce.category.update_validation_rules` 필터로 확장이 검증 규칙을 추가할 수 있습니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/categories/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.categories.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.categories.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CategoryController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.categories.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.categories.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 카테고리 1건의 상세 정보를 조회합니다. `auth:sanctum` + `sirsoft-ecommerce.categories.read` 권한이 필요하며, path의 `id`로 `CategoryService::getCategory()`를 호출해 단건을 `CategoryResource`로 반환합니다. 응답에는 부모(`parent`)·자식(`children`)·이미지(`images`) 관계와 `products_count`·`children_count` 집계, 현재 사용자의 `abilities` 맵이 포함됩니다. 대상 카테고리가 없으면 404를 반환합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/categories/{id}/toggle-status
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.categories.toggle-status -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.categories.toggle-status`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CategoryController@toggleStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.categories.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.categories.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 카테고리의 활성 상태를 토글합니다. `auth:sanctum` + `sirsoft-ecommerce.categories.update` 권한이 필요하며, path의 `id`로 `CategoryService::toggleStatus()`를 호출해 현재 `is_active` 값을 반전시킨 뒤 갱신된 `CategoryResource`를 반환합니다. 관리자 목록에서 노출/비노출을 빠르게 전환할 때 사용하며, 대상이 없거나 처리 중 예외가 발생하면 404 또는 400을 반환합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/categories
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.categories.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.categories.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CategoryController@index`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `87` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"의류","en":"Clothing"}` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| name_localized | string | `의류` | `name` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| slug | string | `clothing` | URL 친화 식별자 (slug) |
|
||||
| depth | integer | `0` | 계층 트리에서의 깊이 (0 = 최상위, 하위로 갈수록 증가) |
|
||||
| parent_id | null | `null` | parent 식별자 (연관 리소스 참조) |
|
||||
| products_count | integer | `22` | products 개수 (집계) |
|
||||
| children | array | `[{"id":88,"name":{"ko":"남성","en":"Men"},"name_localized":…` | 하위 항목 배열 (계층 트리 — children 관계 파생) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). <!-- TODO: 도메인 특이 에러가 있으면 보강 -->_
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 공개 카테고리 트리를 조회합니다. 인증이 필요 없는 공개 엔드포인트이며, `Public\CategoryController@index`가 `CategoryService::getPublicCategoryTree()`를 호출해 활성 카테고리만 자식을 중첩한 트리로 반환합니다. 각 항목에는 로컬라이즈된 이름(`name_localized`)과 공개 상품 수(`products_count`)가 포함됩니다. 스토어프론트의 카테고리 내비게이션/메뉴를 렌더링하는 데 사용하며, 조회 실패 시 500을 반환합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/categories/{slug}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.categories.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.categories.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CategoryController@show`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| slug | path | string | 예 | — | 대상 리소스의 slug (URL 친화 식별자) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** slug로 단일 공개 카테고리와 직계 자식을 조회합니다. 인증이 필요 없는 공개 엔드포인트이며, `Public\CategoryController@show`가 `CategoryService::getPublicCategoryBySlug()`를 호출해 활성 자식(`activeChildren`)과 이미지를 함께 로드합니다. 조회된 카테고리가 비활성(`is_active=false`)이면 없는 것으로 간주해 404를 반환하며, 응답에는 상위 경로를 나타내는 `breadcrumb` 배열과 `products_count` 집계가 포함됩니다. 스토어프론트 카테고리 상세/목록 페이지 진입 시 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Category Image API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Category Image 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/category-image/{hash}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.category-image.download -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.category-image.download`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CategoryImageController@download`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| hash | path | string | 예 | — | 대상 리소스의 해시 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 공개 API로, 해시(`hash`)로 식별되는 카테고리 이미지 원본 파일을 스트리밍 서빙합니다. 인증이 필요 없으며(`PublicBaseController`), `CategoryImageController@download`가 `CategoryImageService::download()`를 호출해 리포지토리에서 해시로 이미지를 찾고 `StorageInterface::response()`로 `StreamedResponse`를 반환합니다. 응답에는 저장된 `mime_type`과 `Cache-Control: public, max-age=31536000`(1년) 헤더가 부여되어 브라우저/CDN 캐싱에 최적화됩니다. 해시에 해당하는 레코드가 없거나 스토리지에 실제 파일이 없으면 404를, 그 외 처리 오류 시 400 에러 응답을 반환합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
# Checkout API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Checkout 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/checkout
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.checkout.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.checkout.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CheckoutController@destroy`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). <!-- TODO: 도메인 특이 에러가 있으면 보강 -->_
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 주문서 페이지를 이탈할 때 현재 회원/비회원의 임시 주문(temp order)을 삭제합니다. `optional.sanctum`으로 회원은 `Auth::id()`, 비회원은 cart_key(`X-Cart-Key`)로 대상을 식별하며, `CheckoutController@destroy`가 `TempOrderService::deleteTempOrder()`를 호출합니다. 삭제할 임시 주문이 없으면 404를 반환합니다. 주문 확정 없이 주문서에서 뒤로가기·페이지 이탈 시 미완료 임시 데이터를 정리하는 용도입니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/checkout
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.checkout.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.checkout.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CheckoutController@show`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| country_code | query | string | 아니오 | — | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| zipcode | query | string | 아니오 | max 20 | 우편번호 |
|
||||
| region | query | string | 아니오 | max 100 | 지역/권역 |
|
||||
| city | query | string | 아니오 | max 100 | 도시명 (배송비 미리보기 산출용 배송 주소) |
|
||||
| address | query | string | 아니오 | max 255 | 기본 주소 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-404 — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 현재 유효한 임시 주문을 조회하면서 최신 가격으로 실시간 재계산해 주문서 페이지 데이터를 반환합니다. `optional.sanctum`으로 회원/비회원 모두 접근하며, `CheckoutController@show`가 `TempOrderService::getTempOrderWithCalculation()`으로 재계산하고 `CheckoutDataService::buildResponseData()`가 쿠폰·마일리지·상품·구매불가 상품 정보를 포함해 응답을 구성합니다. 쿼리로 `country_code`/`zipcode`/`region` 등 배송 주소를 전달하면 해당 주소 기준 배송비가 계산되며, 우편번호 없이 배송국가만으로도 미리보기 배송비를 산출합니다. 임시 주문이 만료·미존재면 404를 반환합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/checkout
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.checkout.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.checkout.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CheckoutController@store`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| item_ids | body | array | 아니오 | min 1 | item 식별자 배열 |
|
||||
| direct_items | body | array | 아니오 | min 1 | 바로 구매 항목 배열 (장바구니 미경유 — 항목별 product_id/option_values/quantity, item_ids와 택일) |
|
||||
| coupon_issue_ids | body | array | 아니오 | — | coupon issue 식별자 배열 |
|
||||
| use_points | body | integer | 아니오 | min 0 | 사용할 마일리지(적립금) 포인트 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.checkout.validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 장바구니에서 선택한 아이템으로 임시 주문을 생성해 주문서 작성 단계로 진입합니다. `optional.sanctum`으로 회원/비회원 모두 접근하며, `CheckoutController@store`가 `direct_items`가 있으면 `TempOrderService::createTempOrderFromDirectItems()`(바로 구매, 장바구니 미경유), 없으면 `item_ids`로 `createTempOrderFromSelectedItems()`(장바구니 경유)를 호출합니다. 응답에는 임시 주문 ID·계산 결과·만료 시각(`expires_at`)이 포함됩니다. 재고 부족·판매 중지·구매 제한 상품이 있으면 400(cart_unavailable), 보유 잔액을 넘는 마일리지 사용은 422, 빈 장바구니는 400을 반환합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/checkout
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.checkout.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.checkout.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CheckoutController@update`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| item_coupons | body | array | 아니오 | — | 상품별 적용 쿠폰 맵 (상품 옵션 ID를 키로, 발급 쿠폰 ID 배열을 값으로 — 상품당 최대 2개) |
|
||||
| order_coupon_issue_id | body | integer | 아니오 | — | order coupon issue 식별자 |
|
||||
| shipping_coupon_issue_id | body | integer | 아니오 | — | shipping coupon issue 식별자 |
|
||||
| use_points | body | integer | 아니오 | min 0 | 사용할 마일리지(적립금) 포인트 |
|
||||
| zipcode | body | string | 아니오 | max 10 | 우편번호 |
|
||||
| country_code | body | string | 아니오 | — | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| payment_method | body | string | 아니오 | max 50 | 결제 수단 코드 (결제수단별 할인/수수료 계산 확장용) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.checkout.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 주문서 작성 중 쿠폰·마일리지·배송 주소가 변경될 때 임시 주문 금액을 재계산합니다. `optional.sanctum`으로 회원/비회원 모두 접근하며, `CheckoutController@update`가 전송된 프로모션 필드(`item_coupons`·`order_coupon_issue_id`·`shipping_coupon_issue_id`)와 `use_points`만 반영하고 미전송 필드는 `TempOrderService::updateTempOrder()`에서 기존 값을 유지합니다. `zipcode`/`country_code`로 배송 주소를 함께 넘기면 배송비가 다시 계산됩니다. 임시 주문이 만료·미존재면 404, 보유 잔액 초과 마일리지는 422를 반환합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/checkout/extend
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.checkout.extend -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.checkout.extend`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\CheckoutController@extend`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). <!-- TODO: 도메인 특이 에러가 있으면 보강 -->_
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 임시 주문의 만료 시각을 연장합니다. `optional.sanctum`으로 회원은 `Auth::id()`, 비회원은 cart_key로 대상을 식별하며, `CheckoutController@extend`가 `TempOrderService::extendExpiration()`을 호출해 갱신된 `expires_at`을 반환합니다. 주문서 작성이 길어져 임시 주문이 만료되기 전에 세션을 연장하는 용도이며, 연장할 임시 주문이 이미 만료·미존재면 404를 반환합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
# Claim Reasons API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Claim Reasons 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/claim-reasons
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.claim-reasons.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.claim-reasons.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ClaimReasonController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `8` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| type | string | `refund` | 클래임 사유 유형 (ClaimReasonTypeEnum — `refund`(환불/취소)) |
|
||||
| code | string | `order_mistake` | 사유 식별 코드 (같은 type 내 고유, 영문 소문자/숫자/`_`) |
|
||||
| name | object | `{"ko":"주문 실수","en":"Order Mistake","ja":"注文ミス"}` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| localized_name | string | `주문 실수` | `name` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| fault_type | string | `customer` | 귀책 구분 (ClaimReasonFaultTypeEnum — `customer`(고객)/`seller`(판매자)/`carrier`(배송사)) |
|
||||
| fault_type_label | string | `고객 귀책` | `fault_type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| is_user_selectable | boolean | `true` | user selectable 여부 |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| sort_order | integer | `0` | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| created_at | string | `2026-05-27 15:20:43` | 생성 일시 |
|
||||
| updated_at | string | `2026-06-27 00:49:51` | 최종 수정 일시 |
|
||||
| creator | array | `[]` | 생성자 정보 객체 (uuid/name/email — creator 관계 파생) |
|
||||
| updater | array | `[]` | 최종 수정자 정보 객체 (id/name — updater 관계 로드 시) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 클래임(반품/교환/환불) 사유 마스터 목록을 조회합니다. `permission:sirsoft-ecommerce.settings.read` 권한이 필요하며, `type`(기본 refund)·`is_active`·`fault_type`·`search` 쿼리로 필터링할 수 있습니다. `ClaimReasonService::getAllReasons()`가 조회하고 `ClaimReasonCollection`으로 반환하며, 각 항목은 다국어 사유명(`name`)과 귀책 구분(`fault_type`: customer·seller·carrier), 사용자 노출 여부(`is_user_selectable`)를 포함합니다. 환경설정의 클래임 사유 관리 화면에서 사용됩니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/claim-reasons
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.claim-reasons.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.claim-reasons.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ClaimReasonController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| type | body | string | 예 | — | 클래임 사유 유형 (ClaimReasonTypeEnum — 현재 `refund`(환불/취소)) |
|
||||
| code | body | string | 예 | max 50 | 사유 식별 코드 (영문 소문자/숫자/`_`, 같은 type 내에서 고유) |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| fault_type | body | string | 예 | — | 귀책 구분 (ClaimReasonFaultTypeEnum — `customer`(고객)/`seller`(판매자)/`carrier`(배송사)) |
|
||||
| is_user_selectable | body | boolean | 아니오 | — | user selectable 여부 |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 새 클래임 사유를 생성합니다. `permission:sirsoft-ecommerce.settings.update` 권한이 필요하며, 유형(`type`)·고유 코드(`code`)·다국어 사유명(`name`)·귀책 구분(`fault_type`)을 필수로 받고 사용자 노출 여부·활성 여부·정렬 순서를 선택 입력합니다. `ClaimReasonService::createReason()`이 저장하고 생성된 사유를 201로 반환합니다. `code` 는 유형 내에서 고유해야 하며 회원 취소/반품 화면의 사유 선택지로 활용됩니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/claim-reasons/active
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.claim-reasons.active -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.claim-reasons.active`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ClaimReasonController@active`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `8` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| type | string | `refund` | 클래임 사유 유형 (ClaimReasonTypeEnum — `refund`(환불/취소)) |
|
||||
| code | string | `order_mistake` | 사유 식별 코드 (같은 type 내 고유, 영문 소문자/숫자/`_`) |
|
||||
| name | object | `{"ko":"주문 실수","en":"Order Mistake","ja":"注文ミス"}` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| localized_name | string | `주문 실수` | `name` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| fault_type | string | `customer` | 귀책 구분 (ClaimReasonFaultTypeEnum — `customer`(고객)/`seller`(판매자)/`carrier`(배송사)) |
|
||||
| fault_type_label | string | `고객 귀책` | `fault_type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| is_user_selectable | boolean | `true` | user selectable 여부 |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| sort_order | integer | `0` | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| created_at | string | `2026-05-27 15:20:43` | 생성 일시 |
|
||||
| updated_at | string | `2026-06-27 00:49:51` | 최종 수정 일시 |
|
||||
| creator | array | `[]` | 생성자 정보 객체 (uuid/name/email — creator 관계 파생) |
|
||||
| updater | array | `[]` | 최종 수정자 정보 객체 (id/name — updater 관계 로드 시) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 활성화된 클래임 사유만 추려 Select 옵션용으로 조회합니다. `permission:sirsoft-ecommerce.settings.read` 권한이 필요하며, `type` 쿼리(기본 refund)로 유형을 지정하면 `ClaimReasonService::getActiveReasons()`가 `is_active=true` 인 사유만 반환합니다. 관리자 화면에서 환불/취소 처리 시 사유 드롭다운을 채우는 용도로, 목록(index)과 달리 필터 없이 활성 사유만 내려주는 점이 다릅니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/claim-reasons/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.claim-reasons.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.claim-reasons.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ClaimReasonController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 클래임 사유 1건을 삭제합니다. `permission:sirsoft-ecommerce.settings.update` 권한이 필요하며, 대상이 없으면 404 를 반환하고 존재하면 `ClaimReasonService::deleteReason()`이 삭제합니다. 이미 사용 중인 사유 등 삭제 불가 상황에서는 서비스가 던진 예외 메시지를 그대로 사용해 400 으로 응답하므로, 관리자에게 삭제 실패 사유가 노출됩니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/claim-reasons/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.claim-reasons.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.claim-reasons.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ClaimReasonController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 클래임 사유 1건의 상세 정보를 조회합니다. `permission:sirsoft-ecommerce.settings.read` 권한이 필요하며, `ClaimReasonService::getReason()`이 대상을 조회해 `ClaimReasonResource`로 반환합니다. 사유 편집 폼을 열 때 기존 값(다국어 사유명·코드·귀책 구분·활성/노출 설정 등)을 채우는 용도로 사용되며, 해당 사유가 없으면 404 를 반환합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/claim-reasons/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.claim-reasons.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.claim-reasons.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ClaimReasonController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| type | body | string | 예 | — | 클래임 사유 유형 (ClaimReasonTypeEnum — 현재 `refund`(환불/취소)) |
|
||||
| code | body | string | 예 | max 50 | 사유 식별 코드 (영문 소문자/숫자/`_`, 같은 type 내에서 고유) |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| fault_type | body | string | 예 | — | 귀책 구분 (ClaimReasonFaultTypeEnum — `customer`(고객)/`seller`(판매자)/`carrier`(배송사)) |
|
||||
| is_user_selectable | body | boolean | 아니오 | — | user selectable 여부 |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 기존 클래임 사유를 수정합니다. `permission:sirsoft-ecommerce.settings.update` 권한이 필요하고 대상은 경로 `id` 로 지정하며, 생성과 동일한 필드(유형·코드·다국어 사유명·귀책 구분·노출/활성/정렬)를 받아 `ClaimReasonService::updateReason()`이 갱신하고 갱신된 사유를 반환합니다. 대상이 없거나 갱신 실패 시 400 오류로 응답합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/claim-reasons/{id}/toggle-status
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.claim-reasons.toggle-status -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.claim-reasons.toggle-status`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ClaimReasonController@toggleStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 클래임 사유의 활성 상태를 켜고 끄는 토글을 수행합니다. `permission:sirsoft-ecommerce.settings.update` 권한이 필요하며, `ClaimReasonService::toggleStatus()`가 대상 사유의 `is_active` 값을 반전시켜 저장하고 갱신된 사유를 반환합니다. 사유를 삭제하지 않고 일시적으로 회원 선택지에서 감추거나 다시 노출할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/claim-reasons
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.claim-reasons.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.claim-reasons.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ClaimReasonController@userSelectableReasons`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:sirsoft-ecommerce.user-orders.cancel`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `7` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| type | string | `refund` | 클래임 사유 유형 (ClaimReasonTypeEnum — `refund`(환불/취소)) |
|
||||
| code | string | `order_mistake` | 사유 식별 코드 (같은 type 내 고유, 영문 소문자/숫자/`_`) |
|
||||
| name | object | `{"ko":"주문 실수","en":"Order Mistake","ja":"注文ミス"}` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| localized_name | string | `주문 실수` | `name` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| fault_type | string | `customer` | 귀책 구분 (ClaimReasonFaultTypeEnum — `customer`(고객)/`seller`(판매자)/`carrier`(배송사)) |
|
||||
| fault_type_label | string | `고객 귀책` | `fault_type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| is_user_selectable | boolean | `true` | user selectable 여부 |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| sort_order | integer | `0` | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| created_at | string | `2026-05-27 15:20:43` | 생성 일시 |
|
||||
| updated_at | string | `2026-06-27 00:49:51` | 최종 수정 일시 |
|
||||
| creator | array | `[]` | 생성자 정보 객체 (uuid/name/email — creator 관계 파생) |
|
||||
| updater | array | `[]` | 최종 수정자 정보 객체 (id/name — updater 관계 로드 시) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.user-orders.cancel`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 회원(및 선택적으로 비회원)이 주문 취소/반품 신청 화면에서 선택할 수 있는 클래임 사유 목록을 조회합니다. `optional.sanctum`(회원/비회원 모두 접근)과 `permission:sirsoft-ecommerce.user-orders.cancel` 권한이 적용되며, `ClaimReasonService::getUserSelectableReasons()`가 활성이면서 `is_user_selectable=true` 인 사유만 반환합니다. 관리 전용 목록과 달리 사용자에게 공개 가능한 사유만 내려주는 사용자향 엔드포인트입니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
# Coupons API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Coupons 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/coupons
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.coupons.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.coupons.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserCouponController@index`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| status | query | string | 아니오 | `available`, `used`, `expired` | 상태 필터 (해당 상태의 항목만 조회) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 50 | 페이지당 항목 수 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.coupon.user_list_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| coupons | object | `{"data":[{"id":8611,"coupon_id":156,"user_id":"a1e0a91a-f…` | 회원이 발급받은 쿠폰(발급 내역) 페이지네이션 객체 (`data[]` 발급 건 + `pagination` — CouponIssueCollection 직렬화, 쿠폰 정의가 아닌 회원별 발급 건) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원이 마이페이지 쿠폰함에서 자신이 발급받은 쿠폰(발급 내역)을 페이지네이션으로 조회합니다. `auth:sanctum` 인증이 필요하며, `status` 필터(available·used·expired)로 사용 가능/사용 완료/만료 쿠폰을 구분합니다. `UserCouponService::getUserCoupons()`가 조회하고 `CouponIssueCollection`으로 직렬화되므로, 여기의 항목은 쿠폰 정의(마스터)가 아니라 회원별 발급 건입니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/coupons/available
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.coupons.available -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.coupons.available`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserCouponController@available`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| product_ids | query | array | 아니오 | — | product 식별자 배열 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.coupon.user_available_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| coupons | array | `[{"id":4702,"coupon_id":106,"user_id":1,"coupon_code":nul…` | 현재 장바구니 상품에 적용 가능한 보유 쿠폰(발급 건) 배열 (상품/카테고리 범위·최소 주문금액·유효기간을 만족해 주문에 곧바로 선택 가능한 후보만) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 체크아웃 화면에서 회원이 현재 장바구니 상품에 실제로 적용할 수 있는 보유 쿠폰만 추려서 반환합니다. `auth:sanctum` 인증이 필요하고 `product_ids` 로 대상 상품을 전달하면, `UserCouponService::getAvailableCoupons()`가 보유 쿠폰 중 상품/카테고리 적용 범위·최소 주문금액·유효기간 등을 만족하는 것만 필터링해 내려줍니다. 쿠폰함 목록(index)과 달리 주문에 곧바로 선택 가능한 후보만 반환하는 점이 다릅니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/coupons/downloadable
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.coupons.downloadable -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.coupons.downloadable`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserCouponController@downloadable`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| per_page | query | integer | 아니오 | min 1, max 50 | 페이지당 항목 수 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.coupon.user_downloadable_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `157` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"API 문서 샘플 쿠폰","en":"API Doc Sample Coupon"}` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| description | object | `{"ko":"특정 카테고리 배송비 할인","en":"Shipping discount on categor…` | 설명 (다국어 필드는 로케일별 값 객체) |
|
||||
| target_type | string | `order_amount` | 할인 적용 대상 (product_amount=상품금액, order_amount=주문금액, shipping_fee=배송비) |
|
||||
| discount_type | string | `fixed` | 혜택 유형 (fixed=정액 할인, rate=정률(%) 할인) |
|
||||
| discount_value | string | `1000.00` | 혜택값 (정액이면 할인 금액, 정률이면 할인율 %) |
|
||||
| discount_max_amount | string | `3000.00` | 정률 할인 시 최대 할인 금액 상한 (없으면 null) |
|
||||
| min_order_amount | string | `0.00` | 쿠폰 적용 최소 주문금액 (미만 주문에는 사용 불가) |
|
||||
| issue_method | string | `download` | 발급 방법 (direct=직접발급, download=다운로드, auto=자동발급) |
|
||||
| issue_condition | string | `manual` | 발급 조건 (manual=수동, signup=회원가입, first_purchase=첫구매, birthday=생일) |
|
||||
| issue_status | string | `issuing` | 발급 상태 (issuing=발급중, stopped=발급중단) |
|
||||
| total_quantity | integer | `300` | 총 발급 수량 상한 (null=무제한) |
|
||||
| issued_count | integer | `0` | issued 개수 (집계) |
|
||||
| per_user_limit | integer | `1` | 회원 1인당 발급 제한 수량 |
|
||||
| valid_type | string | `period` | 유효기간 유형 (period=기간지정, days_from_issue=발급일로부터 N일) |
|
||||
| valid_days | integer | `14` | 발급일로부터 유효한 일수 (valid_type=days_from_issue 인 경우) |
|
||||
| valid_from | string | `2026-06-08T02:24:18.000000Z` | 유효기간 시작일 (쿠폰 사용 가능 시작 시각) |
|
||||
| valid_to | string | `2026-08-07T02:24:18.000000Z` | 유효기간 종료일 (쿠폰 사용 가능 종료 시각) |
|
||||
| issue_from | string | `2026-06-08T02:24:18.000000Z` | 발급기간 시작일 (다운로드 가능 시작 시각) |
|
||||
| issue_to | string | `2026-07-15T02:24:18.000000Z` | 발급기간 종료일 (다운로드 가능 종료 시각) |
|
||||
| is_combinable | boolean | `false` | combinable 여부 |
|
||||
| target_scope | string | `all` | 적용 범위 (all=전체 상품, products=특정 상품, categories=특정 카테고리) |
|
||||
| created_by | integer | `1` | 쿠폰 등록자(관리자) 식별자 (users 참조, 삭제 시 null) |
|
||||
| created_at | string | `2026-07-07T05:47:31.000000Z` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-07T05:47:31.000000Z` | 최종 수정 일시 |
|
||||
| deleted_at | null | `null` | 소프트 삭제 일시 (미삭제 시 null) |
|
||||
| is_downloaded | boolean | `false` | downloaded 여부 |
|
||||
| user_issued_count | integer | `0` | user issued 개수 (집계) |
|
||||
| coupon_id | integer | `157` | coupon 식별자 (연관 리소스 참조) |
|
||||
| localized_name | string | `API 문서 샘플 쿠폰` | `name` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| target_type_short_label | string | `주문` | `target_type_short` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| valid_period_formatted | string | `-` | `valid_period` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| min_order_amount_formatted | string | `0원` | `min_order_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| remaining_quantity | integer | `300` | 잔여 발급 가능 수량 (total_quantity − issued_count, 무제한이면 null) |
|
||||
| benefit_formatted | string | `1,000원 할인` | `benefit` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| included_products | array | `[]` | 적용 대상 포함 상품 목록 (target_scope=products 시 이 상품에만 적용) |
|
||||
| excluded_products | array | `[]` | 적용 제외 상품 목록 (해당 상품은 쿠폰 적용에서 제외) |
|
||||
| included_categories | array | `[]` | 적용 대상 포함 카테고리 목록 (target_scope=categories 시 이 카테고리에만 적용) |
|
||||
| excluded_categories | array | `[]` | 적용 제외 카테고리 목록 (해당 카테고리는 쿠폰 적용에서 제외) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원이 지금 다운로드해 발급받을 수 있는 쿠폰(다운로드형) 목록을 페이지네이션으로 조회합니다. `auth:sanctum` 인증이 필요하며, `UserCouponService::getDownloadableCoupons()`가 발급기간·수량·회원당 한도를 만족하는 다운로드형 쿠폰을 반환하고 각 항목에 `is_downloaded`·`user_issued_count`로 이미 받았는지 여부를 표시합니다. 여기 항목은 아직 발급 전이므로 쿠폰 정의(마스터) 기준이며, 실제 발급은 download 엔드포인트로 수행합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/user/coupons/{couponId}/download
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.coupons.download -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.coupons.download`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserCouponController@download`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| couponId | path | string | 예 | — | 대상 coupon의 식별자 |
|
||||
| coupon_id | body | integer | 예 | — | coupon 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원이 다운로드형 쿠폰 1건을 실제로 발급받습니다. `auth:sanctum` 인증이 필요하고 대상 쿠폰은 `couponId`(경로)로 지정하며, `UserCouponService::downloadCoupon()`이 발급기간·수량·회원당 한도·중복 발급 여부를 검증한 뒤 발급 내역을 생성해 201로 반환합니다. 한도 초과·발급기간 종료 등 발급 불가 사유는 서비스 예외의 메시지와 코드가 그대로 오류 응답에 전달됩니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# Currency API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Currency 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/currency
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.currency.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.currency.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserCurrencyController@show`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| preferred_currency | null | `null` | 회원이 저장한 선호 결제 통화 코드 (미설정 시 `null`) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원 본인의 선호 결제 통화를 조회합니다. `auth:sanctum` 인증이 필요하며, `UserCurrencyService::getPreferredCurrency()`가 현재 사용자의 저장된 통화 코드를 반환합니다. 아직 통화를 설정하지 않은 회원은 `preferred_currency`가 `null`로 반환됩니다. 마이페이지 통화 설정 화면이나 회원정보 수정 화면에서 현재 값을 표시하는 용도입니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/user/currency
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.currency.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.currency.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserCurrencyController@update`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| currency | body | string | 예 | — | 저장할 선호 결제 통화 코드 (등록 통화: is_default 또는 exchange_rate>0 인 통화만 허용) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원 본인의 선호 결제 통화를 저장합니다. `auth:sanctum` 인증이 필요하며, `UserCurrencyService::setPreferredCurrency()`가 검증된 `currency`(등록된 통화만 허용)를 현재 사용자에 영속화하고 저장된 통화 코드를 반환합니다. 마이페이지 통화 설정이나 회원정보 수정에서 회원이 직접 결제 통화를 변경할 때 호출하는 용도입니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
# Dashboard API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Dashboard 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/dashboard/overview
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.dashboard.overview -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.dashboard.overview`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\DashboardController@overview`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.dashboard.view`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| pending_payment | integer | `0` | 오늘 결제대기 상태 주문상품 수량 |
|
||||
| payment_complete | integer | `0` | 오늘 결제완료 상태 주문상품 수량 |
|
||||
| preparing | integer | `0` | 오늘 상품준비중 상태 주문상품 수량 |
|
||||
| shipping_ready | integer | `0` | 오늘 배송준비 상태 주문상품 수량 |
|
||||
| shipping | integer | `0` | 오늘 배송중 상태 주문상품 수량 |
|
||||
| cancellations | integer | `0` | 오늘 취소 상태 주문상품 수량 (전체취소 기준, 부분취소 포함) |
|
||||
| returns | integer | `0` | 오늘 반품 상태 주문상품 수량 (환불 도메인 미반영으로 현재 항상 0) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.dashboard.view`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자 대시보드 상단의 "오늘 주문 현황" 배지를 채우는 조회 엔드포인트입니다. `auth:sanctum` + admin + `sirsoft-ecommerce.dashboard.view` 권한이 필요하며, `EcommerceDashboardService::getOverview()`가 오늘자 주문을 상태별(결제대기/결제완료/상품준비중/배송준비/배송중/취소/반품)로 집계해 각 건수를 반환합니다. 모든 값은 오늘 하루 범위의 집계이며, 관리자가 처리해야 할 주문 흐름을 한눈에 파악하는 용도입니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/dashboard/pending-inquiries
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.dashboard.pending-inquiries -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.dashboard.pending-inquiries`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\DashboardController@pendingInquiries`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.dashboard.view`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| limit | query | integer | 아니오 | min 1, max 50 | 반환할 최대 항목 수 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| items | array | `[{"id":1,"product_id":320,"inquirable_id":79762,"product_…` | 미답변 상품문의 목록 (최신순, PendingInquiryResource — 문의 id/상품/작성자/게시판 글 id 등) |
|
||||
| total | integer | `1` | 전체 개수 (집계) |
|
||||
| board_slug | null | `null` | 문의가 저장된 연동 게시판의 slug (관리자 문의 상세 링크용, 미연동 시 null) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.dashboard.view`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 전체 상품에 달린 미답변 상품문의 목록과 총 건수를 조회합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.dashboard.view` 권한이 필요하며, `EcommerceDashboardService::getPendingInquiries()`가 답변 대기 문의를 최신순으로 조회해 `items`(문의 목록)·`total`(전체 미답변 건수)·`board_slug`(연동 게시판 slug, 미연동 시 null)를 반환합니다. `limit` 쿼리로 표시 건수를 1~50 사이에서 조정할 수 있고, 미지정 시 모듈 설정 `dashboard.recent_limit`(기본 5) 값이 적용됩니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/dashboard/recent-reviews
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.dashboard.recent-reviews -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.dashboard.recent-reviews`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\DashboardController@recentReviews`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.dashboard.view`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| limit | query | integer | 아니오 | min 1, max 50 | 반환할 최대 항목 수 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `99` | 기본 키 (내부 식별자) |
|
||||
| product_id | integer | `320` | product 식별자 (연관 리소스 참조) |
|
||||
| product_name | string | `API 문서 샘플 상품` | 리뷰 대상 상품의 현재 로케일 상품명 (product 관계 파생) |
|
||||
| rating | integer | `5` | 리뷰 평점 (별점 정수) |
|
||||
| author_name | string | `API 문서 샘플 사용자` | 리뷰 작성자 이름 (user 관계 파생) |
|
||||
| created_at | string | `2026-07-07 14:47:31` | 생성 일시 |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.dashboard.view`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 전체 상품에 등록된 최신 노출 리뷰를 조회해 대시보드 "최신 리뷰" 카드를 채웁니다. `auth:sanctum` + admin + `sirsoft-ecommerce.dashboard.view` 권한이 필요하며, `EcommerceDashboardService::getRecentReviews()`가 노출 상태의 리뷰를 최신순으로 가져와 `RecentReviewResource`로 상품명·평점·작성자명·작성일시 등을 반환합니다. `limit` 쿼리로 1~50 건 범위에서 표시 개수를 지정할 수 있으며, 미지정 시 모듈 설정 `dashboard.recent_limit`(기본 5)이 적용됩니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/dashboard/sales-graph
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.dashboard.sales-graph -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.dashboard.sales-graph`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\DashboardController@salesGraph`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.dashboard.view`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| days | array | `[{"date":"2026-07-01","sales_quantity":0,"sales_amount":0…` | 일자별 판매 집계 배열 (각 항목 `{date, sales_quantity, sales_amount}` — 그래프 막대 데이터) |
|
||||
| total_quantity | integer | `0` | 표시 기간 판매 수량 합계 |
|
||||
| total_sales | integer | `0` | 표시 기간 순매출 합계 (기본 통화 자릿수로 라운딩) |
|
||||
| quantity_change | null | `null` | 직전 동일 기간 대비 판매 수량 증감율(%) (직전 합계 0 이면 null) |
|
||||
| sales_change | null | `null` | 직전 동일 기간 대비 순매출 증감율(%) (직전 합계 0 이면 null) |
|
||||
| updated_at | null | `null` | 최종 수정 일시 |
|
||||
| updated_at_display | string | `` | 집계 마지막 갱신 시각의 사용자 타임존 HH:mm 캡션 (갱신 이력 없으면 빈 문자열) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.dashboard.view`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 최근 N일간의 판매 추세 막대 그래프 데이터를 조회합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.dashboard.view` 권한이 필요하며, `EcommerceDashboardService::getSalesGraph()`가 일자별 판매 수량·금액(`days`)과 기간 합계(`total_quantity`, `total_sales`), 직전 기간 대비 변화율(`quantity_change`, `sales_change`)을 반환합니다. 그래프 표시 일수는 모듈 설정 `dashboard.graph_days`(기본 7일)로 결정되며 별도 파라미터는 받지 않습니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,343 @@
|
||||
# Extra Fee Templates API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Extra Fee Templates 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/extra-fee-templates
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.extra-fee-templates.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.extra-fee-templates.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ExtraFeeTemplateController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| search | query | string | 아니오 | max 200 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
|
||||
| region | query | string | 아니오 | max 100 | 지역/권역 |
|
||||
| is_active | query | string | 아니오 | ``, `true`, `false` | 활성 여부 (true 활성 / false 비활성) |
|
||||
| sort_by | query | string | 아니오 | `id`, `zipcode`, `fee`, `region`, `is_active`, `created_at`, `updated_at` | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| per_page | query | integer | 아니오 | min 10, max 100 | 페이지당 항목 수 |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `37` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | integer | `109` | 기본 키 (내부 식별자) |
|
||||
| zipcode | string | `00000` | 추가배송비를 적용할 우편번호 (단일 또는 `-` 로 이은 범위) |
|
||||
| fee | integer | `3000` | 해당 우편번호에 부과할 추가 배송비 (상점 기본 통화 기준 반올림) |
|
||||
| fee_formatted | string | `3,000원` | `fee` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| region | string | `경기 안산 풍도동` | 지역명 (도서산간 등 관리자 참고용 표시 라벨) |
|
||||
| description | string | `도서산간 지역` | 설명 (다국어 필드는 로케일별 값 객체) |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| created_by | null | `null` | 등록자 UUID (creator 관계 파생, 없으면 null) |
|
||||
| updated_by | null | `null` | 최종 수정자 UUID (updater 관계 파생, 없으면 null) |
|
||||
| created_at | string | `2026-07-07 14:47:31` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-07 14:47:31` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 추가배송비(도서산간 등 우편번호별 할증) 템플릿 목록을 검색·필터·정렬·페이지네이션으로 조회합니다. `permission:sirsoft-ecommerce.shipping-policies.read` 권한이 필요하며, `search`·`region`·`is_active` 필터와 다양한 정렬 기준을 지원합니다. `ExtraFeeTemplateService::getList()`가 조회하고 통계(`getStatistics()`)를 함께 담아 `ExtraFeeTemplateCollection`으로 반환합니다. 각 항목은 우편번호·추가 배송비·지역명을 포함하며 배송정책의 지역별 할증 관리 화면에 사용됩니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/extra-fee-templates
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.extra-fee-templates.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.extra-fee-templates.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ExtraFeeTemplateController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| zipcode | body | string | 예 | max 20 | 우편번호 |
|
||||
| fee | body | number | 예 | min 0, max 9999999999.99 | 해당 우편번호에 부과할 추가 배송비 (0 이상) |
|
||||
| region | body | string | 아니오 | max 100 | 지역/권역 |
|
||||
| description | body | string | 아니오 | max 1000 | 설명 |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 추가배송비 템플릿 1건을 생성합니다. `permission:sirsoft-ecommerce.shipping-policies.create` 권한이 필요하며, 우편번호(`zipcode`, 단일 또는 범위)와 추가 배송비(`fee`)를 필수로 받고 지역명·설명·활성 여부를 선택 입력합니다. `ExtraFeeTemplateService::create()`가 저장하고 생성된 템플릿을 201로 반환합니다. 활성 템플릿은 배송비 계산 시 해당 우편번호에 할증으로 반영됩니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/extra-fee-templates/active-settings
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.extra-fee-templates.active-settings -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.extra-fee-templates.active-settings`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ExtraFeeTemplateController@activeSettings`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| zipcode | string | `00000` | 추가배송비 적용 우편번호 (배송정책 설정용 축약 필드) |
|
||||
| fee | integer | `3000` | 해당 우편번호의 추가 배송비 (float 변환값) |
|
||||
| region | string | `` | 지역명 (없으면 빈 문자열) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 활성화된 추가배송비 템플릿을 배송정책에서 바로 사용할 수 있는 축약 JSON 배열(우편번호·배송비·지역명)로 반환합니다. `permission:sirsoft-ecommerce.shipping-policies.read` 권한이 필요하며, `ExtraFeeTemplateService::getAllAsExtraFeeSettings()`가 `is_active=true` 인 템플릿만 배송정책 설정 형식으로 변환합니다. 배송정책 편집 화면에서 지역별 할증 규칙을 채우거나 계산 로직에 주입하는 용도로, 관리 목록(index)의 상세 필드 대신 계산에 필요한 최소 필드만 내려줍니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/extra-fee-templates/bulk
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.extra-fee-templates.bulk-destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.extra-fee-templates.bulk-destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ExtraFeeTemplateController@bulkDestroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | query | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.delete`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 여러 추가배송비 템플릿을 한 번에 삭제합니다. `permission:sirsoft-ecommerce.shipping-policies.delete` 권한이 필요하고 대상 ID 배열(`ids`)을 쿼리로 전달하며, `ExtraFeeTemplateService::bulkDelete()`가 일괄 삭제 후 삭제 건수(`deleted_count`)를 반환합니다. 목록에서 여러 지역 할증 규칙을 선택해 한꺼번에 정리할 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/extra-fee-templates/bulk
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.extra-fee-templates.bulk-store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.extra-fee-templates.bulk-store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ExtraFeeTemplateController@bulkStore`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| items | body | array | 예 | min 1, max 1000 | 처리 대상 항목 배열 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 CSV/엑셀 업로드로 추가배송비 템플릿을 한 번에 대량 등록합니다. `permission:sirsoft-ecommerce.shipping-policies.create` 권한이 필요하고 최대 1000건까지 `items` 배열로 전달하며, `ExtraFeeTemplateService::bulkCreate()`가 일괄 생성 후 등록 건수(`created_count`)를 201로 반환합니다. 도서산간 우편번호 목록처럼 다수의 지역 할증을 수기 입력 없이 파일로 업로드할 때 사용합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/extra-fee-templates/bulk-toggle-active
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.extra-fee-templates.bulk-toggle-active -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.extra-fee-templates.bulk-toggle-active`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ExtraFeeTemplateController@bulkToggleActive`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
| is_active | body | boolean | 예 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 여러 추가배송비 템플릿의 활성 상태를 한 번에 지정한 값(`is_active`)으로 변경합니다. `permission:sirsoft-ecommerce.shipping-policies.update` 권한이 필요하고 대상 ID 배열(`ids`)과 적용할 활성 여부를 전달하며, `ExtraFeeTemplateService::bulkToggleActive()`가 일괄 갱신 후 변경 건수(`updated_count`)를 반환합니다. 단건 토글과 달리 여러 지역 할증을 한꺼번에 켜거나 끌 때 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/extra-fee-templates/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.extra-fee-templates.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.extra-fee-templates.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ExtraFeeTemplateController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 추가배송비 템플릿 1건을 삭제합니다. `permission:sirsoft-ecommerce.shipping-policies.delete` 권한이 필요하며, 대상이 없으면 404 를 반환하고 존재하면 `ExtraFeeTemplateService::delete()`가 삭제합니다. 특정 지역의 할증 규칙을 개별적으로 제거할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/extra-fee-templates/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.extra-fee-templates.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.extra-fee-templates.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ExtraFeeTemplateController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 추가배송비 템플릿 1건의 상세 정보를 조회합니다. `permission:sirsoft-ecommerce.shipping-policies.read` 권한이 필요하며, `ExtraFeeTemplateService::getDetail()`이 대상을 조회해 `ExtraFeeTemplateResource`로 반환합니다. 템플릿 편집 폼에 기존 값(우편번호·배송비·지역명·설명·활성 여부)을 채우는 용도로 사용되며, 대상이 없으면 404 를 반환합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/extra-fee-templates/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.extra-fee-templates.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.extra-fee-templates.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ExtraFeeTemplateController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| zipcode | body | string | 예 | max 20 | 우편번호 |
|
||||
| fee | body | number | 예 | min 0, max 9999999999.99 | 해당 우편번호에 부과할 추가 배송비 (0 이상) |
|
||||
| region | body | string | 아니오 | max 100 | 지역/권역 |
|
||||
| description | body | string | 아니오 | max 1000 | 설명 |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 추가배송비 템플릿 1건을 전체 수정합니다. `permission:sirsoft-ecommerce.shipping-policies.update` 권한이 필요하며, path 의 `id` 로 대상을 조회해 없으면 404(`messages.extra_fee_template.not_found`)를 반환합니다. 존재하면 `ExtraFeeTemplateService::update()`가 우편번호·추가 배송비·지역명·설명·활성 여부를 갱신합니다. 우편번호와 배송비는 필수이며, 수정된 템플릿이 활성 상태이면 이후 배송비 계산에 즉시 반영됩니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/extra-fee-templates/{id}/toggle-active
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.extra-fee-templates.toggle-active -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.extra-fee-templates.toggle-active`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ExtraFeeTemplateController@toggleActive`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 추가배송비 템플릿 1건의 활성 상태를 반전(active↔inactive)합니다. `permission:sirsoft-ecommerce.shipping-policies.update` 권한이 필요하며, path 의 `id` 로 대상을 조회해 없으면 404(`messages.extra_fee_template.not_found`)를 반환합니다. 존재하면 `ExtraFeeTemplateService::toggleActive()`가 현재 값을 뒤집어 저장하고 갱신된 템플릿을 반환합니다. 목록 화면에서 특정 지역 할증 규칙을 개별적으로 켜거나 끌 때 사용하며, 여러 건을 동일 값으로 일괄 설정하려면 bulk-toggle-active 엔드포인트를 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
# Guest API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Guest 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/guest/orders/verify
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.guest.orders.verify -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.guest.orders.verify`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\OrderController@verify`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order_number | body | string | 예 | max 50 | 조회할 주문번호 (본인 확인 키 ①) |
|
||||
| orderer_phone | body | string | 예 | max 20 | 주문자 전화번호 (본인 확인 키 ②) |
|
||||
| guest_lookup_password | body | string | 예 | max 255 | 비회원 주문 조회 비밀번호 (본인 확인 키 ③) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 비회원이 주문번호·주문자 전화번호·조회 비밀번호로 본인 확인을 수행하고, 성공 시 30분 유효한 비회원 주문 조회 토큰을 발급받는 공개 엔드포인트입니다. 인증이 필요 없으며, `OrderController@verify`가 `GuestOrderAuthService::authenticate()`로 검증한 뒤 토큰과 최소 주문 요약(`order_number`, `order_status`)만 반환합니다. 주문 없음·회원 주문·전화번호 불일치·비밀번호 오류·잠금 등 모든 실패는 정보 노출 방지를 위해 동일한 404("주문을 찾을 수 없습니다")로 처리됩니다. 발급된 토큰은 이후 비회원 주문 상세/취소/환불 예상 등 후속 호출의 `X-Guest-Order-Token` 헤더로 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/guest/orders/{orderNumber}/cancel
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.guest.orders.cancel -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.guest.orders.cancel`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\OrderController@cancel`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| orderNumber | path | string | 예 | — | 대상 order number의 식별자 |
|
||||
| reason | body | string | 예 | — | 취소 사유 코드 (ClaimReason 의 refund 타입·활성·사용자 선택 가능 코드) |
|
||||
| reason_detail | body | string | 아니오 | max 500 | 사용자 입력 취소 사유 상세 |
|
||||
| items | body | array | 아니오 | min 1 | 처리 대상 항목 배열 (전달 시 부분취소, 미전달 시 전체취소) |
|
||||
| refund_priority | body | string | 아니오 | `pg_first`, `points_first` | 환불 배분 우선순위 (PG 우선 / 포인트 우선, 미전달 시 pg_first) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 비회원이 조회 토큰으로 인증된 상태에서 자신의 주문을 취소합니다. 주문 소유권은 `VerifyGuestOrderToken` 미들웨어가 `X-Guest-Order-Token` 헤더로 검증하며, `OrderController@cancel`이 회원 취소와 동일한 `OrderCancellationService`를 재사용하되 취소자(`cancelledBy`)는 null로 둡니다. `items`를 전달하면 부분취소, 없으면 전체취소로 처리하고, `refund_priority`로 PG 환불과 포인트 환불 중 우선순위를 지정할 수 있습니다. 취소 후 갱신된 주문 상세를 `GuestOrderResource`로 반환합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/guest/orders/{orderNumber}/estimate-refund
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.guest.orders.estimate-refund -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.guest.orders.estimate-refund`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\OrderController@estimateRefund`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| orderNumber | path | string | 예 | — | 대상 order number의 식별자 |
|
||||
| items | body | array | 예 | min 1 | 처리 대상 항목 배열 |
|
||||
| refund_priority | body | string | 아니오 | `pg_first`, `points_first` | 환불 배분 우선순위 (PG 우선 / 포인트 우선, 미전달 시 pg_first) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 비회원이 취소를 확정하기 전에 특정 옵션(`items`) 취소 시 예상 환불 금액을 미리 계산해 보여줍니다. 조회 토큰(`X-Guest-Order-Token`)으로 주문 소유권이 검증되며, `OrderController@estimateRefund`가 `OrderCancellationService::previewRefund()`로 실제 취소를 수행하지 않고 환불 예상값만 반환합니다. `refund_priority`에 따라 PG 우선/포인트 우선 환불 배분 결과가 달라집니다. 비회원 주문 취소 화면에서 "환불 예정 금액"을 미리 안내하는 용도입니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/guest/orders/{orderNumber}/options/{optionId}/confirm
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.guest.orders.confirm-option -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.guest.orders.confirm-option`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\OrderController@confirmOption`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| orderNumber | path | string | 예 | — | 대상 order number의 식별자 |
|
||||
| optionId | path | string | 예 | — | 대상 option의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 비회원이 배송 완료된 주문의 개별 옵션(`optionId`)을 구매확정합니다. 조회 토큰(`X-Guest-Order-Token`)으로 주문 소유권이 검증되며, `OrderController@confirmOption`이 토큰으로 검증된 주문에 실제 속한 옵션인지 다시 확인한 뒤 `OrderService::confirmOption()`을 호출합니다. 주문에 속하지 않은 옵션 ID면 404, 확정 불가 상태(배송 미완료 등)면 422를 반환합니다. 구매확정 시 적립 포인트 확정 등 후속 처리가 서비스 계층에서 이어집니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/guest/orders/{orderNumber}/shipping-address
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.guest.orders.update-shipping-address -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.guest.orders.update-shipping-address`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\OrderController@updateShippingAddress`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| orderNumber | path | string | 예 | — | 대상 order number의 식별자 |
|
||||
| recipient_name | body | string | 예 | max 50 | 수령인 이름 |
|
||||
| recipient_phone | body | string | 예 | max 20 | 수령인 연락처 |
|
||||
| recipient_tel | body | string | 아니오 | max 20 | 수령인 일반전화 (선택 연락처) |
|
||||
| country_code | body | string | 아니오 | — | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| zipcode | body | string | 아니오 | max 10 | 우편번호 |
|
||||
| address | body | string | 아니오 | max 255 | 기본 주소 |
|
||||
| address_detail | body | string | 아니오 | max 255 | 상세 주소 |
|
||||
| address_line_1 | body | string | 아니오 | max 255 | 주소 1행 (기본 주소) |
|
||||
| address_line_2 | body | string | 아니오 | max 255 | 주소 2행 (상세 주소) |
|
||||
| intl_city | body | string | 아니오 | max 100 | 도시 (국제 주소) |
|
||||
| intl_state | body | string | 아니오 | max 100 | 주/도 (국제 주소) |
|
||||
| intl_postal_code | body | string | 아니오 | max 20 | 우편번호 (국제 주소) |
|
||||
| delivery_memo | body | string | 아니오 | max 255 | 배송 메모 (배송 시 요청사항) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 비회원이 배송 전 상태의 주문 배송지를 수정합니다. 조회 토큰(`X-Guest-Order-Token`)으로 주문 소유권이 검증되며, 비회원은 저장된 회원 주소(`address_id`)를 쓸 수 없으므로 수취인·연락처·주소 필드를 직접 입력받아 `OrderController@updateShippingAddress`가 회원과 동일한 `OrderService::updateShippingAddress()`로 처리합니다. 국내(`zipcode`/`address`)와 해외(`address_line_1`·`intl_city` 등) 주소 필드를 함께 지원합니다. 이미 배송이 시작된 주문 등 수정 불가 상태면 422를 반환합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,320 @@
|
||||
# Inquiries API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Inquiries 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/inquiries/{inquiryId}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.inquiries.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.inquiries.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductInquiryController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.inquiries.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| inquiryId | path | string | 예 | — | 대상 inquiry의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.inquiries.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품 1:1 문의 1건을 삭제합니다. `sirsoft-ecommerce.inquiries.delete` 권한이 필요하며, `ProductInquiryService::deleteInquiry()` 가 해당 문의를 제거하고 `{deleted: true}` 를 반환합니다. 문의가 존재하지 않는 등 삭제 불가 상황에서는 서비스가 `RuntimeException` 을 던져 422 로 응답합니다. 관리자 문의 관리 화면에서 부적절하거나 중복된 문의를 정리할 때 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/inquiries/{inquiryId}/reply
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.inquiries.reply.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.inquiries.reply.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductInquiryController@destroyReply`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.inquiries.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| inquiryId | path | string | 예 | — | 대상 inquiry의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.inquiries.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 문의에 등록된 답변을 삭제합니다. `sirsoft-ecommerce.inquiries.update` 권한이 필요하며, `ProductInquiryService::deleteReply()` 가 답변을 제거하고 문의를 미답변 상태로 되돌린 뒤 `{deleted: true}` 를 반환합니다. 문의 자체는 유지되며, 잘못 등록한 답변을 회수할 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/inquiries/{inquiryId}/reply
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.inquiries.reply -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.inquiries.reply`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductInquiryController@reply`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.inquiries.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| inquiryId | path | string | 예 | — | 대상 inquiry의 식별자 |
|
||||
| content | body | string | 예 | min 1, max 5000 | 본문 내용 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.inquiries.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품 문의에 답변을 등록합니다. `sirsoft-ecommerce.inquiries.update` 권한이 필요하며, `ProductInquiryService::createReply()` 가 `content`(1~5000자)로 답변을 저장하고 문의를 답변완료 상태로 전환한 뒤 `{id, is_answered}` 를 201 로 반환합니다. 이미 답변이 있는 등 등록 불가 상황에서는 `RuntimeException` 이 던져져 422 로 응답합니다. 관리자가 고객 문의에 응대할 때 사용합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/inquiries/{inquiryId}/reply
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.inquiries.reply.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.inquiries.reply.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductInquiryController@updateReply`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.inquiries.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| inquiryId | path | string | 예 | — | 대상 inquiry의 식별자 |
|
||||
| content | body | string | 예 | min 1, max 5000 | 본문 내용 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.inquiries.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 문의에 이미 등록된 답변 내용을 수정합니다. `sirsoft-ecommerce.inquiries.update` 권한이 필요하며, `ProductInquiryService::updateReply()` 가 `content`(1~5000자)로 기존 답변을 갱신하고 `{id}` 를 반환합니다. 답변이 없는 문의 등 수정 불가 상황에서는 `RuntimeException` 이 던져져 422 로 응답합니다. 오탈자 정정 등 답변 내용을 고칠 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/inquiries
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.inquiries.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.inquiries.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\ProductInquiryController@index`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| items | array | `[]` | 내 문의 항목 배열 (각 항목: id, product 요약, product_name, is_answered, 게시판 연동 시 title/category/content/is_secret/reply/attachments) |
|
||||
| meta | object | `{"current_page":1,"per_page":25,"total":0,"last_page":1,"…` | 페이지네이션 메타 (current_page/per_page/total/last_page/from/to, 문의 게시판 연동 여부 inquiry_available, abilities 답변·삭제 권한, board_settings) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인 회원이 마이페이지에서 자신이 작성한 상품 문의 목록을 조회합니다. `auth:sanctum` 인증만 요구하며, `ProductInquiryService::getUserInquiries()` 가 로그인 사용자(`Auth::id()`)의 문의를 `search`(검색어)·`is_answered`(답변 여부) 필터와 `per_page`(기본 10)로 페이지네이션해 `items`(문의 배열)와 `meta`(페이지 정보)로 반환합니다. 마이페이지 문의 내역 화면을 채우는 데 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/user/inquiries/{inquiryId}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.inquiries.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.inquiries.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\ProductInquiryController@destroy`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| inquiryId | path | string | 예 | — | 대상 inquiry의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인 회원이 자신이 작성한 문의를 삭제합니다. `auth:sanctum` 인증이 필요하며, 컨트롤러가 문의를 조회해 없으면 404, `inquiry->user_id` 가 로그인 사용자와 다르면 403 을 반환한 뒤 `ProductInquiryService::deleteInquiry()` 로 삭제하고 `{deleted: true}` 를 반환합니다. 마이페이지에서 본인 문의를 취소/삭제할 때 사용합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/user/inquiries/{inquiryId}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.inquiries.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.inquiries.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\ProductInquiryController@update`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| inquiryId | path | string | 예 | — | 대상 inquiry의 식별자 |
|
||||
| title | body | string | 아니오 | — | 제목 |
|
||||
| category | body | string | 아니오 | — | 문의 분류 (게시판 설정 기반 유형 슬러그, 연동 게시판 Post 로 저장) |
|
||||
| content | body | string | 예 | — | 본문 내용 |
|
||||
| is_secret | body | boolean | 아니오 | — | secret 여부 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.inquiry.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인 회원이 자신이 작성한 문의 내용을 수정합니다. `auth:sanctum` 인증이 필요하며, 컨트롤러가 문의를 조회해 없으면 404, `inquiry->user_id` 가 로그인 사용자와 다르면 403 을 반환한 뒤 `ProductInquiryService::updateInquiry()` 로 제목·분류·본문·비밀글 여부를 갱신하고 `{id}` 를 반환합니다. `content` 는 필수이며, 마이페이지에서 아직 답변되지 않은 본인 문의를 고칠 때 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/user/inquiries/{inquiryId}/reply
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.inquiries.reply.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.inquiries.reply.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\ProductInquiryController@destroyReply`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| inquiryId | path | string | 예 | — | 대상 inquiry의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 사용자 표면에서 문의 답변 권한을 가진 회원이 문의 답변을 삭제합니다. `auth:sanctum` 인증에 더해 컨트롤러가 `PermissionHelper::check('sirsoft-ecommerce.inquiries.update')` 로 답변 권한을 확인(없으면 403)한 뒤 `ProductInquiryService::deleteReply()` 로 답변을 제거하고 `{deleted: true}` 를 반환합니다. 답변 권한을 위임받은 사용자(예: 상담원 역할)가 사용자 화면에서 답변을 회수할 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/user/inquiries/{inquiryId}/reply
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.inquiries.reply -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.inquiries.reply`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\ProductInquiryController@reply`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| inquiryId | path | string | 예 | — | 대상 inquiry의 식별자 |
|
||||
| content | body | string | 예 | min 1, max 5000 | 본문 내용 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 사용자 표면에서 문의 답변 권한을 가진 회원이 문의에 답변을 등록합니다. `auth:sanctum` 인증에 더해 컨트롤러가 `PermissionHelper::check('sirsoft-ecommerce.inquiries.update')` 로 답변 권한을 확인(없으면 403)한 뒤 `ProductInquiryService::createReply()` 가 `content`(1~5000자)로 답변을 저장하고 문의를 답변완료로 전환해 `{id, is_answered}` 를 201 로 반환합니다. 관리자 화면이 아닌 사용자 프론트에서 답변을 처리하는 상담원 역할에 사용합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/user/inquiries/{inquiryId}/reply
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.inquiries.reply.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.inquiries.reply.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\ProductInquiryController@updateReply`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| inquiryId | path | string | 예 | — | 대상 inquiry의 식별자 |
|
||||
| content | body | string | 예 | min 1, max 5000 | 본문 내용 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 사용자 표면에서 문의 답변 권한을 가진 회원이 기존 문의 답변을 수정합니다. `auth:sanctum` 인증에 더해 컨트롤러가 `PermissionHelper::check('sirsoft-ecommerce.inquiries.update')` 로 답변 권한을 확인(없으면 403)한 뒤 `ProductInquiryService::updateReply()` 가 `content`(1~5000자)로 답변을 갱신하고 `{id}` 를 반환합니다. 사용자 프론트에서 답변을 처리하는 상담원 역할이 답변 내용을 정정할 때 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
# Mileage Transactions API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Mileage Transactions 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/mileage-transactions
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.mileage-transactions.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.mileage-transactions.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\MileageTransactionController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.mileage.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| sort | query | string | 아니오 | `created_at_desc`, `created_at_asc`, `amount_desc`, `amount_asc` | 정렬 기준 (필드명, `-` 접두 시 내림차순) |
|
||||
| search_field | query | string | 아니오 | `member`, `member_id`, `email`, `order` | 검색 대상 필드명 (검색어를 적용할 컬럼) |
|
||||
| search_keyword | query | string | 아니오 | max 100 | 검색 키워드 (부분 일치) |
|
||||
| type | query | string | 아니오 | `earn`, `use`, `expire`, `adjust` | 유형 필터 (해당 유형의 항목만 조회) |
|
||||
| currency | query | string | 아니오 | max 10 | 통화 코드 필터 (해당 통화로 기록된 거래만 조회) |
|
||||
| start_date | query | date | 아니오 | — | 조회 기간 시작일 (이 날짜 이후 데이터) |
|
||||
| end_date | query | date | 아니오 | — | 조회 기간 종료일 (이 날짜 이전 데이터) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `68` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | integer | `528` | 기본 키 (내부 식별자) |
|
||||
| user_id | integer | `166` | user 식별자 (연관 리소스 참조) |
|
||||
| currency | string | `KRW` | 거래 기록 통화 코드 (주문 기준통화 스냅샷, 금액 표기·잔액 집계 단위) |
|
||||
| type | string | `admin_earn` | 거래 유형 (MileageTransactionTypeEnum 8종: purchase_earn·admin_earn·order_use·admin_deduct·expired·refund_restore·order_cancel_restore·earn_cancel) |
|
||||
| type_label | string | `관리자 지급` | `type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| admin_badge_group | string | `amber` | 관리자 내역 화면 배지 색상 그룹 (적립계=green·사용계=blue·소멸=gray·복원계=teal·수동/회수계=amber) |
|
||||
| user_display_category | string | `adjust` | 회원 마이페이지 표시용 4분류 (earn·use·expire·adjust — 복원·수동·회수는 adjust 로 통합) |
|
||||
| amount | integer | `1000` | 거래 금액 (양수=적립, 음수=차감) |
|
||||
| amount_formatted | string | `1,000원` | `amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| remaining_amount | integer | `0` | 잔여 금액 (적립건만 양수, FIFO 차감으로 소진 — 미만료 잔여 합이 잔액 SSoT) |
|
||||
| remaining_amount_formatted | string | `0원` | `remaining_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| balance_after | integer | `1000` | 거래 직후 잔액 (감사용 스냅샷, 베스트에포트) |
|
||||
| order_id | integer | `436` | order 식별자 (연관 리소스 참조) |
|
||||
| order_option_id | integer | `824` | order option 식별자 (연관 리소스 참조) |
|
||||
| order_cancel_id | integer | `18` | order cancel 식별자 (연관 리소스 참조) |
|
||||
| source_transaction_id | integer | `523` | source transaction 식별자 (연관 리소스 참조) |
|
||||
| granted_by | integer | `1` | 부여 주체 식별자 (NULL=시스템 자동, user ID=관리자 수동 부여) |
|
||||
| granted_by_name | string | `관리자` | 부여 관리자 이름 (grantedByUser 관계 eager load 시에만 노출) |
|
||||
| granted_by_uuid | string | `a1e0a91a-fba6-491c-a53e-7285a5686857` | 부여 관리자 UUID (grantedByUser 관계 eager load 시에만 노출) |
|
||||
| user_name | string | `API 문서 샘플 사용자` | 거래 대상 회원 이름 (user 관계 eager load 시에만 노출) |
|
||||
| user_uuid | string | `a231747f-e82e-4cf2-9ae1-a261849dce40` | 거래 대상 회원 UUID (user 관계 eager load 시에만 노출) |
|
||||
| order_number | string | `20260619-1425382147` | 연관 주문번호 (order 관계 eager load 시에만 노출) |
|
||||
| description | string | `마일리지 적립 (660원)` | 설명 (다국어 필드는 로케일별 값 객체) |
|
||||
| memo | string | `111` | 관리자 메모 (수동 지급/차감·적립건 편집 시 입력) |
|
||||
| expires_at | string | `2027-07-02T15:29:30+00:00` | expires 일시 |
|
||||
| expires_at_formatted | string | `2027-07-03 00:29:30` | `expires_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| expires_at_date | string | `2027-07-03` | `expires_at` 의 사이트 타임존 기준 날짜 부분 (시각 제외) |
|
||||
| expired_at | null | `null` | expired 일시 |
|
||||
| expired_at_formatted | null | `null` | `expired_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| created_at | string | `2026-07-07T05:47:31+00:00` | 생성 일시 |
|
||||
| created_at_formatted | string | `2026-07-07 14:47:31` | `created_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| created_at_date | string | `2026-07-07` | `created_at` 의 사이트 타임존 기준 날짜 부분 (시각 제외) |
|
||||
| is_earning | boolean | `true` | earning 여부 |
|
||||
| can_edit_expiry | boolean | `false` | edit expiry 수행 가능 여부 (권한 기반) |
|
||||
| expired_amount | integer | `0` | 이 적립 lot 을 source 로 소멸(expired)된 금액 합계 (목록 조회 시 eager 집계, 단건 조회 시 0 폴백) |
|
||||
| expired_amount_formatted | string | `0원` | `expired_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| expiry_state | string | `active` | 적립건 소멸 상태 (active=미소멸, partial_expired=일부 소멸, fully_expired=전액 소멸 — 적립계만 의미) |
|
||||
| abilities | object | `{"can_manage":true,"can_edit":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.mileage.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 전체 회원의 마일리지 거래 원장을 검색·필터·페이지네이션으로 조회합니다. `permission:sirsoft-ecommerce.mileage.read` 권한이 필요하며, 회원(member·member_id·email)·주문번호 검색, type(earn·use·expire·adjust)·통화·기간 필터, 금액/생성일 정렬을 지원합니다. `UserMileageService::paginateAdminHistory()`가 조회하고 `MileageTransactionCollection`이 통화 필터 후보(`withCurrencies`)와 함께 직렬화합니다. 각 행은 원장 스냅샷(balance_after, remaining_amount 등)을 그대로 노출하며 원장은 불변입니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/mileage-transactions
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.mileage-transactions.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.mileage-transactions.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\MileageTransactionController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.mileage.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| user_id | body | uuid | 예 | — | user 식별자 |
|
||||
| action | body | string | 예 | `earn`, `deduct` | 처리 동작 (earn=수동 적립 → adminEarn, deduct=수동 차감 → adminDeduct FIFO 소진) |
|
||||
| amount | body | integer | 예 | min 1 | 지급/차감할 마일리지 금액 (양수) |
|
||||
| currency | body | string | 예 | max 10 | 대상 통화 코드 (해당 통화 잔액에 적용) |
|
||||
| memo | body | string | 아니오 | max 1000 | 관리자 메모 (거래에 기록) |
|
||||
| description | body | string | 아니오 | max 500 | 설명 |
|
||||
| expires_at | body | date | 아니오 | — | 만료일 직접 지정 (지급 시 `use_default_expiry`=false 인 경우 적용) |
|
||||
| use_default_expiry | body | boolean | 아니오 | — | 지급 시 정책 기본 만료일 적용 여부 (기본 true, false 면 `expires_at` 사용) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.mileage.manage`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 회원에게 마일리지를 수동으로 지급하거나 차감합니다. `permission:sirsoft-ecommerce.mileage.manage` 권한이 필요하고 회원은 `user_id`(uuid)로 지정하며, `action`(earn/deduct)에 따라 `UserMileageService::adminEarn()` 또는 `adminDeduct()`를 호출합니다. 지급 시 `use_default_expiry`(기본 true)면 정책 기본 만료일을, 아니면 `expires_at`을 적용하고, 차감은 FIFO로 적립건에서 소진합니다. 잔액 부족 등 도메인 규칙 위반은 `MileageValidationException`으로 422를 반환합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/mileage-transactions/extend-expiry
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.mileage-transactions.extend-expiry -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.mileage-transactions.extend-expiry`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\MileageTransactionController@extendExpiry`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.mileage.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| user_id | body | uuid | 예 | — | user 식별자 |
|
||||
| lot_ids | body | array | 예 | min 1 | lot 식별자 배열 |
|
||||
| days | body | integer | 예 | min 1, max 3650 | 각 lot 만료일을 연장할 일수 (최대 3650일) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.mileage.manage`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 회원의 여러 적립 lot 의 유효기간을 한 번에 연장합니다. `permission:sirsoft-ecommerce.mileage.manage` 권한이 필요하며, 회원(`user_id` uuid)과 대상 적립건 배열(`lot_ids`), 연장 일수(`days`, 최대 3650)를 받아 `UserMileageService::extendLotExpiry()`가 각 lot 의 만료일을 연장하고 실제로 연장된 건수(`extended_count`)를 반환합니다. 이미 소멸/사용된 lot 등 대상 외 건은 서비스가 걸러내므로 반환 건수가 요청한 `lot_ids` 수보다 작을 수 있습니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/mileage-transactions/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.mileage-transactions.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.mileage-transactions.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\MileageTransactionController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.mileage.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| memo | body | string | 아니오 | max 1000 | 관리자 메모 보정값 (요청에 포함된 경우만 갱신, 빈 값으로 비우기 허용) |
|
||||
| expires_at | body | date | 아니오 | — | expires 일시 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.mileage.manage`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 기존 적립 거래의 부가 필드(관리자 메모 `memo`, 만료일 `expires_at`)만 보정합니다. 마일리지 원장은 불변이므로 금액·유형 등 핵심 값은 수정할 수 없고, 요청에 실제로 포함된 키만 갱신합니다(`memo` 만 보내면 만료일은 유지). `UserMileageService::updateAdminTransaction()`가 적립계 거래인지·소멸/사용된 lot 이 아닌지 검증하며, 적립계 외 거래 등 규칙 위반은 `MileageValidationException`(422)으로 거부합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/mileage-transactions/{id}/linked
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.mileage-transactions.linked -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.mileage-transactions.linked`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\MileageTransactionController@linked`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.mileage.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.mileage.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 마일리지 내역 한 행을 펼쳤을 때 그와 연결된 거래들을 조회합니다. `permission:sirsoft-ecommerce.mileage.read` 권한이 필요하며, `UserMileageService::getLinkedTransactions()`가 적립건이면 그 적립을 FIFO 로 소비한 차감 거래들을, 차감/복원건이면 원본 적립·취소 연결 거래를 찾아 `MileageTransactionCollection`으로 반환합니다. 해당 거래가 없으면 404 를 반환하며, 연결 거래가 없으면 빈 목록이 내려옵니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
# Mileage API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Mileage 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/mileage
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.mileage.balance -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.mileage.balance`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserMileageController@balance`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| mileage | object | `{"enabled":false,"available":12910,"pending":14000,"expir…` | 마일리지 잔액 요약 객체 (enabled 기능 활성화 여부, available 사용 가능, pending 적립 대기, expiring_soon/expiring_date 소멸 예정, total_earned/total_used 누적 적립·사용, by_currency 통화별 잔액) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원이 마이페이지에서 자신의 마일리지 잔액 요약을 조회합니다. `auth:sanctum` 인증만 필요하며, `UserMileageService::getBalance()`가 마일리지 기능 활성화 여부, 사용 가능(available)·적립 대기(pending)·소멸 예정 금액을 계산해 `mileage` 객체로 반환합니다. 마일리지 기능이 꺼져 있으면 `enabled: false` 와 0값이 내려오므로 화면에서 잔액 위젯 노출 여부를 이 플래그로 판단할 수 있습니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/mileage/history
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.mileage.history -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.mileage.history`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserMileageController@history`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| category | query | string | 아니오 | `earn`, `use`, `expire`, `adjust` | 분류 필터 (해당 분류의 항목만 조회) |
|
||||
| currency | query | string | 아니오 | max 10 | 통화 코드 필터 (해당 통화의 마일리지 거래만 조회) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| transactions | object | `{"data":[{"number":6,"id":527,"user_id":1,"currency":"KRW…` | 마일리지 거래 내역 페이지네이션 객체 (`data` 거래 항목 배열 + 페이지 메타, `MileageTransactionCollection` 으로 직렬화) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원이 마이페이지에서 자신의 마일리지 적립/사용 내역을 페이지네이션으로 조회합니다. `category`(earn·use·expire·adjust) 4분류 필터와 `currency`·`per_page`(최대 100)를 지원하며, `UserMileageService::paginateUserHistory()`가 필터를 적용해 조회한 뒤 `MileageTransactionCollection`으로 직렬화해 `transactions` 에 담습니다. `category` 는 원장의 원시 type 이 아니라 사용자 표시용 4분류로 매핑된 값입니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/mileage/max-usable
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.mileage.max-usable -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.mileage.max-usable`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserMileageController@maxUsable`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order_amount | query | integer | 예 | min 0 | 사용 가능 상한 계산 기준 주문금액 (마일리지 사용액은 이 금액을 넘을 수 없음) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.mileage.max_usable_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 체크아웃 화면에서 특정 주문금액(`order_amount`)에 실제로 사용 가능한 최대 마일리지를 계산해 반환합니다. `auth:sanctum` 인증이 필요하고 `order_amount` 는 필수이며, `UserMileageService::getMaxUsable()`가 보유 잔액·최소 사용 정책·주문금액 상한을 종합해 사용 가능 상한을 산출하고 현재 잔액(available)도 함께 내려줍니다. 확장은 `sirsoft-ecommerce.mileage.max_usable_validation_rules` 필터로 검증 파라미터를 추가할 수 있습니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
# Options API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Options 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/options/bulk-price
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.options.bulk-price -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.options.bulk-price`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductOptionController@bulkUpdatePrice`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.products.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| product_ids | body | array | 아니오 | — | product 식별자 배열 |
|
||||
| option_ids | body | array | 아니오 | — | option 식별자 배열 |
|
||||
| method | body | string | 예 | `increase`, `decrease`, `fixed` | 가격 변경 방식 (increase 인상 / decrease 인하 / fixed 고정가로 설정) |
|
||||
| value | body | number | 예 | min 0 | 값 |
|
||||
| unit | body | string | 예 | `won`, `percent` | 변경 단위 (won 금액 기준 / percent 비율 기준) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.product_option.bulk_price_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.products.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 선택한 상품/옵션의 판매가를 일괄 변경합니다. `auth:sanctum` + `sirsoft-ecommerce.products.update` 권한이 필요하며, `ProductOptionService::bulkUpdatePriceByMixedIds()`가 처리합니다. `product_ids`는 해당 상품의 모든 옵션을, `option_ids`는 "productId-optionId" 형식으로 개별 선택된 옵션을 대상으로 합니다. `method`(increase/decrease/fixed)와 `unit`(won/percent) 조합으로 인상·인하·고정가를 적용하며, 검증 실패 시 422, 그 외 오류 시 500을 반환합니다. `sirsoft-ecommerce.product_option.bulk_price_validation_rules` 필터로 확장이 검증 규칙을 추가할 수 있습니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/options/bulk-stock
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.options.bulk-stock -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.options.bulk-stock`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductOptionController@bulkUpdateStock`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.products.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| product_ids | body | array | 아니오 | — | product 식별자 배열 |
|
||||
| option_ids | body | array | 아니오 | — | option 식별자 배열 |
|
||||
| method | body | string | 예 | `increase`, `decrease`, `set` | 재고 변경 방식 (increase 증가 / decrease 감소 / set 특정 수량으로 설정) |
|
||||
| value | body | integer | 예 | min 0 | 값 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.product_option.bulk_stock_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.products.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 선택한 상품/옵션의 재고를 일괄 변경합니다. `auth:sanctum` + `sirsoft-ecommerce.products.update` 권한이 필요하며, `ProductOptionService::bulkUpdateStockByMixedIds()`가 처리합니다. `product_ids`는 해당 상품의 모든 옵션을, `option_ids`는 "productId-optionId" 형식으로 개별 선택된 옵션을 대상으로 합니다. `method`(increase/decrease/set)와 정수 `value`로 재고를 가감하거나 특정 수량으로 설정하며, 검증 실패 시 422, 그 외 오류 시 500을 반환합니다. `sirsoft-ecommerce.product_option.bulk_stock_validation_rules` 필터로 확장이 검증 규칙을 추가할 수 있습니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/options/bulk-update
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.options.bulk-update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.options.bulk-update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductOptionController@bulkUpdate`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.products.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
| bulk_changes | body | array | 아니오 | — | 옵션 일괄 변경 조건 (`price_adjustment`/`stock_quantity` 각각 method+value, 설정된 필드가 개별 수정보다 우선 적용) |
|
||||
| items | body | array | 아니오 | — | 처리 대상 항목 배열 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.option.bulk_update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.products.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 옵션들을 통합 일괄 업데이트합니다. `auth:sanctum` + `sirsoft-ecommerce.products.update` 권한이 필요하며, 상품은 미선택하고 옵션만 선택된 경우에 사용됩니다. `ids`(대상 옵션, 최소 1개)와 함께 `bulk_changes`(일괄 변경 조건)와 `items`(개별 인라인 수정)를 받아 `ProductOptionService::bulkUpdate()`가 처리하며, 일괄 변경 조건이 설정된 필드가 우선 적용되고 나머지는 개별 수정이 반영됩니다. 검증 실패 시 422, 그 외 오류 시 500을 반환하고, `sirsoft-ecommerce.option.bulk_update_validation_rules` 필터로 확장이 검증 규칙을 추가할 수 있습니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,935 @@
|
||||
# Orders API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Orders 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/orders
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.orders.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.orders.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\OrderController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.orders.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| search_field | query | string | 아니오 | `all`, `order_number`, `orderer_name`, `recipient_name`, `orderer_phone`, `recipient_phone`, `product_name`, `sku` | 검색 대상 필드명 (검색어를 적용할 컬럼) |
|
||||
| search_keyword | query | string | 아니오 | max 200 | 검색 키워드 (부분 일치) |
|
||||
| date_type | query | string | 아니오 | — | 기간 필터 기준 일자 종류 (ordered_at 주문일 / paid_at 결제일 / confirmed_at 구매확정일 / delivered_at 배송완료일 / cancelled_at 취소일) |
|
||||
| start_date | query | date | 아니오 | — | 조회 기간 시작일 (이 날짜 이후 데이터) |
|
||||
| end_date | query | date | 아니오 | — | 조회 기간 종료일 (이 날짜 이전 데이터) |
|
||||
| order_status | query | array | 아니오 | — | 주문상태 다중 선택 필터 (OrderStatusEnum 값 배열, 해당 상태의 주문만 조회) |
|
||||
| option_status | query | array | 아니오 | — | 주문옵션 상태 다중 선택 필터 (OrderStatusEnum 값 배열, 해당 옵션 상태를 가진 주문만 조회) |
|
||||
| shipping_type | query | array | 아니오 | — | 배송유형 다중 선택 필터 (ShippingType 코드 배열) |
|
||||
| payment_method | query | array | 아니오 | — | 결제수단 다중 선택 필터 (PaymentMethodEnum 값 배열) |
|
||||
| category_id | query | integer | 아니오 | — | category 식별자 |
|
||||
| min_amount | query | integer | 아니오 | min 0 | 주문금액 범위 필터 하한 (이 금액 이상 주문만 조회) |
|
||||
| max_amount | query | integer | 아니오 | min 0 | 주문금액 범위 필터 상한 (이 금액 이하 주문만 조회) |
|
||||
| country_codes | query | array | 아니오 | — | 배송국가 코드 다중 선택 필터 (ISO 3166-1 alpha-2 2자리 코드 배열) |
|
||||
| order_device | query | array | 아니오 | — | 주문 디바이스 다중 선택 필터 (DeviceTypeEnum 값 배열 — pc/mobile/app 등) |
|
||||
| min_shipping_amount | query | integer | 아니오 | min 0 | 배송비 범위 필터 하한 (이 배송비 이상 주문만 조회) |
|
||||
| max_shipping_amount | query | integer | 아니오 | min 0 | 배송비 범위 필터 상한 (이 배송비 이하 주문만 조회) |
|
||||
| shipping_policy_id | query | integer | 아니오 | — | shipping policy 식별자 |
|
||||
| user_id | query | integer | 아니오 | — | user 식별자 |
|
||||
| orderer_uuid | query | uuid | 아니오 | — | 특정 회원의 주문만 조회하는 주문자 UUID 필터 (회원 검색 연동용) |
|
||||
| member_type | query | string | 아니오 | `member`, `guest` | 회원 구분 필터 (member 회원 주문 / guest 비회원 주문) |
|
||||
| sort_by | query | string | 아니오 | `ordered_at`, `paid_at`, `total_amount` | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| per_page | query | integer | 아니오 | min 10, max 100 | 페이지당 항목 수 |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.order.list_validation_rules`, `sirsoft-ecommerce.order.list_validation_messages`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `128` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | integer | `455` | 기본 키 (내부 식별자) |
|
||||
| order_number | string | `ORD-20260707-000002` | 주문번호 (사용자 노출용 고유 식별 코드) |
|
||||
| order_status | string | `pending_payment` | 주문상태 (OrderStatusEnum 값 — 결제대기/결제완료/배송중 등) |
|
||||
| order_status_label | string | `결제대기` | `order_status` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| order_status_variant | string | `warning` | `order_status` 값의 표시 변형 키 (UI 배지 색상/스타일) |
|
||||
| base_currency | string | `KRW` | 금액 표기 기준 통화 (모든 *_formatted 필드의 통화, 주문 시점 base_currency 고정) |
|
||||
| payment_currency | string | `KRW` | 결제 통화 (유저가 선택·결제한 통화, base_currency 와 다르면 병기 표시) |
|
||||
| is_cross_currency | boolean | `false` | cross currency 여부 |
|
||||
| is_partially_cancelled | boolean | `false` | partially cancelled 여부 |
|
||||
| total_amount | integer | `193397` | 최종 주문금액 (상품합계 − 할인 + 배송비) |
|
||||
| total_amount_formatted | string | `193,397원` | `total_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_shipping_amount | integer | `0` | 총 배송비 |
|
||||
| total_shipping_amount_formatted | string | `0원` | `total_shipping_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_paid_amount | integer | `0` | 총 실제 결제금액 (PG 결제된 금액) |
|
||||
| total_paid_amount_formatted | string | `0원` | `total_paid_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_unpaid_amount | integer | `193397` | 미결제 잔액 (최종 주문금액 − 실제 결제금액) |
|
||||
| total_unpaid_amount_formatted | string | `193,397원` | `total_unpaid_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_cancelled_amount | integer | `0` | 총 취소금액 |
|
||||
| total_refunded_amount | integer | `0` | 총 환불금액 |
|
||||
| total_points_used_amount | integer | `0` | 총 포인트(마일리지) 사용액 |
|
||||
| total_points_used_amount_formatted | string | `0원` | `total_points_used_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_earned_points_amount | integer | `1934` | 총 적립 예정 포인트 |
|
||||
| total_earned_points_amount_formatted | string | `1,934원` | `total_earned_points_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| ordered_at | string | `2026-07-07T05:47:30+00:00` | ordered 일시 |
|
||||
| ordered_at_formatted | string | `2026-07-07 14:47:30` | `ordered_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| order_device | string | `pc` | 주문 디바이스 (DeviceTypeEnum 값 — pc/mobile/app) |
|
||||
| order_device_label | string | `PC` | `order_device` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| is_first_order | boolean | `true` | first order 여부 |
|
||||
| user | object | `{"uuid":"a23317ba-05bc-4de3-8272-2b73c091a266","name":"남상준"}` | 회원 주문의 주문자 요약 (uuid·name, 비회원 주문이면 미포함) |
|
||||
| first_option | object | `{"product_name":"quisquam et quia","product_option_name":…` | 대표 표시용 첫 번째 주문 옵션 요약 (상품명·옵션명·수량·썸네일·추가옵션 요약) |
|
||||
| options_count | integer | `1` | options 개수 (집계) |
|
||||
| address | object | `{"orderer_name":"관리자","recipient_name":"구태호","recipient_c…` | 배송지 요약 (주문자명·수령인명·배송국가 코드/현지화명) |
|
||||
| payment | object | `{"payment_method":"dbank","payment_method_label":"무통장입금"}` | 결제 요약 (결제수단 값·현지화 라벨) |
|
||||
| shipping | object | `{"shipping_type":null,"shipping_type_label":null,"shippin…` | 배송 요약 (배송유형·배송방법 라벨·택배사명·송장번호, 첫 번째 배송 기준) |
|
||||
| is_owner | boolean | `false` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":true,"can_update":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.orders.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 주문을 다양한 필터·검색·정렬 조건으로 페이지네이션 조회합니다. `auth:sanctum` + `sirsoft-ecommerce.orders.read` 권한이 필요하며, `Admin\OrderController@index`가 `OrderService::getList()`로 목록을, `getStatistics()`로 상태별 통계를 함께 가져와 `OrderCollection`에 담아 반환합니다. 검색 필드(주문번호/주문자명/상품명/SKU 등)·기간·주문상태·결제수단·금액대·회원/비회원 구분 등 폭넓은 필터를 지원합니다. 관리자 주문 목록 화면의 기본 데이터 소스입니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/orders/bulk
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.orders.bulk -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.orders.bulk`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\OrderController@bulkUpdate`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.orders.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
| order_status | body | string | 아니오 | — | 일괄 전환할 주문상태 (OrderStatusEnum 값, pending_order 제외 · 전이 규칙 검증) |
|
||||
| carrier_id | body | integer | 아니오 | — | carrier 식별자 |
|
||||
| tracking_number | body | string | 아니오 | max 50 | 송장(운송장)번호 (배송 관련 상태로 전환 시 carrier_id 와 함께 필수) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.orders.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 여러 주문(`ids`)의 주문상태나 배송 정보(택배사·송장번호)를 일괄 변경합니다. `auth:sanctum` + `sirsoft-ecommerce.orders.update` 권한이 필요하며, `Admin\OrderController@bulkUpdate`가 `OrderService::bulkUpdate()`로 처리합니다. 주문 목록에서 여러 건을 선택해 "배송 처리"·"상태 일괄 변경" 등을 수행할 때 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/orders/{order}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.orders.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.orders.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\OrderController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.orders.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order | path | string | 예 | — | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.orders.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 주문(`order`)을 소프트 삭제합니다. `auth:sanctum` + `sirsoft-ecommerce.orders.delete` 권한이 필요하며, `Admin\OrderController@destroy`가 `OrderService::delete()`를 호출합니다. 물리 삭제가 아닌 소프트 삭제(deleted_at 표시)이므로 데이터는 보존되며, 주문 목록/상세에서 제외됩니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/orders/{order}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.orders.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.orders.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\OrderController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.orders.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order | path | string | 예 | — | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `322` | 기본 키 (내부 식별자) |
|
||||
| order_number | string | `20260617-0207256237` | 주문번호 |
|
||||
| base_currency | string | `KRW` | 금액 표기 기준 통화 (모든 *_formatted 필드의 통화, 주문 시점 base_currency 고정) |
|
||||
| payment_currency | string | `KRW` | 결제 통화 (유저가 선택·결제한 통화, base_currency 와 다르면 병기 표시) |
|
||||
| is_cross_currency | boolean | `false` | cross currency 여부 |
|
||||
| order_status | string | `payment_complete` | 주문상태 (OrderStatusEnum) |
|
||||
| order_status_label | string | `결제완료` | `order_status` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| order_status_variant | string | `info` | `order_status` 값의 표시 변형 키 (UI 배지 색상/스타일) |
|
||||
| is_partially_cancelled | boolean | `false` | partially cancelled 여부 |
|
||||
| order_device | string | `pc` | 주문 디바이스 (pc/mobile/app) |
|
||||
| order_device_label | string | `PC` | `order_device` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| is_first_order | boolean | `true` | first order 여부 |
|
||||
| subtotal_amount | integer | `140000` | 상품 합계 (할인 전, 상품가×수량 합계) |
|
||||
| subtotal_amount_formatted | string | `140,000원` | `subtotal_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_discount_amount | integer | `25000` | 총 할인금액 (모든 할인 합계) |
|
||||
| total_discount_amount_formatted | string | `25,000원` | `total_discount_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_shipping_amount | integer | `0` | 총 배송비 |
|
||||
| total_shipping_amount_formatted | string | `0원` | `total_shipping_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_amount | integer | `115000` | 최종 주문금액 (subtotal - discount + shipping) |
|
||||
| total_amount_formatted | string | `115,000원` | `total_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_paid_amount | integer | `115000` | 총 실제 결제금액 (PG 결제액) |
|
||||
| total_paid_amount_formatted | string | `115,000원` | `total_paid_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_due_amount | integer | `0` | 총 결제예정금액 (무통장 등) |
|
||||
| total_due_amount_formatted | string | `0원` | `total_due_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| depositor_name | null | `null` | 무통장 입금자명 (입금확인 모달 기본값, payment 관계 로드 시에만 노출) |
|
||||
| total_cancelled_amount | integer | `0` | 총 취소금액 |
|
||||
| total_cancelled_amount_formatted | string | `0원` | `total_cancelled_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_refunded_amount | integer | `0` | 총 환불금액 |
|
||||
| total_refunded_amount_formatted | string | `0원` | `total_refunded_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_refunded_points_amount | integer | `0` | 총 환불 포인트 |
|
||||
| total_refunded_points_amount_formatted | string | `0원` | `total_refunded_points_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_product_coupon_discount_amount | integer | `0` | 상품 쿠폰 할인 합계 |
|
||||
| total_product_coupon_discount_amount_formatted | string | `0원` | `total_product_coupon_discount_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_order_coupon_discount_amount | integer | `25000` | 주문 쿠폰 할인 합계 |
|
||||
| total_order_coupon_discount_amount_formatted | string | `25,000원` | `total_order_coupon_discount_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_coupon_discount_amount | integer | `25000` | 총 쿠폰 할인금액 |
|
||||
| total_coupon_discount_amount_formatted | string | `25,000원` | `total_coupon_discount_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_code_discount_amount | integer | `0` | 총 할인코드 할인금액 |
|
||||
| total_code_discount_amount_formatted | string | `0원` | `total_code_discount_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_points_used_amount | integer | `0` | 총 포인트 사용액 |
|
||||
| total_points_used_amount_formatted | string | `0원` | `total_points_used_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_deposit_used_amount | integer | `0` | 총 예치금 사용액 |
|
||||
| total_deposit_used_amount_formatted | string | `0원` | `total_deposit_used_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_earned_points_amount | integer | `1150` | 총 적립 예정 포인트 |
|
||||
| total_earned_points_amount_formatted | string | `1,150원` | `total_earned_points_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| mc_subtotal_amount | object | `{"KRW":{"amount":140000,"formatted":"140,000원"},"USD":{"a…` | 상품합계 다중 통화 |
|
||||
| mc_total_discount_amount | object | `{"KRW":{"amount":25000,"formatted":"25,000원"},"USD":{"amo…` | 총 할인 다중 통화 |
|
||||
| mc_total_shipping_amount | object | `{"KRW":{"amount":0,"formatted":"0원"},"USD":{"amount":0,"f…` | 총 배송비 다중 통화 |
|
||||
| mc_total_amount | object | `{"KRW":{"amount":115000,"formatted":"115,000원"},"USD":{"a…` | 최종금액 다중 통화 (payment_amount) |
|
||||
| mc_total_product_coupon_discount_amount | object | `{"KRW":{"amount":0,"formatted":"0원"},"USD":{"amount":0,"f…` | 상품 쿠폰 할인 다중 통화 |
|
||||
| mc_total_order_coupon_discount_amount | object | `{"KRW":{"amount":25000,"formatted":"25,000원"},"USD":{"amo…` | 주문 쿠폰 할인 다중 통화 |
|
||||
| mc_total_coupon_discount_amount | object | `{"KRW":{"amount":25000,"formatted":"25,000원"},"USD":{"amo…` | 쿠폰 할인 합계 다중 통화 |
|
||||
| mc_total_code_discount_amount | object | `{"KRW":{"amount":0,"formatted":"0원"},"USD":{"amount":0,"f…` | 할인코드 할인 다중 통화 |
|
||||
| mc_total_points_used_amount | object | `{"KRW":{"amount":0,"formatted":"0원"},"USD":{"amount":0,"f…` | 포인트 사용 다중 통화 |
|
||||
| mc_total_deposit_used_amount | object | `{"KRW":{"amount":0,"formatted":"0원"},"USD":{"amount":0,"f…` | 예치금 사용 다중 통화 |
|
||||
| item_count | integer | `2` | item 개수 (집계) |
|
||||
| total_quantity | integer | `5` | 주문 옵션 수량 합계 (options 로드 시) |
|
||||
| total_list_price | integer | `177000` | 정가 합계 (옵션 스냅샷 정가 × 수량 합계) |
|
||||
| total_list_price_formatted | string | `177,000원` | `total_list_price` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| ordered_at | string | `2026-06-15T02:07:25+00:00` | ordered 일시 |
|
||||
| ordered_at_formatted | string | `2026-06-15 11:07:25` | `ordered_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| paid_at | string | `2026-06-17T02:07:25+00:00` | paid 일시 |
|
||||
| paid_at_formatted | string | `2026-06-17 11:07:25` | `paid_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| confirmed_at | null | `null` | confirmed 일시 |
|
||||
| confirmed_at_formatted | null | `null` | `confirmed_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| cancelled_at | null | `null` | cancelled 일시 |
|
||||
| cancelled_at_formatted | null | `null` | `cancelled_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| delivered_at | null | `null` | delivered 일시 |
|
||||
| total_tax_amount | integer | `10455` | 총 과세금액 |
|
||||
| total_tax_amount_formatted | string | `10,455원` | `total_tax_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_vat_amount | integer | `0` | 총 부가세금액 |
|
||||
| total_vat_amount_formatted | string | `0원` | `total_vat_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_taxable_supply_amount | integer | `10455` | 과세 공급가액 (총 과세금액 − 부가세, 영수증 과세금액 표시 SSoT) |
|
||||
| total_taxable_supply_amount_formatted | string | `10,455원` | `total_taxable_supply_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_tax_free_amount | integer | `0` | 총 면세금액 |
|
||||
| total_tax_free_amount_formatted | string | `0원` | `total_tax_free_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| user | object | `{"uuid":"a20683c6-14f8-4061-baa9-157c45e9de5a","name":"Jo…` | 회원 주문의 주문자 정보 (uuid·name·email, user 관계 로드 시 · 비회원이면 미포함) |
|
||||
| user_id | string | `a20683c6-14f8-4061-baa9-157c45e9de5a` | user 식별자 (연관 리소스 참조) |
|
||||
| user_login_id | null | `null` | 회원 로그인 아이디 (login_id, 비회원 주문이면 null) |
|
||||
| orderer_name | string | `설창용` | 주문자 이름 (배송지에서 플래튼) |
|
||||
| orderer_phone | string | `010-0650-9192` | 주문자 휴대전화 (배송지에서 플래튼) |
|
||||
| orderer_tel | null | `null` | 주문자 일반전화 (배송지에서 플래튼, 미입력 시 null) |
|
||||
| orderer_email | string | `moonchang.shim@gmail.com` | 주문자 이메일 (배송지에서 플래튼, 비회원 알림 수신 통로) |
|
||||
| recipient_name | string | `길준` | 수령인 이름 (배송지에서 플래튼) |
|
||||
| recipient_phone | string | `010-1612-1979` | 수령인 휴대전화 (배송지에서 플래튼) |
|
||||
| recipient_tel | null | `null` | 수령인 일반전화 (배송지에서 플래튼, 미입력 시 null) |
|
||||
| recipient_zipcode | string | `19882` | 수령인 우편번호 (배송지에서 플래튼) |
|
||||
| recipient_address | string | `부산광역시 도봉구 역삼로 201` | 수령인 기본 주소 (배송지에서 플래튼) |
|
||||
| recipient_detail_address | null | `null` | 수령인 상세 주소 (배송지에서 플래튼, 미입력 시 null) |
|
||||
| delivery_memo | null | `null` | 배송 메모 (배송지에서 플래튼, 미입력 시 null) |
|
||||
| delivery_memo_label | null | `null` | `delivery_memo` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| options | array | `[{"id":612,"option_status":"payment_complete","option_sta…` | 주문 옵션(품목) 목록 (OrderOptionResource — 상품·옵션·수량·옵션상태·금액) |
|
||||
| shipping_address | object | `{"id":320,"address_type":"shipping","orderer_name":"설창용",…` | 배송지 상세 (OrderAddressResource — 주문자/수령인/국내·해외 주소) |
|
||||
| billing_address | null | `null` | 청구지 상세 (OrderAddressResource, 미분리 시 null) |
|
||||
| payment | object | `{"id":284,"payment_status":"paid","payment_status_label":…` | 대표 결제 정보 (OrderPaymentResource — 결제수단·결제상태·금액) |
|
||||
| payments | array | `[{"id":284,"payment_status":"paid","payment_status_label"…` | 결제 이력 목록 (OrderPaymentResource 배열 — 다회 결제/부분결제 포함) |
|
||||
| shippings | array | `[]` | 배송 이력 목록 (OrderShippingResource 배열 — 배송유형·택배사·송장번호) |
|
||||
| cancels | array | `[]` | 취소 이력 목록 (OrderCancelResource 배열 — 취소 사유·상세·취소일시, 최근순) |
|
||||
| promotions_applied_snapshot | object | `{"coupon_issue_ids":[7330],"item_coupons":[],"discount_co…` | 적용된 프로모션 스냅샷 (재계산용) |
|
||||
| shipping_policy_applied_snapshot | null | `null` | 적용된 배송정책 스냅샷 (재계산용) |
|
||||
| admin_memo | null | `null` | 관리자 메모 (내부 관리용) |
|
||||
| customer_memo | null | `null` | 고객 메모 (주문 시 고객이 남긴 메모) |
|
||||
| created_at | string | `2026-06-17T02:07:25+00:00` | 생성 일시 |
|
||||
| updated_at | string | `2026-06-17T02:07:25+00:00` | 최종 수정 일시 |
|
||||
| is_owner | boolean | `false` | 현재 인증 사용자가 이 리소스의 소유자인지 여부 (BaseApiResource 표준 메타) |
|
||||
| abilities | object | `{"can_read":true,"can_update":true,"can_cancel":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.orders.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 주문(`order`)의 전체 상세를 조회합니다. `auth:sanctum` + `sirsoft-ecommerce.orders.read` 권한이 필요하며, `Admin\OrderController@show`가 `OrderService::getDetail()`로 옵션·배송·결제·취소 이력·금액 내역(과세/면세/다중통화 포함)까지 풀로드해 `OrderResource`로 반환합니다. 관리자 주문 상세 화면의 데이터 소스이며, 주문이 없으면 404를 반환합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/orders/{order}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.orders.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.orders.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\OrderController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.orders.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order | path | string | 예 | — | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| order_status | body | string | 아니오 | — | 변경할 주문상태 (OrderStatusEnum 값, 현재 상태에서 전이 가능한 값만 허용) |
|
||||
| admin_memo | body | string | 아니오 | max 2000 | 관리자 메모 (내부 관리용, 고객 비노출) |
|
||||
| recipient_name | body | string | 예 | max 50 | 수령인 이름 |
|
||||
| recipient_phone | body | string | 아니오 | max 20 | 수령인 연락처 |
|
||||
| recipient_tel | body | string | 아니오 | max 20 | 수령인 일반전화 (recipient_phone 없을 때 필수) |
|
||||
| recipient_zipcode | body | string | 아니오 | max 10 | 수령인 우편번호 (국내 주소, 해외 주소 없을 때 필수) |
|
||||
| recipient_address | body | string | 아니오 | max 255 | 수령인 기본 주소 (국내 주소, 해외 주소 없을 때 필수) |
|
||||
| recipient_detail_address | body | string | 아니오 | max 255 | 수령인 상세 주소 (recipient_address 입력 시 필수) |
|
||||
| address_line_1 | body | string | 아니오 | max 255 | 주소 1행 (기본 주소) |
|
||||
| address_line_2 | body | string | 아니오 | max 255 | 주소 2행 (상세 주소) |
|
||||
| intl_city | body | string | 아니오 | max 100 | 도시 (국제 주소) |
|
||||
| intl_state | body | string | 아니오 | max 100 | 주/도 (국제 주소) |
|
||||
| intl_postal_code | body | string | 아니오 | max 20 | 우편번호 (국제 주소) |
|
||||
| delivery_memo | body | string | 아니오 | max 500 | 배송 메모 (배송 시 요청사항) |
|
||||
| recipient_country_code | body | string | 아니오 | — | 수령인 배송국가 코드 (ISO 3166-1 alpha-2 2자리) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.orders.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 주문(`order`)의 주문상태·관리자 메모·수취인 배송지(국내/해외 주소 포함)를 수정합니다. `auth:sanctum` + `sirsoft-ecommerce.orders.update` 권한이 필요하며, `Admin\OrderController@update`가 `OrderService::update()`로 처리한 뒤 수정된 주문을 `OrderResource`로 반환합니다. 관리자 주문 상세에서 배송지 정정·메모 기록·상태 변경 등에 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/orders/{order}/cancel
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.orders.cancel -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.orders.cancel`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\OrderController@cancelOrder`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.orders.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order | path | string | 예 | — | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| type | body | string | 예 | `full`, `partial` | 취소 유형 (full 전체취소 / partial 부분취소 — partial 이면 items 필수) |
|
||||
| reason | body | string | 예 | — | 취소 사유 코드 (ClaimReason 의 refund·활성 코드) |
|
||||
| reason_detail | body | string | 아니오 | max 500 | 취소 사유 상세 (관리자 입력 자유 텍스트) |
|
||||
| items | body | array | 아니오 | min 1 | 처리 대상 항목 배열 |
|
||||
| cancel_pg | body | boolean | 아니오 | — | PG 결제 취소 동반 여부 (미지정 시 기본 true — 실제 PG 취소 수행) |
|
||||
| refund_priority | body | string | 아니오 | `pg_first`, `points_first` | 환불 배분 우선순위 (pg_first PG 우선 / points_first 포인트 우선, 기본 pg_first) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.orders.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 주문(`order`)을 전체취소 또는 부분취소합니다. `auth:sanctum` + `sirsoft-ecommerce.orders.update` 권한이 필요하며, `Admin\OrderController@cancelOrder`가 `items` 유무에 따라 `OrderCancellationService`의 `cancelOrder()`(전체) 또는 `cancelOrderOptions()`(부분)를 호출합니다. 취소자(`cancelledBy`)로 관리자 ID가 기록되고, `cancel_pg`로 PG 결제 취소 동반 여부를, `refund_priority`로 PG/포인트 환불 우선순위를 지정합니다. 취소 후 갱신된 주문을 `OrderResource`로 반환하며, 취소 불가 상태 등 실패 시 422를 반환합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/orders/{order}/confirm-deposit
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.orders.confirm-deposit -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.orders.confirm-deposit`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\OrderController@confirmDeposit`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.orders.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order | path | string | 예 | — | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| amount | body | number | 예 | min 0 | 확인된 입금액 (결제예정금액과 정확히 일치해야 함, 불일치 시 422) |
|
||||
| depositor_name | body | string | 아니오 | max 100 | depositor 이름 (식별자) |
|
||||
| mark_order_complete | body | boolean | 아니오 | — | 입금확인과 동시에 주문완료 처리 여부 (미지정 시 기본 false — 결제완료 전이만) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.orders.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 무통장(dbank) 미결제 주문(`order`)의 입금을 확인해 결제완료로 전이합니다. `auth:sanctum` + `sirsoft-ecommerce.orders.update` 권한이 필요하며, `Admin\OrderController@confirmDeposit`가 `OrderProcessingService::confirmManualDeposit()`으로 입금자명·입금액을 기록하고 결제완료 처리합니다. 입금액(`amount`)이 결제예정금액과 정확히 일치하지 않으면 422(deposit_amount_mismatch)를 반환하며, `mark_order_complete`로 결제완료와 동시에 주문완료 처리 여부를 지정할 수 있습니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/orders/{order}/estimate-refund
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.orders.estimate-refund -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.orders.estimate-refund`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\OrderController@estimateRefund`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.orders.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order | path | string | 예 | — | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| items | body | array | 예 | min 1 | 처리 대상 항목 배열 |
|
||||
| refund_priority | body | string | 아니오 | `pg_first`, `points_first` | 환불 배분 우선순위 (pg_first PG 우선 / points_first 포인트 우선, 기본 pg_first) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.orders.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 주문(`order`)의 선택 옵션(`items`) 취소 시 예상 환불 금액을 실제 취소 없이 미리 계산합니다. `auth:sanctum` + `sirsoft-ecommerce.orders.update` 권한이 필요하며, `Admin\OrderController@estimateRefund`가 `OrderCancellationService::previewRefund()`로 환불 예상값을 반환합니다. `refund_priority`에 따라 PG 우선/포인트 우선 환불 배분 결과가 달라집니다. 취소 화면에서 "환불 예정 금액"을 관리자에게 미리 보여주는 용도입니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/orders/{order}/logs
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.orders.logs -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.orders.logs`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\OrderController@logs`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.orders.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order | path | string | 예 | — | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| sort_order | query | string | 아니오 | — | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.orders.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 주문(`order`)의 활동 로그(주문·주문옵션·배송지 변경 이력 합산)를 페이지네이션 조회합니다. `auth:sanctum` + `sirsoft-ecommerce.orders.read` 권한이 필요하며, `Admin\OrderController@logs`가 `OrderService::getActivityLogs()`로 조회해 `ActivityLogResource`로 반환합니다. `sort_order`로 시간 정렬 방향을 지정할 수 있습니다. 관리자 주문 상세의 "처리 이력" 탭에서 누가 언제 무엇을 변경했는지 추적하는 용도입니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/orders/{order}/options/bulk-status
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.orders.options.bulk-status -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.orders.options.bulk-status`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\OrderController@bulkChangeOptionStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.orders.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order | path | string | 예 | — | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| items | body | array | 예 | min 1 | 처리 대상 항목 배열 |
|
||||
| status | body | string | 예 | — | 일괄 전환할 옵션 상태 (OrderStatusEnum 값, 옵션별 전이 규칙 검증) |
|
||||
| carrier_id | body | integer | 아니오 | — | carrier 식별자 |
|
||||
| tracking_number | body | string | 아니오 | max 50 | 송장(운송장)번호 (배송 관련 상태로 전환 시 carrier_id 와 함께 필수) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.orders.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 주문(`order`)의 여러 주문 옵션 상태를 수량 분할까지 지원해 일괄 변경합니다. `auth:sanctum` + `sirsoft-ecommerce.orders.update` 권한이 필요하며, `Admin\OrderController@bulkChangeOptionStatus`가 `status`를 `OrderStatusEnum`으로 변환한 뒤 `OrderOptionService::bulkChangeStatusWithQuantity()`로 처리합니다. 배송중으로 전환 시 `carrier_id`·`tracking_number`(택배사·송장번호)를 함께 넘길 수 있습니다. 한 옵션의 일부 수량만 상태 전환(부분 배송 등)하는 시나리오를 지원합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/orders/{order}/reset-guest-lookup-password
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.orders.reset-guest-lookup-password -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.orders.reset-guest-lookup-password`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\OrderController@resetGuestLookupPassword`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.orders.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order | path | string | 예 | — | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| guest_lookup_password | body | string | 예 | min 8, max 255 | 재설정할 비회원 주문 조회 비밀번호 (8자 이상, 해시로 저장 · 회원가입 정책과 동일) |
|
||||
| guest_lookup_password_confirmation | body | string | 예 | — | 조회 비밀번호 확인 (guest_lookup_password 와 일치해야 함) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.orders.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 비회원 주문(`order`)의 조회 비밀번호를 재설정합니다. `auth:sanctum` + `sirsoft-ecommerce.orders.update` 권한이 필요하며, 비회원 주문(`user_id IS NULL`)만 허용하고 회원 주문에는 422를 반환합니다. `Admin\OrderController@resetGuestLookupPassword`가 `OrderService::resetGuestLookupPassword()`로 새 비밀번호를 해시로 저장하며, 평문은 응답/로그에 노출하지 않습니다. 비회원이 조회 비밀번호를 분실했을 때 관리자가 대신 재설정해 주는 용도입니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/orders/{order}/send-email
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.orders.send-email -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.orders.send-email`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\OrderController@sendEmail`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.orders.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| order | path | string | 예 | — | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| email | body | email | 예 | max 255 | 이메일 주소 |
|
||||
| message | body | string | 예 | max 5000 | 관리자가 작성한 안내 메일 본문 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.orders.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 주문(`order`)에 대해 주문 관련 안내 이메일을 지정 주소(`email`)로 발송합니다. `auth:sanctum` + `sirsoft-ecommerce.orders.update` 권한이 필요하며, `Admin\OrderController@sendEmail`이 `OrderService::sendEmail()`로 관리자가 작성한 메시지(`message`)를 전송합니다. 주문 관련 개별 안내가 필요할 때 관리자가 상세 화면에서 수동으로 메일을 보내는 용도입니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/orders/{orderNumber}/cancel-payment
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.orders.cancel-payment -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.orders.cancel-payment`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\OrderController@cancelPayment`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| orderNumber | path | string | 예 | — | 대상 order number의 식별자 |
|
||||
| cancel_code | body | string | 아니오 | max 100 | PG사 취소 코드 (예: USER_CANCEL, order_payments 취소 이력에 기록) |
|
||||
| cancel_message | body | string | 아니오 | max 500 | PG사 취소 메시지 (order_payments 취소 이력에 기록) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 회원/비회원이 PG 결제창을 닫았을 때 결제 취소 이력만 기록합니다. `optional.sanctum`으로 회원/비회원 모두 접근하며, `Public\OrderController@cancelPayment`가 `OrderProcessingService::recordPaymentCancellation()`으로 주문 상태는 변경하지 않고 `order_payments`에 취소창 닫힘 이력(`cancel_code`·`cancel_message`)만 남깁니다. 결제 SDK가 사용자 취소 콜백을 받았을 때 프론트가 호출해 결제 시도 이력을 추적하는 용도입니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/orders
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.orders.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.orders.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\OrderController@index`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 50 | 페이지당 항목 수 |
|
||||
| status | query | string | 아니오 | — | 상태 필터 (해당 상태의 항목만 조회) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `452` | 기본 키 (내부 식별자) |
|
||||
| order_number | string | `20260625-1144420949` | 주문번호 (사용자 노출용 고유 식별 코드) |
|
||||
| status | string | `shipping` | 주문상태 값 (OrderStatusEnum value — 마이페이지용 status 별칭) |
|
||||
| status_label | string | `배송중` | 상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
|
||||
| status_variant | string | `primary` | 상태 표시 색상/스타일 변형 키 (상태 Enum variant() 산물 — UI 배지용) |
|
||||
| is_partially_cancelled | boolean | `false` | partially cancelled 여부 |
|
||||
| recipient_country_code | string | `KR` | 배송국가 코드 (ISO 3166-1 alpha-2, shippingAddress 로드 시) |
|
||||
| recipient_country_name | object | `{"ko":"한국","en":"South Korea"}` | 배송국가 현지화명 (로케일별 국가명 맵) |
|
||||
| ordered_at | string | `2026-06-25T11:44:42+00:00` | ordered 일시 |
|
||||
| ordered_at_formatted | string | `2026-06-25 20:44:42` | `ordered_at` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_amount | integer | `31000` | 최종 주문금액 (상품합계 − 할인 + 배송비) |
|
||||
| total_amount_formatted | string | `31,000원` | `total_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| mc_total_amount | object | `{"KRW":{"amount":31000,"formatted":"31,000원"},"USD":{"amo…` | 최종 주문금액 다중 통화 (주문 시점 스냅샷, 통화별 amount·formatted) |
|
||||
| total_shipping_amount | integer | `0` | 총 배송비 |
|
||||
| total_shipping_amount_formatted | string | `0원` | `total_shipping_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| mc_total_shipping_amount | object | `{"KRW":{"amount":0,"formatted":"0원"},"USD":{"amount":0,"f…` | 총 배송비 다중 통화 (주문 시점 스냅샷, 통화별 amount·formatted) |
|
||||
| total_points_used_amount | integer | `0` | 총 포인트(마일리지) 사용액 |
|
||||
| total_points_used_amount_formatted | string | `0원` | `total_points_used_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| total_earned_points_amount | integer | `310` | 총 적립 예정 포인트 |
|
||||
| total_earned_points_amount_formatted | string | `310원` | `total_earned_points_amount` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| items | array | `[{"product_name":"프리미엄 샤인머스캣 2kg #94","product_option_nam…` | 주문 품목 목록 (상품명·옵션명·썸네일·수량·단가/소계·추가옵션 요약) |
|
||||
| item_count | integer | `1` | item 개수 (집계) |
|
||||
| abilities | object | `{"can_view":true,"can_cancel":false}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 회원이 마이페이지 주문내역에서 본인 주문 목록을 상태별 통계와 함께 페이지네이션 조회합니다. `auth:sanctum` 인증이 필요하며, `User\OrderController@index`가 `user_id`를 본인으로 고정한 뒤 `OrderService::getList()`와 `getUserStatistics()`를 호출해 `UserOrderCollection`으로 반환합니다. `status`로 특정 주문상태만 필터링할 수 있습니다. 관리자 목록과 달리 항상 본인 주문으로만 한정됩니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/user/orders
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.orders.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.orders.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\OrderController@store`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근) + `permission:sirsoft-ecommerce.user-orders.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| payment_method | body | string | 예 | — | 결제수단 (PaymentMethodEnum 값 — card/vbank/dbank 등) |
|
||||
| expected_total_amount | body | number | 예 | min 0 | 프론트가 계산한 예상 결제금액 (서버 재계산값과 대조해 금액 위변조 검증) |
|
||||
| shipping_memo | body | string | 아니오 | max 500 | 배송 요청사항 메모 |
|
||||
| depositor_name | body | string | 아니오 | max 50 | depositor 이름 (식별자) |
|
||||
| save_shipping_address | body | boolean | 아니오 | — | 회원 주소록에 이번 배송지 저장 여부 (회원 주문 한정) |
|
||||
| guest_lookup_password | body | string | 예 | min 8, max 255 | 비회원 주문 조회 비밀번호 (비회원만 필수, 8자 이상 · 해시로 저장) |
|
||||
| guest_lookup_password_confirmation | body | string | 예 | — | 조회 비밀번호 확인 (guest_lookup_password 와 일치해야 함) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.order.create_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.user-orders.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 주문서 작성을 마치고 실제 주문을 생성(결제하기)하는 회원/비회원 공용 엔드포인트입니다. PG 플러그인의 fetch 인터셉터가 이 한 경로만 매칭하므로 회원/비회원이 동일 URL로 진입하고, `Public\OrderController@store`가 `Auth::id()`로 분기합니다(회원은 `OrderResource`, 비회원은 민감 필드를 가린 `GuestOrderResource`). `optional.sanctum` + `sirsoft-ecommerce.user-orders.create` 권한이 필요하며, `expected_total_amount`로 금액 위변조를 검증하고 비회원은 `guest_lookup_password`로 이후 조회 비밀번호를 설정합니다. 회원이 `save_shipping_address`를 켜면 배송지가 자동 저장(PG 결제는 결제완료 시점) 됩니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/orders/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.orders.show-by-id -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.orders.show-by-id`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\OrderController@show`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 회원이 마이페이지 주문 상세에서 주문 ID(`id`)로 본인 주문의 전체 상세를 조회합니다. `auth:sanctum` 인증이 필요하며, `User\OrderController@show`가 `OrderService::getDetail()`로 로드한 뒤 소유자 검증(`user_id === Auth::id()`)을 거쳐 `OrderResource`로 반환합니다. 본인 주문이 아니거나 존재하지 않으면 정보 노출 방지를 위해 404를 반환합니다. 주문번호로 조회하는 `showByOrderNumber`와 달리 내부 주문 ID를 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/user/orders/{id}/cancel
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.orders.cancel -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.orders.cancel`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\OrderController@cancel`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.user-orders.cancel`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| reason | body | string | 예 | — | 취소 사유 코드 (ClaimReason 의 refund·활성·사용자 선택 가능 코드) |
|
||||
| reason_detail | body | string | 아니오 | max 500 | 취소 사유 상세 (회원 입력 자유 텍스트) |
|
||||
| items | body | array | 아니오 | min 1 | 처리 대상 항목 배열 |
|
||||
| refund_priority | body | string | 아니오 | `pg_first`, `points_first` | 환불 배분 우선순위 (pg_first PG 우선 / points_first 포인트 우선, 기본 pg_first) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.user-orders.cancel`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 회원이 마이페이지에서 본인 주문(`id`)을 취소합니다. `auth:sanctum` + `sirsoft-ecommerce.user-orders.cancel` 권한이 필요하며, `User\OrderController@cancel`이 `items` 유무에 따라 `OrderCancellationService`의 `cancelOrderOptions()`(부분) 또는 `cancelOrder()`(전체)를 호출합니다. 취소자(`cancelledBy`)로 회원 본인 ID가 기록되고, `refund_priority`로 PG/포인트 환불 우선순위를 지정합니다. 취소 가능 상태의 주문만 취소되며, 취소 후 갱신된 주문을 `OrderResource`로 반환합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/user/orders/{id}/estimate-refund
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.orders.estimate-refund -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.orders.estimate-refund`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\OrderController@estimateRefund`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.user-orders.cancel`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| items | body | array | 예 | min 1 | 처리 대상 항목 배열 |
|
||||
| refund_priority | body | string | 아니오 | `pg_first`, `points_first` | 환불 배분 우선순위 (pg_first PG 우선 / points_first 포인트 우선, 기본 pg_first) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.user-orders.cancel`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 회원이 마이페이지에서 본인 주문(`id`)의 선택 옵션(`items`) 취소 시 예상 환불 금액을 실제 취소 없이 미리 계산합니다. `auth:sanctum` + `sirsoft-ecommerce.user-orders.cancel` 권한이 필요하며, `User\OrderController@estimateRefund`가 `OrderCancellationService::previewRefund()`로 환불 예상값을 반환합니다. `refund_priority`에 따라 PG 우선/포인트 우선 환불 배분 결과가 달라집니다. 취소 확정 전 "환불 예정 금액"을 회원에게 안내하는 용도입니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/user/orders/{id}/options/{optionId}/confirm
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.orders.confirm-option -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.orders.confirm-option`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\OrderController@confirmOption`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.user-orders.confirm`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| optionId | path | string | 예 | — | 대상 option의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.user-orders.confirm`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 회원이 마이페이지에서 본인 주문(`id`)의 개별 옵션(`optionId`)을 구매확정합니다. `auth:sanctum` + `sirsoft-ecommerce.user-orders.confirm` 권한이 필요하며, `User\OrderController@confirmOption`이 `OrderService::confirmOption()`을 호출합니다. 구매확정 시 적립 포인트 확정 등 후속 처리가 이어지며, 확정 불가 상태(배송 미완료 등)면 422를 반환합니다. 배송 완료된 상품을 회원이 직접 "구매확정" 할 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/user/orders/{id}/reorder
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.orders.reorder -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.orders.reorder`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\OrderController@reorder`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 회원이 과거 주문(`id`)의 옵션들을 현재 장바구니에 다시 담는 재주문 기능입니다. `auth:sanctum` 인증이 필요하며, `User\OrderController@reorder`가 `CartService::reorderFromOrder()`로 처리해 담긴 수량(`added_count`), 담지 못한 항목(`skipped[]`), 현재 장바구니 총 개수(`cart_count`)를 반환합니다. 취소된 주문도 재주문 대상이 되며, 품절·단종 등으로 추가 불가한 항목은 건너뛰어 `skipped` 배열로 안내합니다. 마이페이지 주문내역의 "재주문" 버튼에 사용합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/user/orders/{id}/shipping-address
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.orders.update-shipping-address -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.orders.update-shipping-address`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\OrderController@updateShippingAddress`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| address_id | body | integer | 아니오 | — | address 식별자 |
|
||||
| recipient_name | body | string | 아니오 | max 50 | 수령인 이름 |
|
||||
| recipient_phone | body | string | 아니오 | max 20 | 수령인 연락처 |
|
||||
| country_code | body | string | 아니오 | — | 국가 코드 (ISO 3166-1 alpha-2) |
|
||||
| zipcode | body | string | 아니오 | max 10 | 우편번호 |
|
||||
| address | body | string | 아니오 | max 255 | 기본 주소 |
|
||||
| address_detail | body | string | 아니오 | max 255 | 상세 주소 |
|
||||
| address_line_1 | body | string | 아니오 | max 255 | 주소 1행 (기본 주소) |
|
||||
| address_line_2 | body | string | 아니오 | max 255 | 주소 2행 (상세 주소) |
|
||||
| intl_city | body | string | 아니오 | max 100 | 도시 (국제 주소) |
|
||||
| intl_state | body | string | 아니오 | max 100 | 주/도 (국제 주소) |
|
||||
| intl_postal_code | body | string | 아니오 | max 20 | 우편번호 (국제 주소) |
|
||||
| delivery_memo | body | string | 아니오 | max 255 | 배송 메모 (배송 시 요청사항) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.order.shipping_address_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 회원이 배송 전 상태의 본인 주문(`id`) 배송지를 변경합니다. `auth:sanctum` 인증이 필요하며, `User\OrderController@updateShippingAddress`가 소유자 검증 후 `OrderService::updateShippingAddress()`로 처리합니다. 저장된 회원 주소(`address_id`)를 선택하거나 수취인·연락처·주소 필드를 직접 입력할 수 있고, 국내(`zipcode`/`address`)와 해외(`address_line_1`·`intl_city` 등) 주소를 모두 지원합니다. 이미 배송이 시작된 주문 등 변경 불가 상태면 422를 반환합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/orders/{orderNumber}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.orders.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.orders.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\OrderController@showByOrderNumber`
|
||||
- **인증/권한**: `optional.sanctum` (선택적 인증: 회원/비회원 모두 접근)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| orderNumber | path | string | 예 | — | 대상 order number의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 주문번호(`orderNumber`)로 주문 상세를 조회하는 회원/비회원 공용 엔드포인트입니다. `optional.sanctum`으로 로그인 여부에 따라 분기하는데, 로그인 상태면 본인 회원 주문만 `OrderResource`로 반환하고 아니면 404(마이페이지 주문 목록으로 안내), 비로그인이면 `X-Guest-Order-Token`으로 비회원 주문을 매칭해 `GuestOrderResource`로 반환하고 실패 시 404(비회원 조회 폼으로 안내)합니다. 회원이 비회원 토큰을 들고 와도 회원 분기가 우선하며, 실패 사유는 모두 동일한 404로 처리해 정보 노출을 차단합니다. 결제 완료 후 주문번호 기반 주문 완료/상세 페이지에서 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Payments API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Payments 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/payments/client-config/{provider}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.payments.client-config -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.payments.client-config`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Shop\PaymentConfigController@clientConfig`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| provider | path | string | 예 | — | 대상 provider의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** PG 제공자(`provider`, 예: `tosspayments`)의 프론트엔드 결제 SDK 초기화에 필요한 클라이언트 설정을 반환하는 공개 엔드포인트입니다. 인증이 필요 없으며, 결제 페이지가 결제창을 띄우기 직전에 호출합니다. 실제 설정값은 `PaymentConfigController@clientConfig`가 `sirsoft-ecommerce.payment.get_client_config` 필터 훅을 실행해 각 PG 플러그인이 등록한 `client_key`·`sdk_url` 등을 수집한 결과이며, 코어는 어떤 PG도 하드코딩하지 않습니다. 해당 provider에 등록된 설정이 없으면(플러그인 미설치·미활성) 404를 반환합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
# Presets API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Presets 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/presets
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.presets.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.presets.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\SearchPresetController@index`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| target_screen | query | string | 아니오 | `products`, `orders`, `coupons` | 대상 검색 화면 (해당 화면의 프리셋만 조회, 미지정 시 `products`) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.search_preset.list_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자 검색 화면(상품/주문/쿠폰 등)에서 저장해 둔 검색 조건 프리셋 목록을 조회합니다. `auth:sanctum` 인증이 필요하며, `SearchPresetService::getPresets()`가 `target_screen`에 해당하는 프리셋을 반환합니다(미지정 시 `products` 화면 기준). 관리자가 자주 쓰는 필터 조합을 프리셋으로 관리해 검색 화면에서 빠르게 적용하기 위한 용도이며, 확장이 `list_validation_rules` 훅으로 조회 파라미터를 추가할 수 있습니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/presets
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.presets.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.presets.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\SearchPresetController@store`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| target_screen | body | string | 아니오 | — | 프리셋이 속할 검색 화면 (`products`/`orders`/`coupons`, 미지정 시 `products`) |
|
||||
| name | body | string | 예 | max 100 | 대상의 이름/명칭 |
|
||||
| conditions | body | array | 예 | — | 저장할 검색 조건 배열 (필터 필드/값 조합, 적용 시 그대로 복원됨) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.preset.store_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자 검색 화면의 새 검색 조건 프리셋을 생성합니다. `auth:sanctum` 인증이 필요하며, `SearchPresetService::create()`가 `target_screen`(미지정 시 `products`)·`name`(최대 100자)·`conditions`(검색 조건 배열)을 받아 프리셋을 저장하고 성공 시 `201`로 생성된 프리셋을 반환합니다. 자주 쓰는 필터 조합을 이름 붙여 저장해 재사용하기 위한 용도이며, 확장이 `preset.store_validation_rules` 훅으로 파라미터를 추가할 수 있습니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/presets/{preset}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.presets.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.presets.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\SearchPresetController@destroy`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| preset | path | string | 예 | — | 대상 preset의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 지정한 검색 조건 프리셋 1건을 삭제합니다. `auth:sanctum` 인증이 필요하며, path의 `{preset}`은 라우트 모델 바인딩으로 `SearchPreset` 모델이 주입되고 `SearchPresetService::delete()`가 삭제를 수행합니다. 삭제 성공 시 `{ "deleted": true }`를 반환하며, 존재하지 않는 프리셋이면 `404`를 반환합니다. 더 이상 사용하지 않는 저장 검색 조합을 정리하는 용도입니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/presets/{preset}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.presets.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.presets.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\SearchPresetController@update`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| preset | path | string | 예 | — | 대상 preset의 식별자 |
|
||||
| name | body | string | 예 | max 100 | 대상의 이름/명칭 |
|
||||
| conditions | body | array | 예 | — | 저장할 검색 조건 배열 (필터 필드/값 조합, 적용 시 그대로 복원됨) |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.preset.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 기존 검색 조건 프리셋 1건을 수정합니다. `auth:sanctum` 인증이 필요하며, path의 `{preset}`은 라우트 모델 바인딩으로 주입되고 `SearchPresetService::update()`가 `name`(최대 100자)·`conditions`(검색 조건 배열)·선택 `sort_order`(정렬 순서, 0 이상)를 반영해 저장 후 갱신된 프리셋을 반환합니다. 저장해 둔 필터 조합의 이름·조건·노출 순서를 변경하는 용도이며, 확장이 `preset.update_validation_rules` 훅으로 파라미터를 추가할 수 있습니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
# Product Common Infos API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Product Common Infos 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/product-common-infos
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-common-infos.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-common-infos.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductCommonInfoController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-common-infos.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `207` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"일반 배송 안내","en":"Standard Shipping"}` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| localized_name | string | `일반 배송 안내` | `name` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| content | object | `{"ko":"• 배송 기간: 결제 완료 후 1~3일 이내 출고 (영업일 기준)\n• 배송 업체: CJ대…` | 본문 내용 |
|
||||
| localized_content | string | `• 배송 기간: 결제 완료 후 1~3일 이내 출고 (영업일 기준) …` | `content` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| content_mode | string | `text` | 내용 표시 모드 (`text` 일반 텍스트 / `html` HTML, 기본값 `text`) |
|
||||
| is_default | boolean | `true` | default 여부 |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| sort_order | integer | `0` | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| icon | string | `info-circle` | 아이콘 식별자 (아이콘 클래스/이름) |
|
||||
| created_at | string | `2026-06-15 11:24:00` | 생성 일시 |
|
||||
| updated_at | string | `2026-06-15 11:24:00` | 최종 수정 일시 |
|
||||
| products_count | integer | `81` | products 개수 (집계) |
|
||||
| language_count | integer | `2` | language 개수 (집계) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-common-infos.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품 공통정보(배송·교환·반품 안내 등 여러 상품에 재사용되는 안내문) 목록을 조회합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-common-infos.read` 권한이 필요하며, `ProductCommonInfoController@index`가 `search`·`active_only`·`default_only` 필터를 조립합니다. `per_page`가 0 이하이거나 `all`이면 `ProductCommonInfoService::getAllCommonInfos()`로 전체를 조회하고, 그 외에는 `getPaginatedCommonInfos()`로 페이지네이션 조회(`data.pagination` 포함)합니다. `localized_name`·`localized_content`는 현재 로케일로 해석된 값, `products_count`는 이 공통정보를 사용하는 상품 수입니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/product-common-infos
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-common-infos.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-common-infos.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductCommonInfoController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-common-infos.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| content | body | array | 아니오 | — | 본문 내용 |
|
||||
| content_mode | body | string | 아니오 | `text`, `html` | 내용 표시 모드 (`text` 일반 텍스트 / `html` HTML, 미지정 시 `text`) |
|
||||
| is_default | body | boolean | 아니오 | — | 기본값 지정 여부 |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.product-common-info.create_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-common-infos.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 새 상품 공통정보를 생성합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-common-infos.create` 권한이 필요하며, `ProductCommonInfoController@store`가 `ProductCommonInfoService::createCommonInfo()`에 검증된 데이터를 전달해 저장합니다. `name`은 다국어 배열(필수), `content`는 다국어 안내 내용, `content_mode`는 `text`/`html` 중 하나이며, `is_default`·`is_active`·`sort_order`로 기본 사용 여부·활성 여부·정렬을 지정합니다. 확장이 `sirsoft-ecommerce.product-common-info.create_validation_rules` 필터로 추가 파라미터를 붙일 수 있고, 성공 시 HTTP 201을, 처리 실패 시 400 에러 응답을 반환합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/product-common-infos/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-common-infos.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-common-infos.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductCommonInfoController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-common-infos.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-common-infos.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품 공통정보 1건을 삭제합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-common-infos.delete` 권한이 필요하며, `ProductCommonInfoController@destroy`가 `ProductCommonInfoService::deleteCommonInfo()`를 호출해 삭제합니다. path의 `id`에 해당하는 공통정보가 없거나 삭제 처리 중 오류가 발생하면 각각 404/400 에러 응답을 반환합니다. 여러 상품에서 참조 중인 공통정보를 삭제할 경우 노출에 영향을 줄 수 있으므로 `products_count`를 먼저 확인하는 것이 좋습니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/product-common-infos/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-common-infos.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-common-infos.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductCommonInfoController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-common-infos.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-common-infos.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품 공통정보 1건의 상세를 조회합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-common-infos.read` 권한이 필요하며, `ProductCommonInfoController@show`가 `ProductCommonInfoService::getCommonInfo()`로 단건을 조회합니다. 다국어 원본(`name`, `content`)과 현재 로케일 해석값(`localized_name`, `localized_content`), `content_mode`, 기본/활성 여부를 함께 반환하며, 해당 `id`의 공통정보가 없으면 404를 반환합니다. 주로 수정 화면 진입 시 기존 값을 불러오는 데 사용됩니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/product-common-infos/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-common-infos.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-common-infos.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductCommonInfoController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-common-infos.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| content | body | array | 아니오 | — | 본문 내용 |
|
||||
| content_mode | body | string | 아니오 | `text`, `html` | 내용 표시 모드 (`text` 일반 텍스트 / `html` HTML, 미지정 시 `text`) |
|
||||
| is_default | body | boolean | 아니오 | — | 기본값 지정 여부 |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.product-common-info.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-common-infos.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품 공통정보 1건을 수정합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-common-infos.update` 권한이 필요하며, `ProductCommonInfoController@update`가 `ProductCommonInfoService::updateCommonInfo()`에 검증된 데이터를 전달해 갱신합니다. `name`(다국어 배열)은 필수이고 `content`·`content_mode`·`is_default`·`is_active`·`sort_order`를 함께 변경할 수 있습니다. 확장이 `sirsoft-ecommerce.product-common-info.update_validation_rules` 필터로 파라미터를 추가할 수 있으며, 대상이 없거나 처리 실패 시 각각 404/400 에러 응답을 반환합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/product-common-infos/{id}/toggle-active
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-common-infos.toggle-active -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-common-infos.toggle-active`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductCommonInfoController@toggleActive`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-common-infos.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-common-infos.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품 공통정보의 활성/비활성 상태를 한 번의 요청으로 토글합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-common-infos.update` 권한이 필요하며, `ProductCommonInfoController@toggleActive`가 `ProductCommonInfoService::toggleActive()`를 호출해 현재 `is_active` 값을 반전시킵니다. 반전 결과에 따라 활성화/비활성화 메시지를 구분해 응답하므로 목록 화면의 스위치 조작에 적합합니다. 대상이 없거나 처리 실패 시 각각 404/400 에러 응답을 반환합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Product Image API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Product Image 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/product-image/{hash}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.product-image.download -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.product-image.download`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\ProductImageController@download`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| hash | path | string | 예 | — | 대상 리소스의 해시 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 공개 API로, 해시(`hash`, 12자)로 식별되는 상품 이미지 원본 파일을 스트리밍 서빙합니다. 인증이 필요 없으며(`PublicBaseController`), `ProductImageController@download`가 먼저 `ProductImageService::findByHash()`로 이미지 레코드 존재를 확인한 뒤 `ProductImageService::download()`로 `StorageInterface::response()` 기반 `StreamedResponse`를 반환합니다. 응답에는 저장된 `mime_type`과 `Cache-Control: public, max-age=31536000`(1년) 헤더가 부여되어 브라우저/CDN 캐싱에 최적화됩니다. 해시에 해당하는 레코드가 없거나 스토리지에 실제 파일이 없으면 404 에러 응답을 반환합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
# Product Labels API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Product Labels 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/product-labels
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-labels.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-labels.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductLabelController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-labels.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| is_active | query | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| active_only | query | boolean | 아니오 | — | 활성 라벨만 필터 (true 시 내부적으로 `is_active=true` 로 변환 — 기존 호환용) |
|
||||
| search | query | string | 아니오 | max 100 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
|
||||
| sort | query | string | 아니오 | `name_asc`, `name_desc`, `created_asc`, `created_desc` | 정렬 기준 (필드명, `-` 접두 시 내림차순) |
|
||||
| locale | query | string | 아니오 | `ko`, `en`, `fr`, `ja` | 로케일 코드 (표시 언어/지역) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `37` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"API 문서 샘플 라벨","en":"API Doc Sample Label"}` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| color | string | `#6B7280` | 라벨 색상 코드 (`#RRGGBB` 6자리 HEX, 뱃지 배경/글자색 등 표시에 사용) |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| sort_order | integer | `0` | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| created_at | string | `2026-07-07 14:47:31` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-07 14:47:31` | 최종 수정 일시 |
|
||||
| assignments_count | integer | `0` | assignments 개수 (집계) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-labels.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품 라벨(예: "신상품", "베스트") 목록을 조회합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-labels.read` 권한이 필요하며, `ProductLabelController@index`가 `ProductLabelService::getAllLabels()`에 검증된 필터를 전달해 조회합니다. `is_active` 또는 `active_only` 로 활성 라벨만 필터링하고, `search`(라벨명 검색), `sort`(이름/생성일 정렬), `locale`(다국어 정렬 기준)을 지원합니다. `active_only=true` 는 내부적으로 `is_active=true` 로 변환되어 기존 호환성을 유지하며, 각 항목의 `assignments_count` 로 라벨이 몇 개 상품에 부여됐는지 확인할 수 있습니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/product-labels
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-labels.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-labels.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductLabelController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-labels.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| color | body | string | 예 | max 20 | 라벨 색상 코드 (필수, `#RRGGBB` 6자리 HEX 형식만 허용) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-labels.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 새 상품 라벨을 생성합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-labels.create` 권한이 필요하며, `ProductLabelController@store`가 `ProductLabelService::createLabel()`에 검증된 데이터를 넘겨 저장합니다. `name`은 다국어 배열({ko, en, ...}), `color`는 라벨 색상 코드(최대 20자)이고, `is_active`·`sort_order`로 활성 여부와 정렬 순서를 지정합니다. 성공 시 HTTP 201과 함께 생성된 라벨 리소스를 반환합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/product-labels/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-labels.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-labels.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductLabelController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-labels.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-labels.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품 라벨 1건을 삭제합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-labels.delete` 권한이 필요하며, `ProductLabelController@destroy`가 `ProductLabelService::deleteLabel()`을 호출해 삭제합니다. path의 `id`에 해당하는 라벨이 없으면 404를 반환하고, 삭제 중 오류가 발생하면 400 에러 응답을 반환합니다. 삭제 시 해당 라벨과 상품 간의 부여(assignment) 관계도 함께 정리됩니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/product-labels/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-labels.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-labels.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductLabelController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-labels.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-labels.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품 라벨 1건의 상세 정보를 조회합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-labels.read` 권한이 필요하며, `ProductLabelController@show`가 `ProductLabelService::getLabel()`로 단건을 조회합니다. 다국어 라벨명(`name`), 색상, 활성 여부, 정렬 순서와 함께 `assignments_count`를 반환하며, 해당 `id`의 라벨이 없으면 404를 반환합니다. 주로 라벨 수정 화면 진입 시 기존 값을 불러오는 데 사용됩니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/product-labels/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-labels.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-labels.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductLabelController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-labels.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| color | body | string | 예 | max 20 | 라벨 색상 코드 (필수, `#RRGGBB` 6자리 HEX 형식만 허용) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-labels.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 기존 상품 라벨 1건을 수정합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-labels.update` 권한이 필요하며, `ProductLabelController@update`가 `ProductLabelService::updateLabel()`에 검증된 데이터를 전달해 갱신합니다. `name`(다국어 배열)과 `color`는 필수이며, `is_active`·`sort_order`도 함께 변경할 수 있습니다. 대상 라벨이 없으면 404, 갱신 처리 중 오류가 발생하면 400 에러 응답을 반환합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/product-labels/{id}/toggle-status
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-labels.toggle-status -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-labels.toggle-status`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductLabelController@toggleStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-labels.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-labels.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품 라벨의 활성/비활성 상태를 한 번의 요청으로 토글합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-labels.update` 권한이 필요하며, `ProductLabelController@toggleStatus`가 `ProductLabelService::toggleStatus()`를 호출해 현재 `is_active` 값을 반전시킵니다. 별도의 본문 없이 path의 `id`만으로 동작하므로 목록 화면에서 스위치 조작으로 즉시 노출 여부를 바꾸는 데 적합합니다. 대상 라벨이 없으면 404, 처리 중 오류가 발생하면 400 에러 응답을 반환합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
# Product Notice Templates API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Product Notice Templates 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/product-notice-templates
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-notice-templates.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-notice-templates.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductNoticeTemplateController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-notice-templates.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| search | query | string | 아니오 | max 200 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
|
||||
| active_only | query | boolean | 아니오 | — | true 시 활성(is_active) 템플릿만 조회 |
|
||||
| per_page | query | string | 아니오 | — | 페이지당 항목 수 |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `172` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"API 문서 샘플 고시템플릿","en":"API Doc Sample Notice Templ…` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| localized_name | string | `API 문서 샘플 고시템플릿` | `name` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| category | string | `clothing` | 이 템플릿이 적용되는 품목 카테고리 식별자 |
|
||||
| fields | array | `[{"label":"품명","value":"샘플"}]` | 고시 항목 정의 배열 (항목별 name/content 다국어 — 상품 등록 시 고시 항목 자동 채움에 사용) |
|
||||
| fields_count | integer | `1` | fields 개수 (집계) |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| sort_order | integer | `0` | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| icon | string | `file-alt` | 아이콘 식별자 (아이콘 클래스/이름) |
|
||||
| created_at | string | `2026-07-07 14:47:31` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-07 14:47:31` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-notice-templates.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품정보제공고시 템플릿(전자상거래법상 품목별 필수 고지 항목 세트) 목록을 조회합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-notice-templates.read` 권한이 필요하며, `ProductNoticeTemplateController@index`가 `search`·`active_only` 필터를 조립합니다. `per_page`가 0 이하이거나 `all`이면 `ProductNoticeTemplateService::getAllTemplates()`로 전체를, 그 외에는 `getPaginatedTemplates()`로 페이지네이션 조회(`data.pagination` 포함)합니다. 각 항목은 다국어 템플릿명, 품목 `category`, 고시 항목 배열 `fields`(및 `fields_count`)를 포함합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/product-notice-templates
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-notice-templates.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-notice-templates.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductNoticeTemplateController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-notice-templates.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| category | body | string | 아니오 | max 100 | 이 템플릿이 적용되는 품목 카테고리 식별자 |
|
||||
| fields | body | array | 예 | min 1 | 고시 항목 정의 배열 (항목별 name/content 다국어, 최소 1개) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.product-notice-template.create_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-notice-templates.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 새 상품정보제공고시 템플릿을 생성합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-notice-templates.create` 권한이 필요하며, `ProductNoticeTemplateController@store`가 `ProductNoticeTemplateService::createTemplate()`에 검증된 데이터를 전달해 저장합니다. `name`(다국어 배열)과 `fields`(고시 항목 정의, 최소 1개)는 필수이고, `category`(품목 카테고리), `is_active`, `sort_order`는 선택입니다. 확장이 `sirsoft-ecommerce.product-notice-template.create_validation_rules` 필터로 파라미터를 추가할 수 있으며, 성공 시 HTTP 201을, 처리 실패 시 400 에러 응답을 반환합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/product-notice-templates/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-notice-templates.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-notice-templates.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductNoticeTemplateController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-notice-templates.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-notice-templates.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품정보제공고시 템플릿 1건을 삭제합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-notice-templates.delete` 권한이 필요하며, `ProductNoticeTemplateController@destroy`가 `ProductNoticeTemplateService::deleteTemplate()`를 호출해 삭제합니다. path의 `id`에 해당하는 템플릿이 없거나 삭제 처리 중 오류가 발생하면 각각 404/400 에러 응답을 반환합니다. 삭제된 템플릿은 이후 신규 상품의 고시 항목 자동 채움에 더 이상 사용되지 않습니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/product-notice-templates/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-notice-templates.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-notice-templates.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductNoticeTemplateController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-notice-templates.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-notice-templates.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품정보제공고시 템플릿 1건의 상세를 조회합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-notice-templates.read` 권한이 필요하며, `ProductNoticeTemplateController@show`가 `ProductNoticeTemplateService::getTemplate()`로 단건을 조회합니다. 다국어 템플릿명(`name`, `localized_name`), 품목 `category`, 고시 항목 배열 `fields`, 활성 여부·정렬 순서를 반환하며, 해당 `id`의 템플릿이 없으면 404를 반환합니다. 주로 템플릿 수정 화면 진입 시 기존 고시 항목을 불러오는 데 사용됩니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/product-notice-templates/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-notice-templates.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-notice-templates.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductNoticeTemplateController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-notice-templates.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| category | body | string | 아니오 | max 100 | 이 템플릿이 적용되는 품목 카테고리 식별자 |
|
||||
| fields | body | array | 예 | min 1 | 고시 항목 정의 배열 (항목별 name/content 다국어, 최소 1개) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.product-notice-template.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-notice-templates.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품정보제공고시 템플릿 1건을 수정합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-notice-templates.update` 권한이 필요하며, `ProductNoticeTemplateController@update`가 `ProductNoticeTemplateService::updateTemplate()`에 검증된 데이터를 전달해 갱신합니다. `name`(다국어 배열)과 `fields`(최소 1개)는 필수이고, `category`·`is_active`·`sort_order`도 함께 변경할 수 있습니다. 확장이 `sirsoft-ecommerce.product-notice-template.update_validation_rules` 필터로 파라미터를 추가할 수 있으며, 대상이 없거나 처리 실패 시 각각 404/400 에러 응답을 반환합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/product-notice-templates/{id}/copy
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-notice-templates.copy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-notice-templates.copy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductNoticeTemplateController@copy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-notice-templates.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-notice-templates.create`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 기존 상품정보제공고시 템플릿을 원본 삼아 복제본을 생성합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-notice-templates.create` 권한이 필요하며(생성 계열이므로 create 권한 사용), `ProductNoticeTemplateController@copy`가 `ProductNoticeTemplateService::copyTemplate()`를 호출해 path의 `id` 템플릿을 복사합니다. 별도 본문 없이 원본 `id`만으로 동작하며, 복제된 새 템플릿을 HTTP 201로 반환합니다. 유사한 고시 항목 세트를 반복 작성하지 않고 빠르게 파생 템플릿을 만들 때 사용하며, 원본이 없거나 처리 실패 시 각각 404/400 에러 응답을 반환합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/product-notice-templates/{id}/toggle-active
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.product-notice-templates.toggle-active -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.product-notice-templates.toggle-active`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductNoticeTemplateController@toggleActive`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.product-notice-templates.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.product-notice-templates.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 상품정보제공고시 템플릿의 활성/비활성 상태를 한 번의 요청으로 토글합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.product-notice-templates.update` 권한이 필요하며, `ProductNoticeTemplateController@toggleActive`가 `ProductNoticeTemplateService::toggleActive()`를 호출해 현재 `is_active` 값을 반전시킵니다. 반전 결과에 따라 활성화/비활성화 메시지를 구분해 응답하므로 목록 화면의 스위치 조작에 적합합니다. 대상이 없거나 처리 실패 시 각각 404/400 에러 응답을 반환합니다.
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,411 @@
|
||||
# Promotion Coupons API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Promotion Coupons 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/promotion-coupons
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.promotion-coupons.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.promotion-coupons.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CouponController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.promotion-coupon.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
| sort_by | query | string | 아니오 | `created_at`, `name`, `discount_value`, `issued_count` | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| search_field | query | string | 아니오 | `all`, `name`, `description`, `created_by` | 검색 대상 필드명 (검색어를 적용할 컬럼) |
|
||||
| search_keyword | query | string | 아니오 | max 255 | 검색 키워드 (부분 일치) |
|
||||
| target_type | query | string | 아니오 | `all`, `product_amount`, `order_amount`, `shipping_fee` | 적용대상(할인 기준) 필터: 상품금액/주문금액/배송비 (`all`=전체) |
|
||||
| discount_type | query | string | 아니오 | `all`, `fixed`, `rate` | 혜택유형 필터: fixed(정액), rate(정률%) (`all`=전체) |
|
||||
| issue_status | query | string | 아니오 | `all`, `issuing`, `stopped` | 발급상태 필터: issuing(발급중), stopped(발급중단) (`all`=전체) |
|
||||
| issue_method | query | string | 아니오 | `all`, `direct`, `download`, `auto` | 발급방법 필터: direct(직접발급), download(다운로드), auto(자동발급) (`all`=전체) |
|
||||
| issue_condition | query | string | 아니오 | `all`, `manual`, `signup`, `first_purchase`, `birthday` | 발급조건 필터: manual(수동), signup(회원가입), first_purchase(첫구매), birthday(생일) (`all`=전체) |
|
||||
| min_benefit_amount | query | number | 아니오 | min 0 | 혜택값(할인 금액/율) 하한 필터 |
|
||||
| max_benefit_amount | query | number | 아니오 | min 0 | 혜택값(할인 금액/율) 상한 필터 |
|
||||
| min_order_amount | query | number | 아니오 | min 0 | 최소 주문금액 하한 필터 |
|
||||
| created_start_date | query | date | 아니오 | — | 생성일시 범위 시작 |
|
||||
| created_end_date | query | date | 아니오 | — | 생성일시 범위 종료 (시작일 이후) |
|
||||
| valid_start_date | query | date | 아니오 | — | 유효기간 범위 시작 |
|
||||
| valid_end_date | query | date | 아니오 | — | 유효기간 범위 종료 (시작일 이후) |
|
||||
| issue_start_date | query | date | 아니오 | — | 발급기간 범위 시작 |
|
||||
| issue_end_date | query | date | 아니오 | — | 발급기간 범위 종료 (시작일 이후) |
|
||||
| created_by | query | uuid | 아니오 | — | 등록자(생성한 관리자) UUID 필터 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `157` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"API 문서 샘플 쿠폰","en":"API Doc Sample Coupon"}` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| localized_name | string | `API 문서 샘플 쿠폰` | `name` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| description | object | `{"ko":null,"en":null}` | 설명 (다국어 필드는 로케일별 값 객체) |
|
||||
| localized_description | string | `설날 특별 무료배송 예정` | `description` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| target_type | string | `order_amount` | 적용대상(할인 기준): product_amount(상품금액), order_amount(주문금액), shipping_fee(배송비) |
|
||||
| target_type_label | string | `주문금액` | `target_type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| target_type_badge_color | string | `blue` | `target_type` 배지 색상 (상품금액=teal, 주문금액=blue, 배송비=orange) |
|
||||
| discount_type | string | `fixed` | 혜택유형: fixed(정액 금액 할인), rate(정률 % 할인) |
|
||||
| discount_type_label | string | `정액할인` | `discount_type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| discount_value | integer | `1000` | 혜택값 (정액이면 할인 금액, 정률이면 할인율 %). 정액은 기본 통화 자릿수로 정규화 |
|
||||
| discount_max_amount | integer | `2000` | 최대 할인액 (정률 할인 시 상한 금액, 미설정 시 null) |
|
||||
| min_order_amount | integer | `0` | 쿠폰 적용 최소 주문금액 (0=제한 없음) |
|
||||
| benefit_formatted | string | `1,000원 할인` | `benefit` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| multi_currency_discount_value | object | `{"KRW":{"price":1000,"formatted":"1,000원","is_default":tr…` | 정액 할인 금액의 통화별 환산 맵 (정률은 통화 무관이라 null) |
|
||||
| multi_currency_min_order_amount | object | `{"KRW":{"price":10000,"formatted":"10,000원","is_default":…` | 최소 주문금액의 통화별 환산 맵 (0이면 null) |
|
||||
| multi_currency_discount_max_amount | object | `{"KRW":{"price":2000,"formatted":"2,000원","is_default":tr…` | 최대 할인액의 통화별 환산 맵 (미설정 시 null) |
|
||||
| issue_method | string | `download` | 발급방법: direct(직접발급), download(다운로드), auto(자동발급) |
|
||||
| issue_method_label | string | `다운로드` | `issue_method` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| issue_method_badge_color | string | `teal` | `issue_method` 배지 색상 (직접발급=gray, 다운로드=teal, 자동발급=blue) |
|
||||
| issue_condition | string | `manual` | 발급조건: manual(수동), signup(회원가입), first_purchase(첫구매), birthday(생일) |
|
||||
| issue_condition_label | string | `수동발급` | `issue_condition` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| issue_condition_badge_color | string | `orange` | `issue_condition` 배지 색상 (수동=orange, 회원가입=blue, 첫구매=teal, 생일=pink) |
|
||||
| issue_status | string | `issuing` | 발급상태: issuing(발급중), stopped(발급중단) |
|
||||
| issue_status_label | string | `발급중` | `issue_status` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| issue_status_badge_color | string | `blue` | `issue_status` 배지 색상 (발급중=blue, 발급중단=orange) |
|
||||
| total_quantity | integer | `1` | 총 발급 수량 (null=무제한) |
|
||||
| issued_count | integer | `0` | issued 개수 (집계) |
|
||||
| per_user_limit | integer | `1` | 회원 1인당 발급 제한 수량 (0=무제한) |
|
||||
| issue_count_formatted | string | `0/무제한` | `issue_count` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| valid_type | string | `period` | 유효기간 유형: period(기간 지정), days_from_issue(발급일로부터 N일) |
|
||||
| valid_days | integer | `1` | 발급일로부터 유효 일수 (valid_type=days_from_issue 일 때) |
|
||||
| valid_from | string | `2026-06-30` | 유효기간 시작일 (사이트 타임존 기준 날짜 문자열) |
|
||||
| valid_to | string | `2026-07-30` | 유효기간 종료일 (사이트 타임존 기준 날짜 문자열) |
|
||||
| valid_period_formatted | string | `-` | `valid_period` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| issue_from | string | `2026-06-30T11:24` | 발급기간 시작 일시 (datetime-local 입력 호환 문자열) |
|
||||
| issue_to | string | `2026-07-15T11:24` | 발급기간 종료 일시 (datetime-local 입력 호환 문자열) |
|
||||
| issue_period_formatted | string | `상시발급` | `issue_period` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
| is_combinable | boolean | `false` | combinable 여부 |
|
||||
| target_scope | string | `all` | 적용 범위: all(전체 상품), products(특정 상품), categories(특정 카테고리) |
|
||||
| target_scope_label | string | `전체상품` | `target_scope` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| is_issuable | boolean | `true` | issuable 여부 |
|
||||
| created_at | string | `2026-07-07 14:47:31` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-07 14:47:31` | 최종 수정 일시 |
|
||||
| created_by | string | `a1e0a91a-fba6-491c-a53e-7285a5686857` | 등록자(생성한 관리자) UUID (creator 관계 로드 시) |
|
||||
| created_by_name | string | `-` | 등록자 이름 (creator 미로드/미설정 시 `-`) |
|
||||
| created_by_email | string | `heuristing@gmail.com` | 등록자 이메일 (creator 관계 파생) |
|
||||
| creator | object | `{"uuid":"a1e0a91a-fba6-491c-a53e-7285a5686857","name":"관리자"}` | 생성자 정보 객체 (uuid/name/email — creator 관계 파생) |
|
||||
| issues_count | integer | `0` | issues 개수 (집계) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.promotion-coupon.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 프로모션 쿠폰(쿠폰 정의/마스터) 목록을 검색·필터·정렬·페이지네이션으로 조회합니다. `permission:sirsoft-ecommerce.promotion-coupon.read` 권한이 필요하며, 이름/설명/생성자 검색, 적용대상·혜택유형·발급상태·발급방법·발급조건 필터, 혜택금액·주문금액·생성/유효/발급 기간 범위 필터를 지원합니다. `CouponService::getCoupons()`가 조회하고 `CouponCollection`으로 직렬화하며, 각 항목은 다국어 라벨·배지 색상·다중통화 혜택값 등 관리자 UI 표시용 파생 필드를 포함합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/promotion-coupons
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.promotion-coupons.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.promotion-coupons.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CouponController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.promotion-coupon.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| description | body | array | 아니오 | — | 설명 |
|
||||
| target_type | body | string | 예 | `product_amount`, `order_amount`, `shipping_fee` | 적용대상(할인 기준): 상품금액/주문금액/배송비 |
|
||||
| discount_type | body | string | 예 | `fixed`, `rate` | 혜택유형: fixed(정액 금액), rate(정률 %) |
|
||||
| discount_value | body | number | 예 | min 1 | 혜택값 (정액이면 할인 금액, 정률이면 1~100 할인율 %) |
|
||||
| discount_max_amount | body | number | 아니오 | min 0 | 최대 할인액 (정률 할인 시 상한 금액) |
|
||||
| min_order_amount | body | number | 아니오 | min 0 | 쿠폰 적용 최소 주문금액 (미입력 시 0=제한 없음) |
|
||||
| issue_method | body | string | 예 | `direct`, `download`, `auto` | 발급방법: direct(직접발급), download(다운로드), auto(자동발급) |
|
||||
| issue_condition | body | string | 예 | `manual`, `signup`, `first_purchase`, `birthday` | 발급조건: manual(수동), signup(회원가입), first_purchase(첫구매), birthday(생일) |
|
||||
| issue_status | body | string | 예 | `issuing`, `stopped` | 발급상태: issuing(발급중), stopped(발급중단) |
|
||||
| total_quantity | body | integer | 아니오 | min 1 | 총 발급 수량 (미입력 시 무제한) |
|
||||
| per_user_limit | body | integer | 예 | min 0 | 회원 1인당 발급 제한 수량 (0=무제한) |
|
||||
| valid_type | body | string | 예 | `period`, `days_from_issue` | 유효기간 유형: period(기간 지정, valid_from/valid_to 필수), days_from_issue(발급일로부터 N일, valid_days 필수) |
|
||||
| valid_days | body | integer | 아니오 | min 1 | 발급일로부터 유효 일수 (valid_type=days_from_issue 시 필수) |
|
||||
| valid_from | body | date | 아니오 | — | 유효기간 시작일 (valid_type=period 시 필수) |
|
||||
| valid_to | body | date | 아니오 | — | 유효기간 종료일 (valid_type=period 시 필수, valid_from 이후) |
|
||||
| issue_from | body | date | 아니오 | — | 발급기간 시작 일시 (미입력 시 상시발급) |
|
||||
| issue_to | body | date | 아니오 | — | 발급기간 종료 일시 (issue_from 이후) |
|
||||
| is_combinable | body | boolean | 아니오 | — | combinable 여부 |
|
||||
| target_scope | body | string | 아니오 | `all`, `products`, `categories` | 적용 범위: all(전체 상품), products(특정 상품), categories(특정 카테고리) |
|
||||
| products | body | array | 아니오 | — | 적용 상품 목록 (`target_scope=products`), 항목별 `{id, type: include\|exclude}` |
|
||||
| categories | body | array | 아니오 | — | 적용 카테고리 목록 (`target_scope=categories`), 항목별 `{id, type: include\|exclude}` |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.coupon.create_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.promotion-coupon.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 새 프로모션 쿠폰(정의)을 생성합니다. `permission:sirsoft-ecommerce.promotion-coupon.create` 권한이 필요하며, 다국어 쿠폰명(`name`), 적용대상·혜택유형·혜택값, 발급방법/조건/상태, 유효기간·발급기간, 회원당 한도, 적용 범위(`target_scope`: all·products·categories)와 그에 따른 상품/카테고리 배열을 받아 `CouponService::createCoupon()`이 저장하고 생성된 쿠폰을 201로 반환합니다. `target_scope` 가 products/categories 일 때만 각 배열이 의미를 가지며, 확장은 `sirsoft-ecommerce.coupon.create_validation_rules` 필터로 검증 규칙을 추가할 수 있습니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/promotion-coupons/bulk-status
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.promotion-coupons.bulk-status -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.promotion-coupons.bulk-status`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CouponController@bulkUpdateStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.promotion-coupon.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
| issue_status | body | string | 예 | `issuing`, `stopped` | 일괄 적용할 발급상태: issuing(발급중), stopped(발급중단) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.promotion-coupon.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 여러 쿠폰의 발급상태(`issue_status`: issuing·stopped)를 한 번에 변경합니다. `permission:sirsoft-ecommerce.promotion-coupon.update` 권한이 필요하고 `ids` 로 대상 쿠폰들을 지정하며, `CouponService::bulkUpdateIssueStatus()`가 일괄 갱신 후 변경된 건수(`updated_count`)를 반환합니다. 쿠폰 목록에서 여러 항목을 선택해 발급을 일괄 중단/재개할 때 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/promotion-coupons/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.promotion-coupons.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.promotion-coupons.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CouponController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.promotion-coupon.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.promotion-coupon.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 프로모션 쿠폰(정의) 1건을 삭제합니다. `permission:sirsoft-ecommerce.promotion-coupon.delete` 권한이 필요하며, `CouponService::deleteCoupon()`이 삭제를 수행합니다(쿠폰 모델은 소프트 삭제 대상). 이미 발급된 내역이 있는 등 도메인 제약으로 삭제가 실패하면 400 오류로 응답합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/promotion-coupons/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.promotion-coupons.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.promotion-coupons.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CouponController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.promotion-coupon.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.promotion-coupon.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 프로모션 쿠폰 1건의 상세 정보를 조회합니다. `permission:sirsoft-ecommerce.promotion-coupon.read` 권한이 필요하며, `CouponService::getCoupon()`이 쿠폰 정의와 함께 적용 범위(included/excluded products·categories)까지 로드해 `CouponResource`로 반환합니다. 목록(index)보다 상세한 필드(적용 대상 상품/카테고리 목록 등)를 포함하며, 해당 쿠폰이 없으면 404 를 반환합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/promotion-coupons/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.promotion-coupons.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.promotion-coupons.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CouponController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.promotion-coupon.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| description | body | array | 아니오 | — | 설명 |
|
||||
| target_type | body | string | 예 | `product_amount`, `order_amount`, `shipping_fee` | 적용대상(할인 기준): 상품금액/주문금액/배송비 |
|
||||
| discount_type | body | string | 예 | `fixed`, `rate` | 혜택유형: fixed(정액 금액), rate(정률 %) |
|
||||
| discount_value | body | number | 예 | min 1 | 혜택값 (정액이면 할인 금액, 정률이면 1~100 할인율 %) |
|
||||
| discount_max_amount | body | number | 아니오 | min 0 | 최대 할인액 (정률 할인 시 상한 금액) |
|
||||
| min_order_amount | body | number | 아니오 | min 0 | 쿠폰 적용 최소 주문금액 (미입력 시 0=제한 없음) |
|
||||
| issue_method | body | string | 예 | `direct`, `download`, `auto` | 발급방법: direct(직접발급), download(다운로드), auto(자동발급) |
|
||||
| issue_condition | body | string | 예 | `manual`, `signup`, `first_purchase`, `birthday` | 발급조건: manual(수동), signup(회원가입), first_purchase(첫구매), birthday(생일) |
|
||||
| issue_status | body | string | 예 | `issuing`, `stopped` | 발급상태: issuing(발급중), stopped(발급중단) |
|
||||
| total_quantity | body | integer | 아니오 | min 1 | 총 발급 수량 (미입력 시 무제한) |
|
||||
| per_user_limit | body | integer | 예 | min 0 | 회원 1인당 발급 제한 수량 (0=무제한) |
|
||||
| valid_type | body | string | 예 | `period`, `days_from_issue` | 유효기간 유형: period(기간 지정, valid_from/valid_to 필수), days_from_issue(발급일로부터 N일, valid_days 필수) |
|
||||
| valid_days | body | integer | 아니오 | min 1 | 발급일로부터 유효 일수 (valid_type=days_from_issue 시 필수) |
|
||||
| valid_from | body | date | 아니오 | — | 유효기간 시작일 (valid_type=period 시 필수) |
|
||||
| valid_to | body | date | 아니오 | — | 유효기간 종료일 (valid_type=period 시 필수, valid_from 이후) |
|
||||
| issue_from | body | date | 아니오 | — | 발급기간 시작 일시 (미입력 시 상시발급) |
|
||||
| issue_to | body | date | 아니오 | — | 발급기간 종료 일시 (issue_from 이후) |
|
||||
| is_combinable | body | boolean | 아니오 | — | combinable 여부 |
|
||||
| target_scope | body | string | 아니오 | `all`, `products`, `categories` | 적용 범위: all(전체 상품), products(특정 상품), categories(특정 카테고리) |
|
||||
| products | body | array | 아니오 | — | 적용 상품 목록 (`target_scope=products`), 항목별 `{id, type: include\|exclude}` |
|
||||
| categories | body | array | 아니오 | — | 적용 카테고리 목록 (`target_scope=categories`), 항목별 `{id, type: include\|exclude}` |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.coupon.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.promotion-coupon.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 기존 프로모션 쿠폰(정의)의 내용을 수정합니다. `permission:sirsoft-ecommerce.promotion-coupon.update` 권한이 필요하며, 생성과 동일한 필드 집합(쿠폰명·혜택·발급 조건·유효/발급 기간·적용 범위 등)을 받아 `CouponService::updateCoupon()`이 전체 갱신합니다. `target_scope` 변경 시 그에 맞는 상품/카테고리 배열을 함께 보내야 하며, 대상 쿠폰이 없으면 404, 갱신 실패 시 400 을 반환합니다. 확장은 `sirsoft-ecommerce.coupon.update_validation_rules` 필터로 검증 규칙을 추가할 수 있습니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/promotion-coupons/{id}/issue-direct
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.promotion-coupons.issue-direct -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.promotion-coupons.issue-direct`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CouponController@issueDirect`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.promotion-coupon.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| user_uuids | body | array | 예 | min 1 | 쿠폰을 직접 발급할 대상 회원 UUID 배열 (내부 회원 ID 로 해석 후 발급) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.promotion-coupon.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 지정한 회원들에게 특정 쿠폰을 즉시 직접 발급합니다. `permission:sirsoft-ecommerce.promotion-coupon.update` 권한이 필요하고 대상 회원은 `user_uuids`(uuid 배열)로 지정하며, FormRequest 가 uuid 를 내부 회원 ID 로 해석한 뒤 `CouponService::issueDirectly()`가 발급합니다. 응답에는 실제 발급 건수(`issued`)와 이미 보유/한도 초과 등으로 건너뛴 목록(`skipped`)이 포함되고, 건너뛴 건이 있으면 별도 안내 메시지 키가 사용됩니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/promotion-coupons/{id}/issues
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.promotion-coupons.issues -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.promotion-coupons.issues`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CouponController@issues`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.promotion-coupon.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| user_id | query | uuid | 아니오 | — | user 식별자 |
|
||||
| status | query | string | 아니오 | `available`, `used`, `expired`, `cancelled` | 상태 필터 (해당 상태의 항목만 조회) |
|
||||
| per_page | query | integer | 아니오 | min 1, max 100 | 페이지당 항목 수 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.coupon.issues_list_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.promotion-coupon.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 쿠폰의 회원별 발급 내역을 회원(`user_id`)·상태(available·used·expired·cancelled)로 필터링해 페이지네이션으로 조회합니다. `permission:sirsoft-ecommerce.promotion-coupon.read` 권한이 필요하며, `CouponService::getCouponIssues()`가 조회하고 `CouponIssueCollection`으로 직렬화합니다. 어떤 회원이 이 쿠폰을 받아 언제 사용/만료/취소했는지 추적하는 발급 원장 화면에 사용됩니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/promotion-coupons/{id}/issues/{issueId}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.promotion-coupons.issues.cancel -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.promotion-coupons.issues.cancel`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\CouponController@cancelIssue`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.promotion-coupon.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| issueId | path | string | 예 | — | 대상 issue의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.promotion-coupon.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 쿠폰의 발급 내역 1건을 취소 처리합니다. 대상은 쿠폰 ID(`id`)와 발급 내역 ID(`issueId`) 조합으로 지정하고 `permission:sirsoft-ecommerce.promotion-coupon.update` 권한이 필요하며, `CouponService::cancelIssue()`가 미사용 발급 건만 취소합니다. 이미 사용된 발급 건 등 취소 불가 사유는 예외 메시지(`detail`)로 관리자에게 그대로 노출되어 400 으로 응답합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Review Image API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Review Image 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/review-image/{hash}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.review-image.download -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.review-image.download`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\ReviewImageController@download`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| hash | path | string | 예 | — | 대상 리소스의 해시 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 리뷰에 첨부된 이미지를 해시(12자) 기반으로 공개 서빙합니다. 인증이 필요 없으며, `ReviewImageController@download` 가 `ProductReviewImageService::download()` 로 해시에 해당하는 이미지를 찾아 스트림(`StreamedResponse`)으로 반환합니다. 해시에 해당하는 이미지가 없으면 404 를 반환합니다. `<img src>` 등에서 리뷰 이미지 원본을 표시할 때 사용하며, 실제 파일 경로를 노출하지 않고 해시로만 접근하게 합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,467 @@
|
||||
# Reviews API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Reviews 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/reviews
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.reviews.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.reviews.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductReviewController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.reviews.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| search_field | query | string | 아니오 | `all`, `product_name`, `reviewer`, `content`, `order_number`, `option_name` | 검색 대상 필드명 (검색어를 적용할 컬럼) |
|
||||
| search_keyword | query | string | 아니오 | max 200 | 검색 키워드 (부분 일치) |
|
||||
| rating | query | string | 아니오 | `1`, `2`, `3`, `4`, `5`, `` | 별점 필터 (해당 별점의 리뷰만 조회, 빈 값은 전체) |
|
||||
| reply_status | query | string | 아니오 | `all`, `replied`, `unreplied` | 답변 상태 필터 (답변완료/미답변) |
|
||||
| photo | query | string | 아니오 | `photo`, `normal`, `` | 포토 리뷰 필터 (이미지 첨부 여부, 빈 값은 전체) |
|
||||
| has_photo | query | boolean | 아니오 | — | photo 여부 |
|
||||
| status | query | string | 아니오 | — | 상태 필터 (해당 상태의 항목만 조회) |
|
||||
| start_date | query | date | 아니오 | — | 조회 기간 시작일 (이 날짜 이후 데이터) |
|
||||
| end_date | query | date | 아니오 | — | 조회 기간 종료일 (이 날짜 이전 데이터) |
|
||||
| sort | query | string | 아니오 | `created_at_desc`, `created_at_asc`, `rating_desc`, `rating_asc` | 정렬 기준 (필드명, `-` 접두 시 내림차순) |
|
||||
| sort_by | query | string | 아니오 | `created_at`, `rating`, `reply_status` | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| per_page | query | integer | 아니오 | min 10, max 100 | 페이지당 항목 수 |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.review.list_validation_rules`, `sirsoft-ecommerce.review.list_validation_messages`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `99` | 기본 키 (내부 식별자) |
|
||||
| product_id | integer | `320` | product 식별자 (연관 리소스 참조) |
|
||||
| order_option_id | integer | `859` | order option 식별자 (연관 리소스 참조) |
|
||||
| user_id | string | `a231747f-e82e-4cf2-9ae1-a261849dce40` | user 식별자 (연관 리소스 참조) |
|
||||
| user | object | `{"uuid":"a231747f-e82e-4cf2-9ae1-a261849dce40","name":"AP…` | 작성자 정보 (uuid·name·email, `user` 관계 로드 시) |
|
||||
| product | object | `{"id":320,"name":"API 문서 샘플 상품","thumbnail_url":null}` | 리뷰 대상 상품 정보 (id·현지화 상품명·썸네일 URL) |
|
||||
| option_snapshot | null | `null` | 주문 시점 옵션 스냅샷 (옵션명 보존용) |
|
||||
| option_snapshot_label | string | `` | `option_snapshot` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| rating | integer | `5` | 별점 (1~5) |
|
||||
| content | string | `Molestiae repellendus accusantium omn…` | 리뷰 내용 |
|
||||
| content_mode | string | `text` | 콘텐츠 모드: text / html |
|
||||
| status | string | `visible` | 리뷰 상태: visible(전시중) / hidden(숨김) |
|
||||
| status_label | string | `전시중` | 상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
|
||||
| status_badge_color | string | `blue` | 상태 뱃지 색상 (visible=blue / hidden=gray) |
|
||||
| images | array | `[]` | 첨부 이미지 목록 (이미지 리소스 배열, `images` 관계 로드 시) |
|
||||
| image_count | integer | `0` | image 개수 (집계) |
|
||||
| orderOption | object | `{"id":859,"order_id":455,"order_number":"ORD-20260707-000…` | 리뷰가 연결된 주문 옵션 정보 (주문 ID·주문번호·수량·주문일) |
|
||||
| has_reply | boolean | `false` | reply 여부 |
|
||||
| has_reply_label | string | `미답변` | `has_reply` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| has_reply_badge_color | string | `gray` | 답변 여부 뱃지 색상 (답변완료=green / 미답변=gray) |
|
||||
| reply_content | null | `null` | 판매자 답변 내용 (없으면 null) |
|
||||
| reply_content_mode | string | `text` | 답변 콘텐츠 모드: text / html |
|
||||
| reply_admin_uuid | null | `null` | 답변 작성 관리자 UUID (`replyAdmin` 관계 로드 시) |
|
||||
| reply_admin | null | `null` | 답변 작성 관리자 정보 (uuid·name·email, `replyAdmin` 관계 로드 시) |
|
||||
| replied_at | null | `null` | replied 일시 |
|
||||
| reply_updated_at | null | `null` | reply updated 일시 |
|
||||
| created_at | string | `2026-07-07 14:47:31` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-07 14:47:31` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.reviews.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 전체 상품 리뷰를 페이지네이션으로 조회합니다. `sirsoft-ecommerce.reviews.read` 권한이 필요하며, `ProductReviewService::getAdminList()`가 검색어·별점·답변 여부·포토 여부·상태·기간 등 필터와 정렬을 적용해 목록을 반환합니다. 각 항목에는 작성자·상품·주문옵션·이미지·답변 정보가 함께 로드되고, `abilities` 로 현재 관리자의 수정/삭제 가능 여부가 내려옵니다. 리뷰 관리 화면의 목록 표를 채우는 데 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/reviews/bulk
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.reviews.bulk -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.reviews.bulk`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductReviewController@bulk`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.reviews.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
| action | body | string | 예 | `delete`, `change_status` | 일괄 작업 종류 (delete=삭제, change_status=상태 변경) |
|
||||
| status | body | string | 아니오 | — | 변경할 리뷰 상태 (visible/hidden, `action=change_status` 시 필수) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.review.bulk_validation_rules`, `sirsoft-ecommerce.review.bulk_validation_messages`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.reviews.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 선택한 여러 리뷰를 한 번에 일괄 처리합니다. `sirsoft-ecommerce.reviews.update` 권한이 필요하며, `action` 이 `delete` 이면 `ProductReviewService::bulkDelete()` 로 삭제하고 `deleted_count` 를, `change_status` 이면 `bulkUpdateStatus()` 로 `status` 값으로 상태를 변경하고 `updated_count` 를 반환합니다. `change_status` 를 선택했다면 `status` 값이 반드시 필요합니다. 목록 화면에서 체크박스로 다건 선택 후 삭제/전시상태 변경 시 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/reviews/{review}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.reviews.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.reviews.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductReviewController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.reviews.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| review | path | string | 예 | — | 대상 review의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.reviews.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 리뷰 1건을 삭제합니다. `sirsoft-ecommerce.reviews.delete` 권한이 필요하며, 삭제 전 `images` 관계를 로드한 뒤 `ProductReviewService::deleteReview()` 가 첨부 이미지 파일까지 함께 정리하며 리뷰를 제거합니다. 라우트 모델 바인딩으로 존재하지 않는 리뷰는 404 를 반환합니다. 부적절한 리뷰를 관리자 화면에서 개별 삭제할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/reviews/{review}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.reviews.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.reviews.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductReviewController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.reviews.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| review | path | string | 예 | — | 대상 review의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | integer | `99` | 기본 키 (내부 식별자) |
|
||||
| product_id | integer | `320` | 상품 ID |
|
||||
| order_option_id | integer | `859` | 주문 옵션 ID |
|
||||
| user_id | string | `a231747f-e82e-4cf2-9ae1-a261849dce40` | 작성자 ID |
|
||||
| user | object | `{"uuid":"a231747f-e82e-4cf2-9ae1-a261849dce40","name":"AP…` | 작성자 정보 (uuid·name·email, `user` 관계 로드 시) |
|
||||
| product | object | `{"id":320,"name":"API 문서 샘플 상품","thumbnail_url":null}` | 리뷰 대상 상품 정보 (id·현지화 상품명·썸네일 URL) |
|
||||
| option_snapshot | null | `null` | 주문 시점 옵션 스냅샷 (옵션명 보존용) |
|
||||
| option_snapshot_label | string | `` | `option_snapshot` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| rating | integer | `5` | 별점 (1~5) |
|
||||
| content | string | `Molestiae repellendus accusantium omn…` | 리뷰 내용 |
|
||||
| content_mode | string | `text` | 콘텐츠 모드: text / html |
|
||||
| status | string | `visible` | 리뷰 상태: visible / hidden |
|
||||
| status_label | string | `전시중` | 상태의 사람이 읽는 라벨 (상태 Enum label() 산물) |
|
||||
| status_badge_color | string | `blue` | 상태 뱃지 색상 (visible=blue / hidden=gray) |
|
||||
| images | array | `[]` | 첨부 이미지 목록 (이미지 리소스 배열, `images` 관계 로드 시) |
|
||||
| image_count | integer | `0` | image 개수 (집계) |
|
||||
| orderOption | object | `{"id":859,"order_id":455,"order_number":"ORD-20260707-000…` | 리뷰가 연결된 주문 옵션 정보 (주문 ID·주문번호·수량·주문일) |
|
||||
| has_reply | boolean | `false` | reply 여부 |
|
||||
| has_reply_label | string | `미답변` | `has_reply` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| has_reply_badge_color | string | `gray` | 답변 여부 뱃지 색상 (답변완료=green / 미답변=gray) |
|
||||
| reply_content | null | `null` | 판매자 답변 내용 |
|
||||
| reply_content_mode | string | `text` | 답변 콘텐츠 모드: text / html |
|
||||
| reply_admin_uuid | null | `null` | 답변 작성 관리자 UUID (`replyAdmin` 관계 로드 시) |
|
||||
| reply_admin | null | `null` | 답변 작성 관리자 정보 (uuid·name·email, `replyAdmin` 관계 로드 시) |
|
||||
| replied_at | null | `null` | replied 일시 |
|
||||
| reply_updated_at | null | `null` | reply updated 일시 |
|
||||
| created_at | string | `2026-07-07 14:47:31` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-07 14:47:31` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.reviews.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 리뷰 1건의 상세 정보를 조회합니다. `sirsoft-ecommerce.reviews.read` 권한이 필요하며, 컨트롤러가 `user`·`product`·`images`·`replyAdmin`·`orderOption.order` 관계를 함께 로드해 작성자·상품·이미지·판매자 답변·주문 정보까지 포함한 단건 리소스를 반환합니다. 관리자 리뷰 상세/답변 작성 화면 진입 시 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/reviews/{review}/reply
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.reviews.reply.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.reviews.reply.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductReviewController@destroyReply`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.reviews.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| review | path | string | 예 | — | 대상 review의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.reviews.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 리뷰에 등록한 판매자 답변을 삭제합니다. `sirsoft-ecommerce.reviews.update` 권한이 필요하며, `ProductReviewService::deleteReply()` 가 답변 내용·작성자·작성 일시를 비우고 답변이 제거된 리뷰 리소스를 반환합니다. 잘못 작성한 답변을 회수할 때 사용하며, 리뷰 자체는 유지됩니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/reviews/{review}/reply
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.reviews.reply.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.reviews.reply.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductReviewController@storeReply`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.reviews.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| review | path | string | 예 | — | 대상 review의 식별자 |
|
||||
| reply_content | body | string | 예 | min 1, max 2000 | 판매자 답변 내용 (1~2000자) |
|
||||
| reply_content_mode | body | string | 아니오 | `text`, `html` | 답변 콘텐츠 모드 (평문/HTML, 미지정 시 text) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.review.store_reply_validation_rules`, `sirsoft-ecommerce.review.store_reply_validation_messages`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.reviews.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 리뷰에 판매자 답변을 등록하거나 기존 답변을 수정합니다. `sirsoft-ecommerce.reviews.update` 권한이 필요하며, `ProductReviewService::saveReply()` 가 로그인 관리자 UUID(`Auth::id()`)를 답변 작성자로 기록하고 `reply_content`(1~2000자)와 `reply_content_mode`(text/html)를 저장합니다. 답변이 이미 있으면 갱신되고 작성 일시가 채워집니다. 고객 리뷰에 판매자가 응대할 때 사용합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/reviews/{review}/status
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.reviews.update-status -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.reviews.update-status`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ProductReviewController@updateStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.reviews.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| review | path | string | 예 | — | 대상 review의 식별자 |
|
||||
| status | body | string | 예 | — | 변경할 리뷰 전시 상태 (visible=전시중 / hidden=숨김) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.review.update_status_validation_rules`, `sirsoft-ecommerce.review.update_status_validation_messages`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.reviews.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 리뷰의 전시 상태를 변경합니다. `sirsoft-ecommerce.reviews.update` 권한이 필요하며, `ProductReviewService::updateStatus()` 가 `status` 값(예: visible/hidden)으로 리뷰를 전시하거나 숨기고 갱신된 리뷰 리소스를 반환합니다. 신고되었거나 부적절한 리뷰를 노출에서 제외하거나 다시 노출할 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/user/reviews
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.reviews.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.reviews.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\ProductReviewController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.user-reviews.write`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| product_id | body | integer | 예 | — | product 식별자 |
|
||||
| order_option_id | body | integer | 예 | — | order option 식별자 |
|
||||
| rating | body | integer | 예 | min 1, max 5 | 별점 (1~5) |
|
||||
| content | body | string | 예 | min 10, max 2000 | 리뷰 내용 (10~2000자) |
|
||||
| content_mode | body | string | 아니오 | `text`, `html` | 콘텐츠 모드 (평문/HTML, 미지정 시 text) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.review.store_validation_rules`, `sirsoft-ecommerce.review.store_validation_messages`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.user-reviews.write`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인 회원이 구매한 상품에 리뷰를 작성합니다. `sirsoft-ecommerce.user-reviews.write` 권한이 필요하며, `ProductReviewService::createReview()` 가 로그인 사용자(`Auth::id()`)를 작성자로 하여 `product_id`·`order_option_id`·별점(1~5)·내용(10~2000자)으로 리뷰를 생성하고 201 로 반환합니다. 본인 주문이 아니거나 이미 작성했거나 작성 조건을 만족하지 못하면 서비스가 `RuntimeException` 을 던져 422 로 응답합니다. 마이페이지 리뷰 작성 폼에서 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/reviews/can-write/{orderOptionId}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.reviews.can-write -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.reviews.can-write`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\ProductReviewController@canWrite`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| orderOptionId | path | string | 예 | — | 대상 order option의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인 회원이 특정 주문 옵션에 대해 리뷰를 쓸 수 있는지 확인합니다. `auth:sanctum` 인증만 요구하며, `ProductReviewService::canWrite()` 가 본인 주문 여부·구매 완료·중복 작성 여부 등을 판정해 `can_write` 불리언과 불가 시 `reason`(예: `not_own_order`)을 반환합니다. 리뷰 작성 버튼 노출 여부를 결정하기 위해 상품/주문 화면에서 사전 호출합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/user/reviews/{review}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.reviews.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.reviews.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\ProductReviewController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.user-reviews.write`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| review | path | string | 예 | — | 대상 review의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.user-reviews.write`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인 회원이 본인이 작성한 리뷰를 삭제합니다. `sirsoft-ecommerce.user-reviews.write` 권한이 필요하며, 컨트롤러가 `review->user_id` 와 로그인 사용자를 대조해 본인 소유가 아니면 403 을 반환합니다. 본인 리뷰이면 `images` 관계를 로드한 뒤 `ProductReviewService::deleteReview()` 가 첨부 이미지까지 함께 삭제합니다. 마이페이지에서 자신의 리뷰를 지울 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/user/reviews/{review}/images
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.reviews.images.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.reviews.images.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\ReviewImageController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.user-reviews.write`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| review | path | string | 예 | — | 대상 review의 식별자 |
|
||||
| image | body | file | 예 | max 10240 | 첨부할 이미지 파일 (최대 용량은 리뷰 설정 `review_settings.max_image_size_mb` 기반, 폴백 10MB) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.user-reviews.write`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인 회원이 자신의 리뷰에 이미지를 첨부합니다. `sirsoft-ecommerce.user-reviews.write` 권한이 필요하며, 컨트롤러가 `review->user_id` 로 본인 소유를 확인(불일치 시 403)한 뒤 `ProductReviewImageService::upload()` 가 업로드된 이미지(최대 10MB)를 저장하고 201 로 이미지 리소스를 반환합니다. 파일 형식/크기 등 제약 위반 시 서비스가 `RuntimeException` 을 던져 422 로 응답합니다. 포토 리뷰 작성 시 이미지를 추가할 때 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/user/reviews/{review}/images/{image}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.reviews.images.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.reviews.images.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\ReviewImageController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.user-reviews.write`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| review | path | string | 예 | — | 대상 review의 식별자 |
|
||||
| image | path | string | 예 | — | 대상 image의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.user-reviews.write`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인 회원이 자신의 리뷰에서 첨부 이미지 1건을 삭제합니다. `sirsoft-ecommerce.user-reviews.write` 권한이 필요하며, 컨트롤러가 `review->user_id` 로 본인 소유를 확인(불일치 시 403)하고 `image->review_id` 가 해당 리뷰에 속하는지 대조(불일치 시 404)한 뒤 `ProductReviewImageService::delete()` 로 파일과 레코드를 함께 제거합니다. 포토 리뷰에서 잘못 올린 이미지를 개별 삭제할 때 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,324 @@
|
||||
# Settings API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Settings 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/settings
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.settings.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.settings.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\EcommerceSettingsController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| basic_info | object | `{"shop_name":"","route_path":"shop","no_route":false,"com…` | 쇼핑몰 기본 정보 (쇼핑몰명·라우트 경로·상호·사업자번호·주소·연락처·이메일 등) |
|
||||
| language_currency | object | `{"default_currency":"KRW","currencies":[{"code":"KRW","na…` | 통화 설정 (기본 통화 + 등록 통화 목록: 코드·다국어명·환율·기호·국기·반올림 규칙) |
|
||||
| order_settings | object | `{"default_pg_provider":null,"payment_methods":[{"id":"car…` | 주문/결제 설정 (기본 PG·병합된 결제수단·은행/무통장 계좌·자동취소·장바구니 만료 등) |
|
||||
| shipping | object | `{"default_country":"KR","available_countries":[{"code":"K…` | 배송 설정 (기본 국가·배송 가능 국가·무료배송·DB 관리 배송사(carriers)·배송유형(types)·계산 API 후보 필드 포함) |
|
||||
| seo | object | `{"meta_category_title":"{commerce_name} - {category_name}…` | SEO 메타 설정 (카테고리·검색·상품·쇼핑몰 인덱스별 메타 타이틀/설명 및 SEO 활성 토글) |
|
||||
| review_settings | object | `{"write_deadline_days":90,"max_images":5,"max_image_size_…` | 리뷰 정책 (작성 기한일·이미지 최대 개수·이미지 최대 용량 MB) |
|
||||
| inquiry | object | `{"board_slug":null}` | 문의 연동 설정 (문의 게시판 slug) |
|
||||
| notifications | object | `{"channels":[{"id":"mail","is_active":true,"sort_order":1…` | 알림 채널 설정 (채널 ID·활성 여부·정렬 순서) |
|
||||
| mileage | object | `{"enabled":false,"default_earn_rate":1,"earn_trigger":"co…` | 마일리지 설정 (사용 여부·기본 적립률·적립 트리거·통화별 규칙·소멸/소멸 알림·실제 활성 알림 채널 포함) |
|
||||
| claim | object | `{"refund_reasons":[{"id":1,"type":"refund","code":"order_…` | 클레임 설정 (DB 관리 대상인 환불 사유 목록: 코드·다국어명·귀책 유형·노출/활성 여부) |
|
||||
| available_pg_providers | array | `[{"id":"kginicis","name_key":"sirsoft-pay_kginicis::provi…` | 설치된 PG 플러그인이 훅으로 등록한 PG 제공자 목록 (id·name_key·지원 결제수단) |
|
||||
| abilities | object | `{"can_update":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 이커머스 모듈의 전체 환경설정을 카테고리별로 묶어 한 번에 조회합니다. `permission:sirsoft-ecommerce.settings.read` 권한이 필요하며, `EcommerceSettingsService::getAllSettings()`로 JSON 설정을 읽은 뒤 DB 관리 대상(배송사·배송유형·클레임 사유·마일리지 알림 채널)과 등록된 PG 목록을 병합해 반환합니다. `basic_info`·`shipping`·`order_settings`·`claim`·`mileage` 등 관리자 설정 화면 전 탭의 초기 데이터를 이 한 응답으로 채웁니다. 응답의 `abilities.can_update` 로 수정 권한 보유 여부도 함께 내려갑니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/settings
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.settings.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.settings.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\EcommerceSettingsController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| _tab | body | string | 아니오 | `basic_info`, `language_currency`, `seo`, `order_settings`, `claim`, `shipping`, `review_settings`, `notification_definitions`, `notifications`, `inquiry`, `mileage` | 저장할 설정 탭(카테고리) 지정 (탭별 부분 저장 식별용) |
|
||||
| notifications | body | array | 아니오 | — | 알림 채널 설정 배열 (채널 ID·활성 여부·정렬 순서) |
|
||||
| basic_info | body | array | 아니오 | — | 쇼핑몰 기본 정보 섹션 (쇼핑몰명·라우트 경로·상호·사업자번호·주소·연락처 등) |
|
||||
| language_currency | body | array | 아니오 | — | 통화 설정 섹션 (기본 통화·통화 목록: 코드·다국어명·환율·반올림 규칙·통화별 로케일) |
|
||||
| seo | body | array | 아니오 | — | SEO 메타 설정 섹션 (페이지 유형별 메타 타이틀/설명·SEO 활성 토글) |
|
||||
| inquiry | body | array | 아니오 | — | 문의 연동 설정 섹션 (문의 게시판 slug) |
|
||||
| order_settings | body | array | 아니오 | — | 주문/결제 설정 섹션 (기본 PG·결제수단·은행/무통장 계좌·자동취소·장바구니 만료 등) |
|
||||
| claim | body | array | 아니오 | — | 클레임 설정 섹션 (환불 사유 목록, DB 동기화 대상으로 분리 저장) |
|
||||
| review_settings | body | array | 아니오 | — | 리뷰 정책 섹션 (작성 기한일·이미지 최대 개수·이미지 최대 용량 MB) |
|
||||
| mileage | body | array | 아니오 | — | 마일리지 설정 섹션 (사용 여부·기본 적립률·적립 트리거·통화별 규칙·소멸/소멸 알림) |
|
||||
| shipping | body | array | 아니오 | — | 배송 설정 섹션 (기본 국가·배송 가능 국가·무료배송·배송사(carriers)·배송유형(types) — carriers/types는 DB 동기화 대상으로 분리 저장) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 이커머스 환경설정을 저장합니다. `permission:sirsoft-ecommerce.settings.update` 권한이 필요하며, `_tab` 으로 저장할 카테고리를 지정하고 각 섹션(`basic_info`·`shipping`·`claim` 등)을 배열로 전달합니다. `EcommerceSettingsService::saveSettings()`가 JSON 설정을 저장하되, DB 관리 대상인 `shipping.carriers`·`shipping.types`·`claim.refund_reasons` 는 분리해 각 Service 의 sync 메서드로 동기화합니다. 저장 성공 시 `sirsoft-ecommerce.settings.after_save` 훅을 발화하고, 관리자 UI 상태 갱신을 위해 병합된 전체 설정을 다시 반환합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/settings/banks
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.settings.store-banks -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.settings.store-banks`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\EcommerceSettingsController@storeBanks`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| banks | body | array | 아니오 | — | 무통장입금용 은행 목록 (은행 코드·다국어 은행명) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 무통장입금용 은행 목록만 별도로 저장합니다. `permission:sirsoft-ecommerce.settings.update` 권한이 필요하며, `banks` 배열을 받아 `EcommerceSettingsService::saveBanks()`가 저장합니다. 전체 설정 저장(`store`)과 분리된 전용 엔드포인트로, 결제 설정 화면에서 은행 목록만 관리할 때 사용합니다. 저장 성공 시 갱신된 전체 설정을 반환합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/settings/clear-cache
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.settings.clear-cache -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.settings.clear-cache`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\EcommerceSettingsController@clearCache`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.update`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 이커머스 설정 캐시와 SEO 렌더 캐시를 초기화합니다. `permission:sirsoft-ecommerce.settings.update` 권한이 필요하며, `EcommerceSettingsService::clearCache()`로 설정 캐시를 비우고 `SeoCacheManagerInterface::clearAll()`로 SEO 페이지 캐시까지 전부 삭제합니다. 설정 변경이 화면에 즉시 반영되지 않을 때 캐시를 강제로 비우는 용도로, 성공 시 `{cleared: true}` 를 반환합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/settings/seo-cache-info
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.settings.seo-cache-info -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.settings.seo-cache-info`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\EcommerceSettingsController@seoCacheInfo`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| count | integer | `0` | 캐시된 SEO 페이지 URL 개수 |
|
||||
| size_bytes | integer | `0` | 캐시된 SEO 페이지의 지원 로케일별 HTML 총 바이트 |
|
||||
| size_formatted | string | `0 B` | `size` 값의 표시용 포맷 문자열 (통화/용량/일시 등 로케일·단위 포맷) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 현재 캐시된 SEO 페이지의 개수와 총 용량을 조회합니다. `permission:sirsoft-ecommerce.settings.read` 권한이 필요하며, `SeoCacheManagerInterface::getCachedUrls()`로 캐시된 URL 을 열거하고 지원 로케일별 HTML 바이트를 합산합니다. 응답은 캐시 페이지 수(`count`)·총 바이트(`size_bytes`)·사람이 읽기 쉬운 크기(`size_formatted`, 예 `1.5 MB`)를 담습니다. 설정 화면에서 SEO 캐시 현황을 표시하고 캐시 초기화 여부를 판단하는 근거로 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/settings/{category}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.settings.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.settings.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\EcommerceSettingsController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| category | path | string | 예 | — | 분류 필터 (해당 분류의 항목만 조회) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 단일 설정 카테고리만 골라 조회합니다. `permission:sirsoft-ecommerce.settings.read` 권한이 필요하며, path 의 `category`(예 `basic_info`)로 `EcommerceSettingsService::getSettings()`를 호출해 해당 섹션만 반환합니다. 전체 설정을 내려받는 index 와 달리 특정 탭 데이터만 필요할 때 사용하며, 응답은 `category`·`settings`·`abilities.can_update` 를 포함합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/settings/checkout
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.settings.checkout -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.settings.checkout`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\EcommerceSettingsController@checkout`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| shipping | object | `{"default_country":"KR","available_countries":[{"code":"K…` | 체크아웃용 배송 설정 (기본 국가·배송 가능 국가·무료배송·배송유형 등) |
|
||||
| order_settings | object | `{"default_pg_provider":null,"payment_methods":[{"id":"car…` | 체크아웃용 주문/결제 설정 (기본 PG·활성 결제수단·무통장 계좌 등) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). <!-- TODO: 도메인 특이 에러가 있으면 보강 -->_
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 인증 없이 접근 가능한 공개 엔드포인트로, 체크아웃 화면이 필요로 하는 배송·결제 설정을 한 번에 반환합니다. `EcommerceSettingsService::getSettings()`로 `shipping` 과 `order_settings` 두 섹션을 함께 조회하며, 개별 shipping/payment 엔드포인트를 두 번 호출하지 않도록 묶어줍니다. 비회원·회원 모두 접근하고, `logApiUsage('settings.checkout')`로 사용 로그를 남깁니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/settings/payment
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.settings.payment -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.settings.payment`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\EcommerceSettingsController@payment`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| order_settings | object | `{"default_pg_provider":null,"payment_methods":[{"id":"car…` | 공개 가능한 결제 설정 (활성 결제수단·무통장 은행명 매핑 포함, 민감 정보 제외) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). <!-- TODO: 도메인 특이 에러가 있으면 보강 -->_
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 인증 없이 접근 가능한 공개 엔드포인트로, 체크아웃에서 필요한 결제 설정을 반환합니다. `EcommerceSettingsService::getPublicPaymentSettings()`가 활성화된 결제 수단과 무통장입금 설정 등 공개 가능한 항목만 추려 `order_settings` 로 내려줍니다. 관리자 전용 민감 정보는 제외되며, 비회원·회원 모두 접근하고 `logApiUsage('settings.payment')`로 사용 로그를 남깁니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/settings/review
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.settings.review -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.settings.review`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\EcommerceSettingsController@review`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| review_settings | object | `{"write_deadline_days":90,"max_images":5,"max_image_size_…` | 공개 리뷰 정책 (작성 기한일·이미지 최대 개수·이미지 최대 용량 MB) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). <!-- TODO: 도메인 특이 에러가 있으면 보강 -->_
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 인증 없이 접근 가능한 공개 엔드포인트로, 리뷰 작성 화면이 필요로 하는 리뷰 정책을 반환합니다. `EcommerceSettingsService::getSettings('review_settings')`로 리뷰 이미지 최대 개수(`max_images`)·최대 용량(`max_image_size_mb`)·작성 기한(`write_deadline_days`) 등을 `review_settings` 로 내려줍니다. 프론트가 이미지 업로드 제한과 작성 가능 기간을 판단하는 데 사용하며, `logApiUsage('settings.review')`로 사용 로그를 남깁니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/settings/shipping
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.settings.shipping -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.settings.shipping`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\EcommerceSettingsController@shipping`
|
||||
- **인증/권한**: 공개 (인증 불필요)
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| shipping | object | `{"default_country":"KR","available_countries":[{"code":"K…` | 공개 배송 설정 (기본 국가·배송 가능 국가·국제배송 활성 여부·배송유형·무료배송 설정) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
_대표 에러 없음 (공개 조회). <!-- TODO: 도메인 특이 에러가 있으면 보강 -->_
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 인증 없이 접근 가능한 공개 엔드포인트로, 체크아웃에서 필요한 배송 설정을 반환합니다. `EcommerceSettingsService::getSettings('shipping')`로 기본 배송 국가·이용 가능한 국가 목록·국제 배송 활성화 여부·배송 타입·무료 배송 설정 등을 `shipping` 으로 내려줍니다. 프론트가 배송지 선택과 배송비 안내를 구성하는 데 사용하며, `logApiUsage('settings.shipping')`로 사용 로그를 남깁니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
# Shipping Carriers API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Shipping Carriers 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/shipping-carriers
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-carriers.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-carriers.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingCarrierController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `13` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | integer | `1` | 기본 키 (내부 식별자) |
|
||||
| code | string | `cj` | 배송사 고유 코드 (소문자 시작 영숫자·하이픈/언더스코어, 시스템 식별용) |
|
||||
| name | object | `{"ko":"CJ대한통운","en":"CJ Logistics","ja":"CJ大韓通運"}` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| localized_name | string | `CJ대한통운` | `name` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| type | string | `domestic` | 배송사 유형 (`domestic` 국내 / `international` 해외) |
|
||||
| type_label | string | `국내` | `type` 값의 사람이 읽는 라벨 (현지화/Enum 파생) |
|
||||
| tracking_url | string | `https://trace.cjlogistics.com/next/tr…` | tracking URL |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| sort_order | integer | `0` | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| created_at | string | `2026-05-27 15:20:43` | 생성 일시 |
|
||||
| updated_at | string | `2026-06-27 00:49:51` | 최종 수정 일시 |
|
||||
| creator | array | `[]` | 생성자 정보 객체 (uuid/name/email — creator 관계 파생) |
|
||||
| updater | array | `[]` | 최종 수정자 정보 객체 (id/name — updater 관계 로드 시) |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 등록된 배송사 목록을 조회합니다. 배송 설정 영역이므로 `sirsoft-ecommerce.settings.read` 권한이 필요하며, `ShippingCarrierService::getAllCarriers()` 가 요청 파라미터로 목록을 조회해 `ShippingCarrierCollection` 으로 반환합니다. 각 항목에는 코드·다국어 배송사명·유형(국내/해외)·추적 URL·활성여부·정렬순서가 포함됩니다. 배송사 관리 화면의 목록을 채우는 데 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/shipping-carriers
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-carriers.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-carriers.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingCarrierController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| code | body | string | 예 | max 50 | 배송사 고유 코드 (소문자 시작 영숫자·하이픈/언더스코어, 중복 불가) |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| type | body | string | 예 | — | 배송사 유형 (`domestic` 국내 / `international` 해외) |
|
||||
| tracking_url | body | string | 아니오 | max 500 | 배송 추적 URL 템플릿 (`{tracking_number}` 치환자를 운송장 번호로 대체) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.shipping_carrier.create_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 새 배송사를 등록합니다. `sirsoft-ecommerce.settings.update` 권한이 필요하며, `ShippingCarrierService::createCarrier()` 가 고유 코드(`code`), 다국어 배송사명(`name`), 유형(`type`, 국내/해외), 배송 추적 URL 템플릿, 활성여부, 정렬순서를 저장하고 201 로 생성된 배송사 리소스를 반환합니다. `tracking_url` 에는 `{tracking_number}` 치환자를 넣어 추적 링크를 구성합니다. 새 택배사/특송사를 시스템에 추가할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/shipping-carriers/active
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-carriers.active -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-carriers.active`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingCarrierController@active`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| value | integer | `1` | 배송사 ID (Select 옵션의 value) |
|
||||
| label | string | `CJ대한통운` | 표시용 라벨 |
|
||||
| code | string | `cj` | 배송사 고유 코드 (시스템 식별용) |
|
||||
| type | string | `domestic` | 배송사 유형 (`domestic` 국내 / `international` 해외) |
|
||||
| tracking_url | string | `https://trace.cjlogistics.com/next/tr…` | tracking URL |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 활성화된 배송사만 Select 옵션 형태로 조회합니다. `sirsoft-ecommerce.settings.read` 권한이 필요하며, `ShippingCarrierService::getActiveCarriers()` 결과를 `{value, label, code, type, tracking_url}` 로 매핑해 반환합니다. `type` 쿼리(domestic/international)로 국내/해외 배송사를 필터링할 수 있습니다. 송장 등록 등에서 배송사를 선택하는 드롭다운을 채우는 데 사용하며, 비활성 배송사는 노출되지 않습니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/shipping-carriers/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-carriers.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-carriers.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingCarrierController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 배송사 1건을 삭제합니다. `sirsoft-ecommerce.settings.update` 권한이 필요하며, 컨트롤러가 `getCarrier()` 로 배송사를 조회해 없으면 404 를 반환한 뒤 `ShippingCarrierService::deleteCarrier()` 로 제거합니다. 주문/송장에서 사용 중이어서 삭제할 수 없는 경우 서비스 예외 메시지와 함께 400 을 반환합니다. 더 이상 쓰지 않는 배송사를 정리할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/shipping-carriers/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-carriers.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-carriers.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingCarrierController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 배송사 1건의 상세 정보를 조회합니다. `sirsoft-ecommerce.settings.read` 권한이 필요하며, `ShippingCarrierService::getCarrier()` 가 배송사를 조회해 없으면 404 를 반환하고, 있으면 코드·다국어명·유형·추적 URL·활성여부 등을 담은 단건 리소스를 반환합니다. 배송사 수정 화면 진입 시 기존 값을 불러오는 데 사용합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/shipping-carriers/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-carriers.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-carriers.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingCarrierController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| code | body | string | 아니오 | max 50 | 배송사 고유 코드 (부분 수정 시 전달, 중복 불가) |
|
||||
| name | body | array | 아니오 | — | 대상의 이름/명칭 |
|
||||
| type | body | string | 아니오 | — | 배송사 유형 (`domestic` 국내 / `international` 해외) |
|
||||
| tracking_url | body | string | 아니오 | max 500 | 배송 추적 URL 템플릿 (`{tracking_number}` 치환자를 운송장 번호로 대체) |
|
||||
| is_active | body | boolean | 아니오 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.shipping_carrier.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 기존 배송사 정보를 수정합니다. `sirsoft-ecommerce.settings.update` 권한이 필요하며, `ShippingCarrierService::updateCarrier()` 가 코드·다국어명·유형·추적 URL·활성여부·정렬순서 중 전달된 값을 갱신하고 수정된 리소스를 반환합니다(모든 body 필드는 선택적, 부분 수정 가능). 대상 배송사가 없거나 갱신에 실패하면 각각 404/400 을 반환합니다. 배송사의 추적 URL이나 표시명을 변경할 때 사용합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/shipping-carriers/{id}/toggle-status
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-carriers.toggle-status -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-carriers.toggle-status`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingCarrierController@toggleStatus`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.settings.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.settings.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 배송사 1건의 활성 상태를 토글합니다. `sirsoft-ecommerce.settings.update` 권한이 필요하며, `ShippingCarrierService::toggleStatus()` 가 현재 활성 여부를 반전시키고 갱신된 배송사 리소스를 반환합니다. 대상 배송사가 없거나 처리에 실패하면 각각 404/400 을 반환합니다. 목록 화면에서 배송사 사용여부 스위치를 켜고 끌 때 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# Shipping Country API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Shipping Country 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/user/shipping-country
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.shipping-country.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.shipping-country.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserShippingCountryController@show`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_단건 응답: `data` 객체의 필드._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| preferred_shipping_country | null | `null` | 회원이 저장한 선호 배송국가 코드 (2자리 대문자, 미설정 시 `null`) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원이 마이페이지에 저장해 둔 선호 배송국가 코드를 조회합니다. `auth:sanctum` 인증이 필요하며, `UserShippingCountryService::getPreferredShippingCountry()`가 인증 사용자 ID로 영속된 값을 반환하고 미설정 시 `preferred_shipping_country: null`을 내려줍니다. 마이페이지 배송국가 설정·회원정보 수정 화면이 초기 선택값을 채우는 데 사용합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/user/shipping-country
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.user.shipping-country.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.user.shipping-country.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\User\UserShippingCountryController@update`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| shipping_country | body | string | 예 | — | 저장할 선호 배송국가 2자리 코드 (활성 배송가능 국가만 허용, 대문자로 정규화되어 저장) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원이 선호 배송국가를 저장합니다. `auth:sanctum` 인증이 필요하며, `UpdateUserShippingCountryRequest`가 활성 국가 코드만 허용하도록 검증한 뒤 `UserShippingCountryService::setPreferredShippingCountry()`가 인증 사용자에게 영속합니다. 저장된 값은 대문자로 정규화되어 응답되며, 이후 장바구니·주문 계산의 기본 배송국가로 사용됩니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,389 @@
|
||||
# Shipping Policies API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Shipping Policies 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/shipping-policies
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-policies.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-policies.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingPolicyController@index`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| search | query | string | 아니오 | max 200 | 검색어 (지정한 검색 대상 필드에서 부분 일치) |
|
||||
| shipping_methods | query | array | 아니오 | — | 배송방법 코드로 필터 (ShippingType 코드 배열, 국가별 설정 중 하나라도 매치되는 정책만) |
|
||||
| charge_policies | query | array | 아니오 | — | 배송비 부과정책으로 필터 (free/fixed/conditional_free/range_*/api/per_* 등, 국가별 설정 매치) |
|
||||
| countries | query | array | 아니오 | — | 배송 국가 코드로 필터 (ISO 코드 배열, 해당 국가 설정을 가진 정책만) |
|
||||
| is_active | query | string | 아니오 | ``, `true`, `false` | 활성 여부 (true 활성 / false 비활성) |
|
||||
| sort_by | query | string | 아니오 | `id`, `name`, `is_active`, `sort_order`, `created_at`, `updated_at` | 정렬 기준 필드명 |
|
||||
| sort_order | query | string | 아니오 | `asc`, `desc` | 정렬 방향 (asc 오름차순 / desc 내림차순) |
|
||||
| per_page | query | integer | 아니오 | min 10, max 100 | 페이지당 항목 수 |
|
||||
| page | query | integer | 아니오 | min 1 | 조회할 페이지 번호 (1부터 시작) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.shipping_policy.list_validation_rules`, `sirsoft-ecommerce.shipping_policy.list_validation_messages`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| number | integer | `17` | 목록에서의 순번 (페이지네이션 반영 행 번호 — HasRowNumber 파생) |
|
||||
| id | integer | `47` | 기본 키 (내부 식별자) |
|
||||
| name | object | `{"ko":"API 문서 샘플 배송정책","en":"API Doc Sample Shipping Poli…` | 대상의 이름/명칭 (다국어 필드는 로케일별 값 객체) |
|
||||
| name_localized | string | `API 문서 샘플 배송정책` | `name` 의 현재 로케일 해석 값 (다국어 필드를 표시용 문자열로 해석) |
|
||||
| country_settings | array | `[]` | 국가별 배송 설정 목록 (countrySettings 관계 로드 시 각 국가의 배송방식·부과정책·배송비 상세) |
|
||||
| fee_summary | string | `` | 활성 국가별 설정을 종합한 배송비 요약 텍스트 (예: `KR: 3000원 \| US: $20`, 활성 설정 없으면 빈 문자열) |
|
||||
| countries_display | string | `` | 활성 배송 국가를 국기 이모지로 표시한 문자열 (최대 3개 노출, 초과분은 `+N` 축약) |
|
||||
| is_active | boolean | `true` | active 여부 |
|
||||
| is_default | boolean | `false` | default 여부 |
|
||||
| sort_order | integer | `0` | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| created_at | string | `2026-07-07 14:47:31` | 생성 일시 |
|
||||
| updated_at | string | `2026-07-07 14:47:31` | 최종 수정 일시 |
|
||||
| abilities | object | `{"can_create":true,"can_update":true,"can_delete":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.read`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 배송정책 목록을 페이지네이션으로 조회합니다. `sirsoft-ecommerce.shipping-policies.read` 권한이 필요하며, `ShippingPolicyService::getList()` 가 검색어·배송방식·부과정책·국가·활성여부 필터와 정렬을 적용하고, 함께 `getStatistics()` 로 집계 통계를 계산해 `ShippingPolicyCollection` 에 담아 반환합니다. 각 항목의 `abilities` 로 생성/수정/삭제 가능 여부가 내려옵니다. 배송정책 관리 목록 화면을 채우는 데 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/shipping-policies
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-policies.store -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-policies.store`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingPolicyController@store`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.create`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| is_active | body | boolean | 예 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| is_default | body | boolean | 아니오 | — | 기본값 지정 여부 |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| country_settings | body | array | 예 | min 1 | 국가별 배송 설정 배열 (최소 1개). 각 항목에 국가코드·배송방식·부과정책(charge_policy)·배송비·구간/API/도서산간 설정을 담음 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.shipping_policy.store_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.create`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 새 배송정책을 생성합니다. `sirsoft-ecommerce.shipping-policies.create` 권한이 필요하며, `ShippingPolicyService::create()` 가 다국어 정책명(`name`), 활성여부, 기본여부, 정렬순서, 국가별 설정(`country_settings`, 최소 1개)을 저장하고 201 로 생성된 정책 리소스를 반환합니다. 국가별로 배송방식·배송비 부과정책을 담은 배송정책을 새로 등록할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/shipping-policies/active
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-policies.active -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-policies.active`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingPolicyController@activeList`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| value | integer | `46` | 배송정책 ID (Select 옵션의 value) |
|
||||
| label | string | `sdfsf` | 표시용 라벨 |
|
||||
| countries_display | string | `🇰🇷` | 활성 배송 국가를 국기 이모지로 표시한 문자열 (최대 3개, 초과분 `+N`) |
|
||||
| fee_summary | string | `KR: 외부 API 연동 (실시간 계산)` | 국가별 배송비 요약 텍스트 (`country_code: fee` 형태를 ` \| ` 로 결합) |
|
||||
| is_default | boolean | `false` | default 여부 |
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.read`)이 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 활성화된 배송정책만 Select 옵션 형태로 조회합니다. `sirsoft-ecommerce.shipping-policies.read` 권한이 필요하며, `ShippingPolicyService::getActiveList()` 결과를 `{value, label, countries_display, fee_summary, is_default}` 로 매핑해 반환합니다. 상품 등록/수정 폼 등에서 배송정책을 선택하는 드롭다운을 채우는 데 사용하며, 비활성 정책은 노출되지 않습니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/shipping-policies/bulk
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-policies.bulk-destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-policies.bulk-destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingPolicyController@bulkDestroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | query | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.shipping_policy.bulk_delete_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.delete`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 선택한 여러 배송정책을 한 번에 삭제합니다. `sirsoft-ecommerce.shipping-policies.delete` 권한이 필요하며, `ShippingPolicyService::bulkDelete()` 가 `ids`(최소 1개)에 해당하는 정책들을 삭제하고 `deleted_count` 를 반환합니다. 목록 화면에서 체크박스로 다건 선택 후 일괄 삭제할 때 사용합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/shipping-policies/bulk-toggle-active
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-policies.bulk-toggle-active -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-policies.bulk-toggle-active`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingPolicyController@bulkToggleActive`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| ids | body | array | 예 | min 1 | 대상 리소스 식별자 배열 (대량 작업 대상) |
|
||||
| is_active | body | boolean | 예 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.shipping_policy.bulk_toggle_active_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 선택한 여러 배송정책의 활성 상태를 한 번에 변경합니다. `sirsoft-ecommerce.shipping-policies.update` 권한이 필요하며, `ShippingPolicyService::bulkToggleActive()` 가 `ids`(최소 1개)에 해당하는 정책들을 `is_active` 값으로 일괄 활성/비활성 처리하고 `updated_count` 를 반환합니다. 목록 화면에서 다건 선택 후 사용여부를 한꺼번에 켜거나 끌 때 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/admin/shipping-policies/test-api-call
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-policies.test-api-call -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-policies.test-api-call`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingPolicyController@testApiCall`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| endpoint | body | string | 예 | max 500 | 테스트로 호출할 외부 배송비 계산 API 엔드포인트 URL |
|
||||
| request_fields | body | array | 아니오 | — | 요청에 실어 보낼 필드명 목록 (후보 SSoT ShippingApiRequestField 5종) |
|
||||
| config | body | array | 아니오 | — | API 호출 고급 설정 (HTTP 메서드·인증방식·필드 매핑·응답 형식/경로 등) |
|
||||
| sample | body | array | 아니오 | — | 테스트 계산에 사용할 샘플 주문 데이터 (무게/금액/수량 등) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 배송정책 편집 폼에서 입력 중인 설정으로 외부 배송비 계산 API 를 1회 실호출해 미리 테스트합니다. `sirsoft-ecommerce.shipping-policies.update` 권한이 필요하며, `OrderCalculationService::testApiCall()` 이 `endpoint`·`config`·`request_fields`·`sample` 을 사용해 실제 요청을 보내고 요청 미리보기, 응답, 추출된 배송비를 반환합니다. 타임아웃과 응답 크기 제한이 적용됩니다. 실시간 계산형 배송정책을 저장하기 전에 API 연동이 올바른지 검증할 때 사용합니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/admin/shipping-policies/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-policies.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-policies.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingPolicyController@destroy`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.delete`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.delete`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 배송정책 1건을 삭제합니다. `sirsoft-ecommerce.shipping-policies.delete` 권한이 필요하며, 컨트롤러가 `getDetail()` 로 정책을 조회해 없으면 404 를 반환한 뒤 `ShippingPolicyService::delete()` 로 제거합니다. 사용 중인 정책이라 삭제할 수 없는 등 실패 시 400 을 반환합니다. 더 이상 쓰지 않는 배송정책을 개별 정리할 때 사용합니다.
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/admin/shipping-policies/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-policies.show -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-policies.show`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingPolicyController@show`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.read`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.read`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 배송정책 1건의 상세 정보를 조회합니다. `sirsoft-ecommerce.shipping-policies.read` 권한이 필요하며, `ShippingPolicyService::getDetail()` 이 정책을 조회해 없으면 404 를 반환하고, 있으면 다국어 정책명·국가별 설정·배송비 요약 등을 담은 단건 리소스를 반환합니다. 배송정책 수정 화면 진입 시 기존 값을 불러오는 데 사용합니다.
|
||||
|
||||
|
||||
### PUT /api/modules/sirsoft-ecommerce/admin/shipping-policies/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-policies.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-policies.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingPolicyController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
| name | body | array | 예 | — | 대상의 이름/명칭 |
|
||||
| is_active | body | boolean | 예 | — | 활성 여부 (true 활성 / false 비활성) |
|
||||
| is_default | body | boolean | 아니오 | — | 기본값 지정 여부 |
|
||||
| sort_order | body | integer | 아니오 | min 0 | 표시 정렬 순서 값 (작을수록 우선) |
|
||||
| country_settings | body | array | 예 | min 1 | 국가별 배송 설정 배열 (최소 1개). 각 항목에 국가코드·배송방식·부과정책(charge_policy)·배송비·구간/API/도서산간 설정을 담음 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.shipping_policy.update_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.update`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 기존 배송정책을 수정합니다. `sirsoft-ecommerce.shipping-policies.update` 권한이 필요하며, 컨트롤러가 `getDetail()` 로 정책을 조회해 없으면 404 를 반환한 뒤 `ShippingPolicyService::update()` 가 다국어 정책명·활성여부·기본여부·정렬순서·국가별 설정(`country_settings`, 최소 1개)을 갱신하고 수정된 리소스를 반환합니다. 배송정책의 국가별 배송비/방식을 변경할 때 사용합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/shipping-policies/{id}/set-default
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-policies.set-default -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-policies.set-default`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingPolicyController@setDefault`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 지정한 배송정책을 기본 배송정책으로 설정합니다. `sirsoft-ecommerce.shipping-policies.update` 권한이 필요하며, 컨트롤러가 `getDetail()` 로 정책을 조회해 없으면 404 를 반환한 뒤 `ShippingPolicyService::setDefault()` 가 해당 정책을 기본값으로 지정합니다(기존 기본 정책은 해제). 별도 정책이 매칭되지 않을 때 적용되는 기본 배송정책을 바꿀 때 사용합니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/shipping-policies/{id}/toggle-active
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.shipping-policies.toggle-active -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.shipping-policies.toggle-active`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\ShippingPolicyController@toggleActive`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.shipping-policies.update`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.shipping-policies.update`)이 없는 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 배송정책 1건의 활성 상태를 토글합니다. `sirsoft-ecommerce.shipping-policies.update` 권한이 필요하며, 컨트롤러가 `getDetail()` 로 정책을 조회해 없으면 404 를 반환한 뒤 `ShippingPolicyService::toggleActive()` 가 현재 활성 여부를 반전시키고 갱신된 리소스를 반환합니다. 목록 화면에서 개별 정책의 사용여부 스위치를 켜고 끌 때 사용합니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# Users API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Users 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/users/{user}/currency
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.users.currency.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.users.currency.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\AdminUserCurrencyController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.user-currency.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| user | path | string | 예 | — | 대상 user의 식별자 |
|
||||
| currency | body | string | 예 | — | 회원에게 지정할 결제 통화 코드 (등록 통화: is_default 또는 exchange_rate>0 인 통화만 허용) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.user-currency.manage`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 회원의 선호 결제 통화를 변경합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.user-currency.manage` 권한이 필요하며, path의 `{user}`는 UUID 라우트 모델 바인딩(관리자 회원 URL 규약)으로 주입됩니다. `UserCurrencyService::changeUserCurrencyByAdmin()`이 통화 저장과 활동 로그 훅 발화를 한 단위로 처리하며, `currency`는 등록된 통화 코드만 허용됩니다. 관리자 회원 상세 화면에서 회원별 결제 통화를 지정하는 용도입니다.
|
||||
|
||||
|
||||
### PATCH /api/modules/sirsoft-ecommerce/admin/users/{user}/shipping-country
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.admin.users.shipping-country.update -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.admin.users.shipping-country.update`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Admin\AdminUserShippingCountryController@update`
|
||||
- **인증/권한**: `auth:sanctum` + `permission:sirsoft-ecommerce.user-shipping-country.manage`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| user | path | string | 예 | — | 대상 user의 식별자 |
|
||||
| shipping_country | body | string | 예 | — | 회원에게 지정할 배송국가 2자리 코드 (활성 배송가능 국가만 허용, 대문자로 정규화) |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 403 | Forbidden | 요구 권한(`sirsoft-ecommerce.user-shipping-country.manage`)이 없는 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 관리자가 특정 회원의 선호 배송국가를 변경합니다. `auth:sanctum` + admin + `sirsoft-ecommerce.user-shipping-country.manage` 권한이 필요하며, path의 `{user}`는 UUID 라우트 모델 바인딩으로 주입됩니다. `UserShippingCountryService::changeUserShippingCountryByAdmin()`이 배송국가 저장과 활동 로그 훅 발화를 한 단위로 처리하고, `shipping_country`는 활성 국가만 허용되며 대문자로 정규화되어 반환됩니다. 관리자 회원 상세 화면에서 회원별 기본 배송국가를 지정하는 용도입니다.
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
# Wishlist API 레퍼런스
|
||||
|
||||
> **소유**: module `sirsoft-ecommerce` · **생성**: `php artisan api:docgen` (실측 기반). @generated 블록은 재생성 시 갱신되며, 사람이 작성한 설명은 보존됩니다.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR (5초 요약)
|
||||
|
||||
```text
|
||||
1. 이 문서는 실제 API 호출로 실측한 Wishlist 엔드포인트 레퍼런스입니다
|
||||
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
|
||||
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
|
||||
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
|
||||
5. 설명(TODO) 칸은 사람이 채웁니다
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### GET /api/modules/sirsoft-ecommerce/wishlist
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.wishlist.index -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.wishlist.index`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\WishlistController@index`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
_요청 파라미터 없음._
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
_목록 응답: `data.data[]` 배열 항목의 필드 + `data.pagination`._
|
||||
|
||||
<!-- 실측 응답에 필드 없음(빈 목록 등) — 데이터가 있는 상태로 재실측하거나 사람이 작성. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 로그인한 회원의 찜(위시리스트) 목록을 페이지네이션으로 조회합니다. `auth:sanctum` 인증이 필요하며, `WishlistController@index`가 `ProductWishlistService::getByUser()`로 본인 찜 목록만 가져와 `WishlistCollection`으로 반환합니다. `per_page`는 기본 20건이며 최대 100건으로 제한됩니다. 마이페이지의 찜 목록 화면에서 사용합니다.
|
||||
|
||||
|
||||
### POST /api/modules/sirsoft-ecommerce/wishlist/toggle
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.wishlist.toggle -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.wishlist.toggle`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\WishlistController@toggle`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| product_id | body | integer | 예 | — | product 식별자 |
|
||||
|
||||
> 이 엔드포인트는 확장이 파라미터를 추가할 수 있습니다 (`sirsoft-ecommerce.wishlist.toggle_validation_rules`).
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 422 | Unprocessable Entity | 요청 파라미터가 검증 규칙을 위반한 경우 (`error.errors` 에 필드별 메시지) |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 특정 상품(`product_id`)의 찜 상태를 토글합니다. `auth:sanctum` 인증이 필요하며, `WishlistController@toggle`이 `ProductWishlistService::toggle()`을 호출해 이미 찜한 상품이면 제거하고 아니면 추가한 뒤 `added` 불리언을 반환합니다. 상품 상세/목록의 찜 하트 버튼이 이 하나의 엔드포인트로 추가·제거를 모두 처리합니다. 응답의 `added` 값으로 현재 찜 여부를 즉시 갱신할 수 있습니다.
|
||||
|
||||
|
||||
### DELETE /api/modules/sirsoft-ecommerce/wishlist/{id}
|
||||
<!-- @generated:start:api.modules.sirsoft-ecommerce.wishlist.destroy -->
|
||||
- **라우트명**: `api.modules.sirsoft-ecommerce.wishlist.destroy`
|
||||
- **컨트롤러**: `Modules\Sirsoft\Ecommerce\Http\Controllers\Public\WishlistController@destroy`
|
||||
- **인증/권한**: `auth:sanctum`
|
||||
|
||||
**요청 파라미터**
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | string | 예 | — | 대상 리소스의 식별자 |
|
||||
|
||||
**응답 필드** (`data` 내부)
|
||||
|
||||
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
|
||||
|
||||
**에러 응답**
|
||||
|
||||
| 상태코드 | 의미 | 발생 조건 |
|
||||
| --- | --- | --- |
|
||||
| 401 | Unauthenticated | 유효한 Bearer 토큰이 없거나 만료된 경우 |
|
||||
| 404 | Not Found | path 파라미터에 해당하는 리소스가 없는 경우 |
|
||||
|
||||
<!-- @generated:end -->
|
||||
|
||||
**설명** 찜 목록에서 특정 찜 항목(`id`)을 삭제합니다. `auth:sanctum` 인증이 필요하며, `WishlistController@destroy`가 `ProductWishlistService::destroy()`로 본인 소유 찜만 삭제합니다. 상품 ID가 아니라 찜 레코드 ID로 삭제하며, 해당 항목이 본인 것이 아니거나 존재하지 않으면 404를 반환합니다. 상품 상세의 하트 토글과 달리 마이페이지 찜 목록에서 특정 항목을 명시적으로 제거할 때 사용합니다.
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user