상위 문서: 백엔드 가이드 인덱스
1. 모든 라우트는 name() 필수: ->name('api.users.index')
2. 접두사: api.*, web.*, vendor-module.*
3. URL: /api/admin/*, /api/auth/*, /api/public/*
4. 권한: permission: 또는 Middleware에서 체크
5. REST 패턴: index, store, show, update, destroy
- 모든 라우트는
name필수 - 일관된 네이밍 컨벤션 준수
| 타입 | 접두사 | 예시 |
|---|---|---|
| API | api. |
api.users.index |
| WEB | web. |
web.dashboard |
| 모듈 | [vendor-module]. |
sirsoft-ecommerce.products.index |
| 플러그인 | [vendor-plugin]. |
sirsoft-payment.settings |
// 코어 API
->name('api.users.index')
->name('api.users.store')
// 모듈 API
->name('api.sirsoft-ecommerce.products.index')
->name('api.sirsoft-ecommerce.products.store')
// 플러그인 API
->name('api.sirsoft-payment.transactions.index')| 타입 | 패턴 | 예시 |
|---|---|---|
| 코어 | /admin/[기능명] |
/admin/users |
| 모듈 | /admin/[vendor-module]/[기능명] |
/admin/sirsoft-ecommerce/products |
| 플러그인 | /admin/[vendor-plugin]/[기능명] |
/admin/sirsoft-payment/settings |
| 모듈 공개 API | /api/modules/[vendor-module]/[기능명] |
/api/modules/sirsoft-ecommerce/products |
| 플러그인 공개 API | /api/plugins/[vendor-plugin]/[기능명] |
/api/plugins/sirsoft-gdpr/consent |
# 목록 조회
GET /admin/sirsoft-ecommerce/products
# 단일 조회
GET /admin/sirsoft-ecommerce/products/{id}
# 생성
POST /admin/sirsoft-ecommerce/products
# 수정
PUT /admin/sirsoft-ecommerce/products/{id}
# 삭제
DELETE /admin/sirsoft-ecommerce/products/{id}
코어 및 확장의 LICENSE 파일 내용을 반환하는 API 엔드포인트입니다.
GET /api/admin/license # 코어 LICENSE 반환
GET /api/admin/modules/{identifier}/license # 모듈 LICENSE 반환
GET /api/admin/plugins/{identifier}/license # 플러그인 LICENSE 반환
GET /api/admin/templates/{identifier}/license # 템플릿 LICENSE 반환
주의: FormRequest의 authorize() 메서드 사용 금지
필수: 라우트에 permission 미들웨어 체인
// ✅ DO: 라우트에 permission 미들웨어 사용
Route::get('/products', [ProductController::class, 'index'])
->middleware('permission:sirsoft-ecommerce.products.view')
->name('api.sirsoft-ecommerce.products.index');
// ❌ DON'T: FormRequest에서 권한 체크
class ProductRequest extends FormRequest
{
public function authorize(): bool
{
// 이 방식 사용 금지
return $this->user()->can('view-products');
}
}[vendor-module].[resource].[action]
예시:
sirsoft-ecommerce.products.view
sirsoft-ecommerce.products.create
sirsoft-ecommerce.products.edit
sirsoft-ecommerce.products.delete
// modules/_bundled/sirsoft-ecommerce/src/routes/api.php
use Illuminate\Support\Facades\Route;
use Modules\Sirsoft\Ecommerce\Controllers\Api\Admin\ProductController;
// 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('products.index'); // 최종 name: api.modules.sirsoft-ecommerce.products.index
Route::post('/products', [ProductController::class, 'store'])
->middleware('permission:sirsoft-ecommerce.products.create')
->name('products.store');
Route::get('/products/{id}', [ProductController::class, 'show'])
->middleware('permission:sirsoft-ecommerce.products.view')
->name('products.show');
Route::put('/products/{id}', [ProductController::class, 'update'])
->middleware('permission:sirsoft-ecommerce.products.edit')
->name('products.update');
Route::delete('/products/{id}', [ProductController::class, 'destroy'])
->middleware('permission:sirsoft-ecommerce.products.delete')
->name('products.destroy');
});// routes/api.php
use App\Http\Controllers\Api\Admin\UserController;
Route::prefix('admin')->middleware(['auth:sanctum', 'admin'])->group(function () {
// 사용자 관리
Route::get('/users', [UserController::class, 'index'])
->middleware('permission:users.view')
->name('api.users.index');
Route::post('/users', [UserController::class, 'store'])
->middleware('permission:users.create')
->name('api.users.store');
});자기 자신 또는 소유자에 대해 권한 체크를 바이패스하는 라우트:
// routes/api.php
Route::prefix('admin')->middleware(['auth:sanctum', 'admin'])->group(function () {
// 사용자 수정: 자기 자신은 core.users.update 권한 없이 수정 가능
Route::put('/users/{user}', [UserController::class, 'update'])
->middleware('permission:admin,core.users.update,except:self:user')
->name('api.admin.users.update');
// 메뉴 수정: 소유자는 core.menus.update 권한 없이 수정 가능 (향후 적용 예시)
Route::put('/menus/{menu}', [MenuController::class, 'update'])
->middleware('permission:admin,core.menus.update,except:owner:menu')
->name('api.admin.menus.update');
});상세 문법: middleware.md "permission 미들웨어 except 옵션" 참조
사용자(프론트엔드) 라우트는 permission:user,... 미들웨어와 user 타입 권한 식별자를 함께 사용합니다.
// routes/api.php — 사용자 알림 라우트 예시
Route::middleware('auth:sanctum')->prefix('user')->group(function () {
Route::prefix('notifications')->group(function () {
Route::get('/', [UserNotificationController::class, 'index'])
->middleware('permission:user,core.user-notifications.read')
->name('api.user.notifications.index');
Route::patch('{notification}/read', [UserNotificationController::class, 'markAsRead'])
->middleware('permission:user,core.user-notifications.update')
->name('api.user.notifications.read');
Route::delete('{notification}', [UserNotificationController::class, 'destroy'])
->middleware('permission:user,core.user-notifications.delete')
->name('api.user.notifications.destroy');
});
});⚠️ CRITICAL: 사용자 라우트에 admin 타입 권한 식별자를 사용하면 항상 403 응답
✅ 사용자 컨텍스트 권한은 별도 식별자(예: core.user-notifications.*)로 정의 + permission:user 미들웨어 사용
permissions.identifier 단일 unique 제약 때문에 같은 식별자로 admin/user 권한 두 행을 생성할 수 없습니다. 같은 도메인이라도 컨텍스트가 다르면 식별자를 분리하세요. 상세 규칙: extension/permissions.md
// modules/_bundled/sirsoft-ecommerce/src/routes/api.php
use Modules\Sirsoft\Ecommerce\Controllers\Api\Public\ProductController;
// 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('/{id}', [ProductController::class, 'show'])
->name('public.products.show');
});- 라우트에
name()메서드로 이름 지정 - 적절한 접두사 사용 (api., web., vendor-module.)
- URL 경로 규칙 준수 (/admin/[vendor-module]/[기능명])
- 권한이 필요한 라우트에
permission미들웨어 적용 - 인증이 필요한 라우트에
auth:sanctum미들웨어 적용 - 관리자 라우트에
admin미들웨어 적용 - FormRequest의
authorize()메서드에서 권한 체크하지 않음
- 인증 없이 접근 시 401 반환
- 권한 없이 접근 시 403 반환
- 올바른 권한으로 접근 시 성공
- 컨트롤러 계층 구조 - 컨트롤러 네이밍 규칙
- 미들웨어 등록 규칙 - 미들웨어 실행 순서
- 검증 로직 구현 - FormRequest 사용 규칙
| URL | 메서드 | 라우트명 | 컨트롤러 | 비고 |
|---|---|---|---|---|
| /sitemap.xml | GET | web.sitemap | SitemapController@index | catch-all보다 위에 정의 |
| /api/admin/seo/stats | GET | api.admin.seo.stats | SeoCacheController | 관리자 전용 |
| /api/admin/seo/clear-cache | POST | api.admin.seo.clear-cache | SeoCacheController | 관리자 전용 |
| /api/admin/seo/warmup | POST | api.admin.seo.warmup | SeoCacheController | 관리자 전용 |
| /api/admin/seo/cached-urls | GET | api.admin.seo.cached-urls | SeoCacheController | 관리자 전용 |
상세: seo-system.md