feat: TenantApi.php & CategoryApi.php Swagger 점검 및 개선 (Phase 3-5, 3-6)

Phase 3-5 (TenantApi.php):
- TenantStoreRequest.php 생성 (검증 로직 분리)
- TenantUpdateRequest.php 생성 (검증 로직 분리)
- TenantController.php FormRequest 적용 및 DI 패턴 적용
- TenantService static 호출 → DI 인스턴스 호출
- lang/ko/message.php tenant 메시지 키 추가

Phase 3-6 (CategoryApi.php):
- CategoryStoreRequest.php 생성 (검증 로직 분리)
- CategoryUpdateRequest.php 생성 (검증 로직 분리)
- CategoryMoveRequest.php 생성 (카테고리 이동 검증)
- CategoryReorderRequest.php 생성 (정렬순서 일괄 변경 검증)
- CategoryController.php FormRequest 적용
- lang/ko/message.php category 메시지 키 추가
- SAM API Development Rules 준수 완료
This commit is contained in:
2025-11-07 02:47:30 +09:00
parent 97c0d8245e
commit 17a710f8ef
9 changed files with 198 additions and 29 deletions

View File

@@ -4,6 +4,10 @@
use App\Helpers\ApiResponse;
use App\Http\Controllers\Controller;
use App\Http\Requests\Category\CategoryMoveRequest;
use App\Http\Requests\Category\CategoryReorderRequest;
use App\Http\Requests\Category\CategoryStoreRequest;
use App\Http\Requests\Category\CategoryUpdateRequest;
use App\Services\CategoryService;
use Illuminate\Http\Request;
@@ -13,46 +17,46 @@ public function __construct(private CategoryService $service) {}
public function index(Request $request)
{
return ApiResponse::handle(fn () => $this->service->index($request->all()), '카테고리 목록 조회');
return ApiResponse::handle(fn () => $this->service->index($request->all()), __('message.category.fetched'));
}
public function show(int $id)
{
return ApiResponse::handle(fn () => $this->service->show($id), '카테고리 단건 조회');
return ApiResponse::handle(fn () => $this->service->show($id), __('message.category.fetched'));
}
public function store(Request $request)
public function store(CategoryStoreRequest $request)
{
return ApiResponse::handle(fn () => $this->service->store($request->all()), '카테고리 생성');
return ApiResponse::handle(fn () => $this->service->store($request->validated()), __('message.category.created'));
}
public function update(int $id, Request $request)
public function update(int $id, CategoryUpdateRequest $request)
{
return ApiResponse::handle(fn () => $this->service->update($id, $request->all()), '카테고리 수정');
return ApiResponse::handle(fn () => $this->service->update($id, $request->validated()), __('message.category.updated'));
}
public function destroy(int $id)
{
return ApiResponse::handle(fn () => $this->service->destroy($id), '카테고리 삭제');
return ApiResponse::handle(fn () => $this->service->destroy($id), __('message.category.deleted'));
}
public function toggle(int $id)
{
return ApiResponse::handle(fn () => $this->service->toggle($id), '카테고리 활성/비활성 토글');
return ApiResponse::handle(fn () => $this->service->toggle($id), __('message.category.toggled'));
}
public function move(int $id, Request $request)
public function move(int $id, CategoryMoveRequest $request)
{
return ApiResponse::handle(fn () => $this->service->move($id, $request->all()), '카테고리 이동');
return ApiResponse::handle(fn () => $this->service->move($id, $request->validated()), __('message.category.moved'));
}
public function reorder(Request $request)
public function reorder(CategoryReorderRequest $request)
{
return ApiResponse::handle(fn () => $this->service->reorder($request->all()), '카테고리 정렬순서 일괄 변경');
return ApiResponse::handle(fn () => $this->service->reorder($request->validated()), __('message.category.reordered'));
}
public function tree(Request $request)
{
return ApiResponse::handle(fn () => $this->service->tree($request->all()), '카테고리 트리 조회');
return ApiResponse::handle(fn () => $this->service->tree($request->all()), __('message.category.tree_fetched'));
}
}

View File

