fix : 카테고리 API

This commit is contained in:
2025-08-22 18:08:57 +09:00
parent cd81285731
commit 4b6e43ee62
5 changed files with 581 additions and 49 deletions

View File

@@ -22,6 +22,7 @@
use App\Http\Controllers\Api\V1\TenantOptionGroupController;
use App\Http\Controllers\Api\V1\TenantOptionValueController;
use App\Http\Controllers\Api\V1\TenantUserProfileController;
use App\Http\Controllers\Api\V1\CategoryController;
// error test
Route::get('/test-error', function () {
@@ -122,61 +123,61 @@
// Menu API
Route::middleware(['perm.map', 'permission'])->prefix('menus')->group(function () {
Route::get ('/', [MenuController::class, 'index'])->name('v1.menus.index');
Route::get ('/{id}', [MenuController::class, 'show'])->name('v1.menus.show');
Route::post ('/', [MenuController::class, 'store'])->name('v1.menus.store');
Route::patch ('/{id}', [MenuController::class, 'update'])->name('v1.menus.update');
Route::delete('/{id}', [MenuController::class, 'destroy'])->name('v1.menus.destroy');
Route::post ('/reorder', [MenuController::class, 'reorder'])->name('v1.menus.reorder');
Route::post ('/{id}/toggle', [MenuController::class, 'toggle'])->name('v1.menus.toggle');
Route::get('/', [MenuController::class, 'index'])->name('v1.menus.index');
Route::get('/{id}', [MenuController::class, 'show'])->name('v1.menus.show');
Route::post('/', [MenuController::class, 'store'])->name('v1.menus.store');
Route::patch('/{id}', [MenuController::class, 'update'])->name('v1.menus.update');
Route::delete('/{id}', [MenuController::class, 'destroy'])->name('v1.menus.destroy');
Route::post('/reorder', [MenuController::class, 'reorder'])->name('v1.menus.reorder');
Route::post('/{id}/toggle', [MenuController::class, 'toggle'])->name('v1.menus.toggle');
});
// Role API
Route::prefix('roles')->group(function () {
Route::get ('/', [RoleController::class, 'index'])->name('v1.roles.index'); // view
Route::post ('/', [RoleController::class, 'store'])->name('v1.roles.store'); // create
Route::get ('/{id}', [RoleController::class, 'show'])->name('v1.roles.show'); // view
Route::patch ('/{id}', [RoleController::class, 'update'])->name('v1.roles.update'); // update
Route::delete('/{id}', [RoleController::class, 'destroy'])->name('v1.roles.destroy');// delete
Route::get('/', [RoleController::class, 'index'])->name('v1.roles.index'); // view
Route::post('/', [RoleController::class, 'store'])->name('v1.roles.store'); // create
Route::get('/{id}', [RoleController::class, 'show'])->name('v1.roles.show'); // view
Route::patch('/{id}', [RoleController::class, 'update'])->name('v1.roles.update'); // update
Route::delete('/{id}', [RoleController::class, 'destroy'])->name('v1.roles.destroy');// delete
});
// Role Permission API
Route::prefix('roles/{id}/permissions')->group(function () {
Route::get ('/', [RolePermissionController::class, 'index'])->name('v1.roles.perms.index'); // list
Route::post ('/', [RolePermissionController::class, 'grant'])->name('v1.roles.perms.grant'); // grant
Route::delete('/', [RolePermissionController::class, 'revoke'])->name('v1.roles.perms.revoke'); // revoke
Route::put ('/sync', [RolePermissionController::class, 'sync'])->name('v1.roles.perms.sync'); // sync
Route::get('/', [RolePermissionController::class, 'index'])->name('v1.roles.perms.index'); // list
Route::post('/', [RolePermissionController::class, 'grant'])->name('v1.roles.perms.grant'); // grant
Route::delete('/', [RolePermissionController::class, 'revoke'])->name('v1.roles.perms.revoke'); // revoke
Route::put('/sync', [RolePermissionController::class, 'sync'])->name('v1.roles.perms.sync'); // sync
});
// User Role API
Route::prefix('users/{id}/roles')->group(function () {
Route::get ('/', [UserRoleController::class, 'index'])->name('v1.users.roles.index'); // list
Route::post ('/', [UserRoleController::class, 'grant'])->name('v1.users.roles.grant'); // grant
Route::delete('/', [UserRoleController::class, 'revoke'])->name('v1.users.roles.revoke'); // revoke
Route::put ('/sync', [UserRoleController::class, 'sync'])->name('v1.users.roles.sync'); // sync
Route::get('/', [UserRoleController::class, 'index'])->name('v1.users.roles.index'); // list
Route::post('/', [UserRoleController::class, 'grant'])->name('v1.users.roles.grant'); // grant
Route::delete('/', [UserRoleController::class, 'revoke'])->name('v1.users.roles.revoke'); // revoke
Route::put('/sync', [UserRoleController::class, 'sync'])->name('v1.users.roles.sync'); // sync
});
// Department API
Route::prefix('departments')->group(function () {
Route::get ('', [DepartmentController::class, 'index'])->name('departments.index'); // 목록
Route::post ('', [DepartmentController::class, 'store'])->name('departments.store'); // 생성
Route::get ('/{id}', [DepartmentController::class, 'show'])->name('departments.show'); // 단건
Route::patch ('/{id}', [DepartmentController::class, 'update'])->name('departments.update'); // 수정
Route::delete('/{id}', [DepartmentController::class, 'destroy'])->name('departments.destroy'); // 삭제(soft)
Route::get('', [DepartmentController::class, 'index'])->name('departments.index'); // 목록
Route::post('', [DepartmentController::class, 'store'])->name('departments.store'); // 생성
Route::get('/{id}', [DepartmentController::class, 'show'])->name('departments.show'); // 단건
Route::patch('/{id}', [DepartmentController::class, 'update'])->name('departments.update'); // 수정
Route::delete('/{id}', [DepartmentController::class, 'destroy'])->name('departments.destroy'); // 삭제(soft)
// 부서-사용자
Route::get ('/{id}/users', [DepartmentController::class, 'listUsers'])->name('departments.users.index'); // 부서 사용자 목록
Route::post ('/{id}/users', [DepartmentController::class, 'attachUser'])->name('departments.users.attach'); // 사용자 배정(주/부서)
Route::get('/{id}/users', [DepartmentController::class, 'listUsers'])->name('departments.users.index'); // 부서 사용자 목록
Route::post('/{id}/users', [DepartmentController::class, 'attachUser'])->name('departments.users.attach'); // 사용자 배정(주/부서)
Route::delete('/{id}/users/{user}', [DepartmentController::class, 'detachUser'])->name('departments.users.detach'); // 사용자 제거
Route::patch ('/{id}/users/{user}/primary', [DepartmentController::class, 'setPrimary'])->name('departments.users.primary'); // 주부서 설정/해제
Route::patch('/{id}/users/{user}/primary', [DepartmentController::class, 'setPrimary'])->name('departments.users.primary'); // 주부서 설정/해제
// 부서-권한
Route::get ('/{id}/permissions', [DepartmentController::class, 'listPermissions'])->name('departments.permissions.index'); // 권한 목록
Route::post ('/{id}/permissions', [DepartmentController::class, 'upsertPermissions'])->name('departments.permissions.upsert'); // 권한 부여/차단(메뉴별 가능)
Route::get('/{id}/permissions', [DepartmentController::class, 'listPermissions'])->name('departments.permissions.index'); // 권한 목록
Route::post('/{id}/permissions', [DepartmentController::class, 'upsertPermissions'])->name('departments.permissions.upsert'); // 권한 부여/차단(메뉴별 가능)
Route::delete('/{id}/permissions/{permission}', [DepartmentController::class, 'revokePermissions'])->name('departments.permissions.revoke'); // 권한 제거(해당 메뉴 범위까지)
});
@@ -191,33 +192,50 @@
// 테넌트 필드 설정
Route::prefix('fields')->group(function () {
Route::get ('', [TenantFieldSettingController::class, 'index'])->name('v1.fields.index'); // 필드 설정 목록(전역+테넌트 병합 효과값)
Route::put ('/bulk', [TenantFieldSettingController::class, 'bulkUpsert'])->name('v1.fields.bulk'); // 필드 설정 대량 저장(트랜잭션 처리)
Route::patch ('/{key}', [TenantFieldSettingController::class, 'updateOne'])->name('v1.fields.update'); // 필드 설정 단건 수정/업데이트
Route::get('', [TenantFieldSettingController::class, 'index'])->name('v1.fields.index'); // 필드 설정 목록(전역+테넌트 병합 효과값)
Route::put('/bulk', [TenantFieldSettingController::class, 'bulkUpsert'])->name('v1.fields.bulk'); // 필드 설정 대량 저장(트랜잭션 처리)
Route::patch('/{key}', [TenantFieldSettingController::class, 'updateOne'])->name('v1.fields.update'); // 필드 설정 단건 수정/업데이트
});
// 옵션 그룹/값
Route::prefix('opt-groups')->group(function () {
Route::get ('', [TenantOptionGroupController::class, 'index'])->name('v1.opt-groups.index'); // 옵션 그룹 목록
Route::post ('', [TenantOptionGroupController::class, 'store'])->name('v1.opt-groups.store'); // 옵션 그룹 생성
Route::get ('/{id}', [TenantOptionGroupController::class, 'show'])->name('v1.opt-groups.show'); // 옵션 그룹 단건 조회
Route::patch ('/{id}', [TenantOptionGroupController::class, 'update'])->name('v1.opt-groups.update'); // 옵션 그룹 수정
Route::delete('/{id}', [TenantOptionGroupController::class, 'destroy'])->name('v1.opt-groups.destroy'); // 옵션 그룹 삭제
Route::get ('/{gid}/values', [TenantOptionValueController::class, 'index'])->name('v1.opt-groups.values.index'); // 옵션 값 목록
Route::post ('/{gid}/values', [TenantOptionValueController::class, 'store'])->name('v1.opt-groups.values.store'); // 옵션 값 생성
Route::get ('/{gid}/values/{id}', [TenantOptionValueController::class, 'show'])->name('v1.opt-groups.values.show'); // 옵션 값 단건 조회
Route::patch ('/{gid}/values/{id}', [TenantOptionValueController::class, 'update'])->name('v1.opt-groups.values.update'); // 옵션 값 수정
Route::delete('/{gid}/values/{id}', [TenantOptionValueController::class, 'destroy'])->name('v1.opt-groups.values.destroy'); // 옵션 값 삭제
Route::patch ('/{gid}/values/reorder', [TenantOptionValueController::class, 'reorder'])->name('v1.opt-groups.values.reorder'); // 옵션 값 정렬순서 재배치
Route::get('', [TenantOptionGroupController::class, 'index'])->name('v1.opt-groups.index'); // 옵션 그룹 목록
Route::post('', [TenantOptionGroupController::class, 'store'])->name('v1.opt-groups.store'); // 옵션 그룹 생성
Route::get('/{id}', [TenantOptionGroupController::class, 'show'])->name('v1.opt-groups.show'); // 옵션 그룹 단건 조회
Route::patch('/{id}', [TenantOptionGroupController::class, 'update'])->name('v1.opt-groups.update'); // 옵션 그룹 수정
Route::delete('/{id}', [TenantOptionGroupController::class, 'destroy'])->name('v1.opt-groups.destroy'); // 옵션 그룹 삭제
Route::get('/{gid}/values', [TenantOptionValueController::class, 'index'])->name('v1.opt-groups.values.index'); // 옵션 값 목록
Route::post('/{gid}/values', [TenantOptionValueController::class, 'store'])->name('v1.opt-groups.values.store'); // 옵션 값 생성
Route::get('/{gid}/values/{id}', [TenantOptionValueController::class, 'show'])->name('v1.opt-groups.values.show'); // 옵션 값 단건 조회
Route::patch('/{gid}/values/{id}', [TenantOptionValueController::class, 'update'])->name('v1.opt-groups.values.update'); // 옵션 값 수정
Route::delete('/{gid}/values/{id}', [TenantOptionValueController::class, 'destroy'])->name('v1.opt-groups.values.destroy'); // 옵션 값 삭제
Route::patch('/{gid}/values/reorder', [TenantOptionValueController::class, 'reorder'])->name('v1.opt-groups.values.reorder'); // 옵션 값 정렬순서 재배치
});
// 회원 프로필(테넌트 기준)
Route::prefix('profiles')->group(function () {
Route::get ('', [TenantUserProfileController::class, 'index'])->name('v1.profiles.index'); // 프로필 목록(테넌트 기준)
Route::get ('/{userId}', [TenantUserProfileController::class, 'show'])->name('v1.profiles.show'); // 특정 사용자 프로필 조회
Route::patch ('/{userId}', [TenantUserProfileController::class, 'update'])->name('v1.profiles.update'); // 특정 사용자 프로필 수정(관리자)
Route::get ('/me', [TenantUserProfileController::class, 'me'])->name('v1.profiles.me'); // 내 프로필 조회
Route::patch ('/me', [TenantUserProfileController::class, 'updateMe'])->name('v1.profiles.me.update'); // 내 프로필 수정
Route::get('', [TenantUserProfileController::class, 'index'])->name('v1.profiles.index'); // 프로필 목록(테넌트 기준)
Route::get('/{userId}', [TenantUserProfileController::class, 'show'])->name('v1.profiles.show'); // 특정 사용자 프로필 조회
Route::patch('/{userId}', [TenantUserProfileController::class, 'update'])->name('v1.profiles.update'); // 특정 사용자 프로필 수정(관리자)
Route::get('/me', [TenantUserProfileController::class, 'me'])->name('v1.profiles.me'); // 내 프로필 조회
Route::patch('/me', [TenantUserProfileController::class, 'updateMe'])->name('v1.profiles.me.update'); // 내 프로필 수정
});
// Category API
Route::prefix('categories')->group(function () {
// 확장 기능
Route::get('/tree', [CategoryController::class, 'tree'])->name('v1.categories.tree'); // 트리
Route::post('/reorder', [CategoryController::class, 'reorder'])->name('v1.categories.reorder'); // 정렬 일괄
Route::post('/{id}/toggle', [CategoryController::class, 'toggle'])->name('v1.categories.toggle'); // 활성 토글
Route::patch('/{id}/move', [CategoryController::class, 'move'])->name('v1.categories.move'); // 부모/순서 이동
// 기본
Route::get('', [CategoryController::class, 'index'])->name('v1.categories.index'); // 목록(페이징)
Route::post('', [CategoryController::class, 'store'])->name('v1.categories.store'); // 생성
Route::get('/{id}', [CategoryController::class, 'show'])->name('v1.categories.show'); // 단건
Route::patch('/{id}', [CategoryController::class, 'update'])->name('v1.categories.update'); // 수정
Route::delete('/{id}', [CategoryController::class, 'destroy'])->name('v1.categories.destroy'); // 삭제(soft)
});
});