group(function () { Route::get('', [DepartmentController::class, 'index'])->name('v1.departments.index'); // 목록 Route::post('', [DepartmentController::class, 'store'])->name('v1.departments.store'); // 생성 Route::get('/tree', [DepartmentController::class, 'tree'])->name('v1.departments.tree'); // 트리 Route::get('/{id}', [DepartmentController::class, 'show'])->name('v1.departments.show'); // 단건 Route::patch('/{id}', [DepartmentController::class, 'update'])->name('v1.departments.update'); // 수정 Route::delete('/{id}', [DepartmentController::class, 'destroy'])->name('v1.departments.destroy'); // 삭제(soft) // 부서-사용자 Route::get('/{id}/users', [DepartmentController::class, 'listUsers'])->name('v1.departments.users.index'); // 부서 사용자 목록 Route::post('/{id}/users', [DepartmentController::class, 'attachUser'])->name('v1.departments.users.attach'); // 사용자 배정(주/부서) Route::delete('/{id}/users/{user}', [DepartmentController::class, 'detachUser'])->name('v1.departments.users.detach'); // 사용자 제거 Route::patch('/{id}/users/{user}/primary', [DepartmentController::class, 'setPrimary'])->name('v1.departments.users.primary'); // 주부서 설정/해제 // 부서-권한 Route::get('/{id}/permissions', [DepartmentController::class, 'listPermissions'])->name('v1.departments.permissions.index'); // 권한 목록 Route::post('/{id}/permissions', [DepartmentController::class, 'upsertPermissions'])->name('v1.departments.permissions.upsert'); // 권한 부여/차단(메뉴별 가능) Route::delete('/{id}/permissions/{permission}', [DepartmentController::class, 'revokePermissions'])->name('v1.departments.permissions.revoke'); // 권한 제거(해당 메뉴 범위까지) }); // Position API (직급/직책 통합 관리) Route::prefix('positions')->group(function () { Route::get('', [PositionController::class, 'index'])->name('v1.positions.index'); Route::post('', [PositionController::class, 'store'])->name('v1.positions.store'); Route::put('/reorder', [PositionController::class, 'reorder'])->name('v1.positions.reorder'); Route::get('/{id}', [PositionController::class, 'show'])->name('v1.positions.show'); Route::put('/{id}', [PositionController::class, 'update'])->name('v1.positions.update'); Route::delete('/{id}', [PositionController::class, 'destroy'])->name('v1.positions.destroy'); }); // Employee API (사원 관리) Route::prefix('employees')->group(function () { Route::get('', [EmployeeController::class, 'index'])->name('v1.employees.index'); Route::post('', [EmployeeController::class, 'store'])->name('v1.employees.store'); Route::get('/stats', [EmployeeController::class, 'stats'])->name('v1.employees.stats'); Route::get('/{id}', [EmployeeController::class, 'show'])->name('v1.employees.show'); Route::patch('/{id}', [EmployeeController::class, 'update'])->name('v1.employees.update'); Route::delete('/{id}', [EmployeeController::class, 'destroy'])->name('v1.employees.destroy'); Route::post('/bulk-delete', [EmployeeController::class, 'bulkDelete'])->name('v1.employees.bulkDelete'); Route::post('/{id}/create-account', [EmployeeController::class, 'createAccount'])->name('v1.employees.createAccount'); Route::post('/{id}/revoke-account', [EmployeeController::class, 'revokeAccount'])->name('v1.employees.revokeAccount'); }); // Attendance API (근태 관리) Route::prefix('attendances')->group(function () { Route::get('', [AttendanceController::class, 'index'])->name('v1.attendances.index'); Route::post('', [AttendanceController::class, 'store'])->name('v1.attendances.store'); Route::get('/monthly-stats', [AttendanceController::class, 'monthlyStats'])->name('v1.attendances.monthlyStats'); Route::get('/export', [AttendanceController::class, 'export'])->name('v1.attendances.export'); Route::post('/check-in', [AttendanceController::class, 'checkIn'])->name('v1.attendances.checkIn'); Route::post('/check-out', [AttendanceController::class, 'checkOut'])->name('v1.attendances.checkOut'); Route::get('/{id}', [AttendanceController::class, 'show'])->name('v1.attendances.show'); Route::patch('/{id}', [AttendanceController::class, 'update'])->name('v1.attendances.update'); Route::delete('/{id}', [AttendanceController::class, 'destroy'])->name('v1.attendances.destroy'); Route::post('/bulk-delete', [AttendanceController::class, 'bulkDelete'])->name('v1.attendances.bulkDelete'); }); // Leave API (휴가 관리) Route::prefix('leaves')->group(function () { Route::get('', [LeaveController::class, 'index'])->name('v1.leaves.index'); Route::post('', [LeaveController::class, 'store'])->name('v1.leaves.store'); Route::get('/balances', [LeaveController::class, 'balances'])->name('v1.leaves.balances'); Route::get('/balance', [LeaveController::class, 'balance'])->name('v1.leaves.balance'); Route::get('/balance/{userId}', [LeaveController::class, 'userBalance'])->name('v1.leaves.userBalance'); Route::put('/balance', [LeaveController::class, 'setBalance'])->name('v1.leaves.setBalance'); Route::get('/grants', [LeaveController::class, 'grants'])->name('v1.leaves.grants'); Route::post('/grants', [LeaveController::class, 'storeGrant'])->name('v1.leaves.grants.store'); Route::delete('/grants/{id}', [LeaveController::class, 'destroyGrant'])->name('v1.leaves.grants.destroy'); Route::get('/{id}', [LeaveController::class, 'show'])->name('v1.leaves.show'); Route::patch('/{id}', [LeaveController::class, 'update'])->name('v1.leaves.update'); Route::delete('/{id}', [LeaveController::class, 'destroy'])->name('v1.leaves.destroy'); Route::post('/{id}/approve', [LeaveController::class, 'approve'])->name('v1.leaves.approve'); Route::post('/{id}/reject', [LeaveController::class, 'reject'])->name('v1.leaves.reject'); Route::post('/{id}/cancel', [LeaveController::class, 'cancel'])->name('v1.leaves.cancel'); }); // Leave Policy API (휴가 정책) Route::get('/leave-policy', [LeavePolicyController::class, 'show'])->name('v1.leave-policy.show'); Route::put('/leave-policy', [LeavePolicyController::class, 'update'])->name('v1.leave-policy.update'); // Approval Form API (결재 양식) Route::prefix('approval-forms')->group(function () { Route::get('', [ApprovalFormController::class, 'index'])->name('v1.approval-forms.index'); Route::post('', [ApprovalFormController::class, 'store'])->name('v1.approval-forms.store'); Route::get('/active', [ApprovalFormController::class, 'active'])->name('v1.approval-forms.active'); Route::get('/{id}', [ApprovalFormController::class, 'show'])->whereNumber('id')->name('v1.approval-forms.show'); Route::patch('/{id}', [ApprovalFormController::class, 'update'])->whereNumber('id')->name('v1.approval-forms.update'); Route::delete('/{id}', [ApprovalFormController::class, 'destroy'])->whereNumber('id')->name('v1.approval-forms.destroy'); }); // Approval Line API (결재선) Route::prefix('approval-lines')->group(function () { Route::get('', [ApprovalLineController::class, 'index'])->name('v1.approval-lines.index'); Route::post('', [ApprovalLineController::class, 'store'])->name('v1.approval-lines.store'); Route::get('/{id}', [ApprovalLineController::class, 'show'])->whereNumber('id')->name('v1.approval-lines.show'); Route::patch('/{id}', [ApprovalLineController::class, 'update'])->whereNumber('id')->name('v1.approval-lines.update'); Route::delete('/{id}', [ApprovalLineController::class, 'destroy'])->whereNumber('id')->name('v1.approval-lines.destroy'); }); // Approval API (전자결재) Route::prefix('approvals')->group(function () { // 기안함 Route::get('/drafts', [ApprovalController::class, 'drafts'])->name('v1.approvals.drafts'); Route::get('/drafts/summary', [ApprovalController::class, 'draftsSummary'])->name('v1.approvals.drafts.summary'); // 결재함 Route::get('/inbox', [ApprovalController::class, 'inbox'])->name('v1.approvals.inbox'); Route::get('/inbox/summary', [ApprovalController::class, 'inboxSummary'])->name('v1.approvals.inbox.summary'); // 참조함 Route::get('/reference', [ApprovalController::class, 'reference'])->name('v1.approvals.reference'); // CRUD Route::post('', [ApprovalController::class, 'store'])->name('v1.approvals.store'); Route::get('/{id}', [ApprovalController::class, 'show'])->whereNumber('id')->name('v1.approvals.show'); Route::patch('/{id}', [ApprovalController::class, 'update'])->whereNumber('id')->name('v1.approvals.update'); Route::delete('/{id}', [ApprovalController::class, 'destroy'])->whereNumber('id')->name('v1.approvals.destroy'); // 액션 Route::post('/{id}/submit', [ApprovalController::class, 'submit'])->whereNumber('id')->name('v1.approvals.submit'); Route::post('/{id}/approve', [ApprovalController::class, 'approve'])->whereNumber('id')->name('v1.approvals.approve'); Route::post('/{id}/reject', [ApprovalController::class, 'reject'])->whereNumber('id')->name('v1.approvals.reject'); Route::post('/{id}/cancel', [ApprovalController::class, 'cancel'])->whereNumber('id')->name('v1.approvals.cancel'); // 참조 열람 Route::post('/{id}/read', [ApprovalController::class, 'markRead'])->whereNumber('id')->name('v1.approvals.read'); Route::post('/{id}/unread', [ApprovalController::class, 'markUnread'])->whereNumber('id')->name('v1.approvals.unread'); }); // Site API (현장 관리) Route::prefix('sites')->group(function () { Route::get('', [SiteController::class, 'index'])->name('v1.sites.index'); Route::post('', [SiteController::class, 'store'])->name('v1.sites.store'); Route::get('/stats', [SiteController::class, 'stats'])->name('v1.sites.stats'); Route::get('/active', [SiteController::class, 'active'])->name('v1.sites.active'); Route::delete('/bulk', [SiteController::class, 'bulkDestroy'])->name('v1.sites.bulk-destroy'); Route::get('/{id}', [SiteController::class, 'show'])->whereNumber('id')->name('v1.sites.show'); Route::put('/{id}', [SiteController::class, 'update'])->whereNumber('id')->name('v1.sites.update'); Route::delete('/{id}', [SiteController::class, 'destroy'])->whereNumber('id')->name('v1.sites.destroy'); }); // Site Briefing API (현장설명회 관리) Route::prefix('site-briefings')->group(function () { Route::get('', [SiteBriefingController::class, 'index'])->name('v1.site-briefings.index'); Route::post('', [SiteBriefingController::class, 'store'])->name('v1.site-briefings.store'); Route::get('/stats', [SiteBriefingController::class, 'stats'])->name('v1.site-briefings.stats'); Route::delete('/bulk', [SiteBriefingController::class, 'bulkDestroy'])->name('v1.site-briefings.bulk-destroy'); Route::get('/{id}', [SiteBriefingController::class, 'show'])->whereNumber('id')->name('v1.site-briefings.show'); Route::put('/{id}', [SiteBriefingController::class, 'update'])->whereNumber('id')->name('v1.site-briefings.update'); Route::delete('/{id}', [SiteBriefingController::class, 'destroy'])->whereNumber('id')->name('v1.site-briefings.destroy'); }); // Construction API (시공관리) Route::prefix('construction')->group(function () { // Contract API (계약관리) Route::prefix('contracts')->group(function () { Route::get('', [ContractController::class, 'index'])->name('v1.construction.contracts.index'); Route::post('', [ContractController::class, 'store'])->name('v1.construction.contracts.store'); Route::get('/stats', [ContractController::class, 'stats'])->name('v1.construction.contracts.stats'); Route::get('/stage-counts', [ContractController::class, 'stageCounts'])->name('v1.construction.contracts.stage-counts'); Route::delete('/bulk', [ContractController::class, 'bulkDestroy'])->name('v1.construction.contracts.bulk-destroy'); Route::post('/from-bidding/{biddingId}', [ContractController::class, 'storeFromBidding'])->whereNumber('biddingId')->name('v1.construction.contracts.store-from-bidding'); Route::get('/{id}', [ContractController::class, 'show'])->whereNumber('id')->name('v1.construction.contracts.show'); Route::put('/{id}', [ContractController::class, 'update'])->whereNumber('id')->name('v1.construction.contracts.update'); Route::delete('/{id}', [ContractController::class, 'destroy'])->whereNumber('id')->name('v1.construction.contracts.destroy'); }); // HandoverReport API (인수인계보고서관리) Route::prefix('handover-reports')->group(function () { Route::get('', [HandoverReportController::class, 'index'])->name('v1.construction.handover-reports.index'); Route::post('', [HandoverReportController::class, 'store'])->name('v1.construction.handover-reports.store'); Route::get('/stats', [HandoverReportController::class, 'stats'])->name('v1.construction.handover-reports.stats'); Route::delete('/bulk', [HandoverReportController::class, 'bulkDestroy'])->name('v1.construction.handover-reports.bulk-destroy'); Route::get('/{id}', [HandoverReportController::class, 'show'])->whereNumber('id')->name('v1.construction.handover-reports.show'); Route::put('/{id}', [HandoverReportController::class, 'update'])->whereNumber('id')->name('v1.construction.handover-reports.update'); Route::delete('/{id}', [HandoverReportController::class, 'destroy'])->whereNumber('id')->name('v1.construction.handover-reports.destroy'); }); // StructureReview API (구조검토관리) Route::prefix('structure-reviews')->group(function () { Route::get('', [StructureReviewController::class, 'index'])->name('v1.construction.structure-reviews.index'); Route::post('', [StructureReviewController::class, 'store'])->name('v1.construction.structure-reviews.store'); Route::get('/stats', [StructureReviewController::class, 'stats'])->name('v1.construction.structure-reviews.stats'); Route::delete('/bulk', [StructureReviewController::class, 'bulkDestroy'])->name('v1.construction.structure-reviews.bulk-destroy'); Route::get('/{id}', [StructureReviewController::class, 'show'])->whereNumber('id')->name('v1.construction.structure-reviews.show'); Route::put('/{id}', [StructureReviewController::class, 'update'])->whereNumber('id')->name('v1.construction.structure-reviews.update'); Route::delete('/{id}', [StructureReviewController::class, 'destroy'])->whereNumber('id')->name('v1.construction.structure-reviews.destroy'); }); });