@@ -4,50 +4,54 @@
use App\Helpers\ApiResponse;
use App\Http\Controllers\Controller;
use App\Http\Requests\Tenant\TenantStoreRequest;
use App\Http\Requests\Tenant\TenantUpdateRequest;
use App\Services\TenantService;
use Illuminate\Http\Request;
class TenantController extends Controller
{
public function __construct(private TenantService $service) {}
public function index(Request $request)
{
return ApiResponse::handle(function () use ($request) {
return TenantService::getTenants($request->all());
}, '테넌트목록 조회');
return $this->service->getTenants($request->all());
}, __('message.tenant.fetched'));
}
public function show(Request $request)
{
return ApiResponse::handle(function () use ($request) {
return TenantService::getTenant($request->all());
}, '테넌트정보 조회');
return $this->service->getTenant($request->all());
}, __('message.tenant.fetched'));
}
public function update(Request $request)
public function store(TenantStoreRequest $request)
{
return ApiResponse::handle(function () use ($request) {
return TenantService::updateTenant($request->all());
}, '테넌트정보 수정');
return $this->service->storeTenants($request->validated());
}, __('message.tenant.created'));
}
public function store(Request $request)
public function update(TenantUpdateRequest $request)
{
return ApiResponse::handle(function () use ($request) {
return TenantService::storeTenants($request->all());
}, '테넌트 등록');
return $this->service->updateTenant($request->validated());
}, __('message.tenant.updated'));
}
public function destroy(Request $request)
{
return ApiResponse::handle(function () use ($request) {
return TenantService::destroyTenant($request->all());
}, '테넌트 삭제(탈퇴)');
return $this->service->destroyTenant($request->all());
}, __('message.tenant.deleted'));
}
public function restore(Request $request)
{
return ApiResponse::handle(function () use ($request) {
return TenantService::restoreTenant($request->all());
}, '테넌트 복구');
return $this->service->restoreTenant($request->all());
}, __('message.tenant.restored'));
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Http\Requests\Category;
use Illuminate\Foundation\Http\FormRequest;
class CategoryMoveRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'parent_id' => 'nullable|integer|exists:categories,id',
'sort_order' => 'nullable|integer',
];
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Http\Requests\Category;
use Illuminate\Foundation\Http\FormRequest;
class CategoryReorderRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'items' => 'required|array',
'items.*.id' => 'required|integer|exists:categories,id',
'items.*.sort_order' => 'required|integer',
];
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Http\Requests\Category;
use Illuminate\Foundation\Http\FormRequest;
class CategoryStoreRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'parent_id' => 'nullable|integer|exists:categories,id',
'code' => 'nullable|string|max:50',
'name' => 'required|string|max:100',
'description' => 'nullable|string|max:255',
'is_active' => 'nullable|boolean',
'sort_order' => 'nullable|integer',
];
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Http\Requests\Category;
use Illuminate\Foundation\Http\FormRequest;
class CategoryUpdateRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'parent_id' => 'nullable|integer|exists:categories,id',
'code' => 'nullable|string|max:50',
'name' => 'sometimes|string|max:100',
'description' => 'nullable|string|max:255',
'is_active' => 'nullable|boolean',
'sort_order' => 'nullable|integer',
];
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Http\Requests\Tenant;
use Illuminate\Foundation\Http\FormRequest;
class TenantStoreRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'company_name' => 'required|string|max:100',
'email' => 'nullable|email|max:100',
'phone' => 'nullable|string|max:20',
'address' => 'nullable|string|max:255',
'business_num' => 'nullable|string|max:20',
'ceo_name' => 'nullable|string|max:100',
];
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Http\Requests\Tenant;
use Illuminate\Foundation\Http\FormRequest;
class TenantUpdateRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'tenant_id' => 'required|integer|exists:tenants,id',
'company_name' => 'sometimes|string|max:100',
'email' => 'nullable|email|max:100',
'phone' => 'nullable|string|max:20',
'address' => 'nullable|string|max:255',
'business_num' => 'nullable|string|max:20',
'ceo_name' => 'nullable|string|max:100',
];
}
}

View File

@@ -51,6 +51,14 @@
],
'category' => [
'fetched' => '카테고리를 조회했습니다.',
'created' => '카테고리가 등록되었습니다.',
'updated' => '카테고리가 수정되었습니다.',
'deleted' => '카테고리가 삭제되었습니다.',
'toggled' => '카테고리 상태가 변경되었습니다.',
'moved' => '카테고리가 이동되었습니다.',
'reordered' => '카테고리 정렬순서가 변경되었습니다.',
'tree_fetched' => '카테고리 트리를 조회했습니다.',
'fields_saved' => '카테고리 필드가 저장되었습니다.',
'template_saved' => '카테고리 템플릿이 저장되었습니다.',
'template_applied' => '카테고리 템플릿이 적용되었습니다.',
@@ -110,6 +118,15 @@
'tenant_switched' => '활성 테넌트가 전환되었습니다.',
],
// 테넌트 관리
'tenant' => [
'fetched' => '테넌트를 조회했습니다.',
'created' => '테넌트가 등록되었습니다.',
'updated' => '테넌트가 수정되었습니다.',
'deleted' => '테넌트가 삭제되었습니다.',
'restored' => '테넌트가 복구되었습니다.',
],
// 파일 관리
'file' => [
'uploaded' => '파일이 업로드되었습니다.',