403Webshell
Server IP : 35.80.110.71  /  Your IP : 216.73.216.221
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux ip-172-31-21-44 6.17.0-1019-aws #19~24.04.1-Ubuntu SMP Tue Jun 23 18:53:06 UTC 2026 x86_64
User : ubuntu ( 1000)
PHP Version : 8.3.31
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/client-portal-laravel/releases/20260626120707/routes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/client-portal-laravel/releases/20260626120707/routes/portal-routes.php
<?php

/**
 * Portal Route Definitions
 *
 * This file contains all portal route definitions.
 * It is included by both:
 * - portal.php (with /portal prefix for legacy URLs)
 * - portal-domain.php (without prefix for portal.scopeforged.com)
 *
 * Middleware should be applied by the including file.
 */

use App\Http\Controllers\Portal\AuditController as PortalAuditController;
use App\Http\Controllers\Portal\AuditDashboardController as PortalAuditDashboardController;
use App\Http\Controllers\Portal\AuditTeamController as PortalAuditTeamController;
use App\Http\Controllers\Portal\ClientUploadController;
use App\Http\Controllers\Portal\ConversationController as PortalConversationController;
use App\Http\Controllers\Portal\DashboardController as PortalDashboardController;
use App\Http\Controllers\Portal\DeliverableApprovalController as PortalDeliverableApprovalController;
use App\Http\Controllers\Portal\DiscoveryController as PortalDiscoveryController;
use App\Http\Controllers\Portal\DocumentRequestController as PortalDocumentRequestController;
use App\Http\Controllers\Portal\FileController as PortalFileController;
use App\Http\Controllers\Portal\InboxController as PortalInboxController;
use App\Http\Controllers\Portal\InvoiceController as PortalInvoiceController;
use App\Http\Controllers\Portal\MeetingController as PortalMeetingController;
use App\Http\Controllers\Portal\MilestoneAcceptanceController;
use App\Http\Controllers\Portal\NotificationPreferenceController;
use App\Http\Controllers\Portal\PaymentController as PortalPaymentController;
use App\Http\Controllers\Portal\PortalSearchController;
use App\Http\Controllers\Portal\ProjectController as PortalProjectController;
use App\Http\Controllers\Portal\ProjectFeedbackController;
use App\Http\Controllers\Portal\ProjectPlanController as PortalProjectPlanController;
use App\Http\Controllers\Portal\ProposalController as PortalProposalController;
use App\Http\Controllers\Portal\SurveyController;
use App\Http\Controllers\Portal\TeamController as PortalTeamController;
use App\Http\Controllers\Portal\UserJobController;
use Illuminate\Support\Facades\Route;

Route::get('/', [PortalDashboardController::class, 'index'])->name('dashboard');

// Global Search (using unique path to avoid conflict with admin search route)
Route::get('portal-search', [PortalSearchController::class, 'search'])->name('search');

// Websites product (plan 270 §Phase 4)
// Plan 272 §B.3 — require.mfa.setup enforces the default-on MFA
// deadline written by WebsiteOnboardingCompletionService.
Route::prefix('websites')->name('websites.')->middleware('require.mfa.setup')->group(function () {
    Route::get('/', [\App\Http\Controllers\Portal\Websites\PortalWebsiteController::class, 'index'])->name('index');
    Route::get('/{website}', [\App\Http\Controllers\Portal\Websites\PortalWebsiteController::class, 'show'])->name('show');
    Route::get('/{website}/billing', [\App\Http\Controllers\Portal\Websites\PortalWebsiteBillingController::class, 'show'])->name('billing.show');
    Route::post('/{website}/billing/portal', [\App\Http\Controllers\Portal\Websites\PortalWebsiteBillingController::class, 'customerPortal'])
        ->middleware('blocked.during.impersonation:change_payment_method')
        ->name('billing.portal');
    Route::get('/{website}/cancel', [\App\Http\Controllers\Portal\Websites\PortalWebsiteController::class, 'showCancel'])->name('cancel.show');
    Route::post('/{website}/cancel', [\App\Http\Controllers\Portal\Websites\PortalWebsiteController::class, 'cancel'])
        ->middleware(['idempotent', 'blocked.during.impersonation:cancel_subscription'])
        ->name('cancel');
    // Plan 279 §A — Singular customer-facing status page + JSON poll.
    Route::get('/{website}/domain', [\App\Http\Controllers\Portal\Websites\PortalDomainController::class, 'singular'])->name('domain');
    Route::get('/{website}/domain/status', [\App\Http\Controllers\Portal\Websites\PortalDomainController::class, 'status'])
        ->middleware(['throttle:60,1', 'throttle.domain:20,1'])
        ->name('domain.status');

    // Plan 279 §B — Add custom domain wizard + manual re-check + restart.
    Route::get('/{website}/domain/add', [\App\Http\Controllers\Portal\Websites\PortalDomainController::class, 'create'])->name('domain.create');
    Route::post('/{website}/domain/add', [\App\Http\Controllers\Portal\Websites\PortalDomainController::class, 'store'])->name('domain.store');
    Route::post('/{website}/domain/{domain}/recheck', [\App\Http\Controllers\Portal\Websites\PortalDomainController::class, 'recheck'])
        ->middleware('throttle:6,1')->name('domain.recheck');
    Route::post('/{website}/domain/{domain}/restart', [\App\Http\Controllers\Portal\Websites\PortalDomainController::class, 'restart'])
        ->middleware('throttle:3,1')->name('domain.restart');

    // Plan 279 §C — Remove with grace + restore-during-grace.
    Route::get('/{website}/domain/{domain}/remove', [\App\Http\Controllers\Portal\Websites\PortalDomainController::class, 'confirmRemove'])->name('domain.remove.show');
    Route::delete('/{website}/domain/{domain}', [\App\Http\Controllers\Portal\Websites\PortalDomainController::class, 'destroy'])->name('domain.destroy');
    Route::get('/{website}/domain/{domain}/restore', [\App\Http\Controllers\Portal\Websites\PortalDomainController::class, 'confirmRestore'])->name('domain.restore.show');
    Route::post('/{website}/domain/{domain}/restore', [\App\Http\Controllers\Portal\Websites\PortalDomainController::class, 'restore'])
        ->middleware('throttle:3,1')->name('domain.restore');

    // Plan 272 §A.1 legacy — preserve plural URLs as 301s so plan-272 tests
    // and bookmarks survive. Inline the redirect rather than the read-only
    // controller because singular is now the canonical surface.
    Route::get('/{website}/domains', function (string $website) {
        return redirect()->route('portal.websites.domain', ['website' => $website], 301);
    })->name('domains.index');
    Route::get('/{website}/domains/{domain}', function (string $website) {
        return redirect()->route('portal.websites.domain', ['website' => $website], 301);
    })->name('domains.show');

    // Plan 272 §A.4 — customer-facing AI opt-out.
    Route::get('/{website}/ai-settings', [\App\Http\Controllers\Portal\Websites\PortalAiSettingsController::class, 'show'])->name('ai-settings.show');
    Route::post('/{website}/ai-settings/opt-out', [\App\Http\Controllers\Portal\Websites\PortalAiSettingsController::class, 'optOut'])->name('ai-settings.opt-out');
    Route::post('/{website}/ai-settings/opt-in', [\App\Http\Controllers\Portal\Websites\PortalAiSettingsController::class, 'optIn'])->name('ai-settings.opt-in');

    // Plan 272 §B.1 — GDPR Article 17 deletion flow.
    Route::get('/{website}/delete-data', [\App\Http\Controllers\Portal\Websites\PortalDataDeletionController::class, 'show'])->name('delete-data.show');
    Route::post('/{website}/delete-data', [\App\Http\Controllers\Portal\Websites\PortalDataDeletionController::class, 'request'])->name('delete-data.request');
    Route::post('/{website}/delete-data/withdraw', [\App\Http\Controllers\Portal\Websites\PortalDataDeletionController::class, 'withdraw'])->name('delete-data.withdraw');

    Route::get('/{website}/data-exports', [\App\Http\Controllers\Portal\Websites\PortalWebsiteDataExportController::class, 'index'])->name('data-exports.index');
    Route::post('/{website}/data-exports', [\App\Http\Controllers\Portal\Websites\PortalWebsiteDataExportController::class, 'request'])
        ->middleware('idempotent')
        ->name('data-exports.request');
});

// Signed download — outside the websites prefix so signed-url verification
// doesn't conflict with the {website} param.
Route::get('/websites-exports/{export}/download', [
    \App\Http\Controllers\Portal\Websites\PortalWebsiteDataExportController::class,
    'download',
])->name('websites.data-exports.download')->middleware('signed');

Route::get('/portal-websites-exports/{export}/download', [
    \App\Http\Controllers\Portal\Websites\PortalWebsiteDataExportController::class,
    'download',
])->name('portal.websites.data-exports.download')->middleware('signed');

// Projects (read-only for clients)
Route::get('projects', [PortalProjectController::class, 'index'])->name('projects.index');
Route::get('projects/{project}', [PortalProjectController::class, 'show'])->name('projects.show');

// Files
Route::post('projects/{project}/files', [PortalFileController::class, 'store'])
    ->name('files.store');
Route::get('files/{file}/download', [PortalFileController::class, 'download'])
    ->name('files.download');
Route::delete('files/{file}', [PortalFileController::class, 'destroy'])
    ->name('files.destroy');

// Invoices (read-only for clients)
Route::get('invoices', [PortalInvoiceController::class, 'index'])->name('invoices.index');
Route::get('invoices/{invoice}', [PortalInvoiceController::class, 'show'])->name('invoices.show');
Route::get('invoices/{invoice}/pdf', [PortalInvoiceController::class, 'pdf'])->name('invoices.pdf');
Route::get('invoices/{invoice}/pdf/download', [PortalInvoiceController::class, 'downloadPdf'])
    ->name('invoices.pdf.download');

// Invoice Payments
Route::post('invoices/{invoice}/pay', [PortalPaymentController::class, 'checkout'])
    ->name('invoices.payment.checkout');
Route::get('invoices/{invoice}/payment/success', [PortalPaymentController::class, 'success'])
    ->name('invoices.payment.success');

// Conversations (legacy — 278-D 302-redirects to /inbox after R4 cutover)
Route::get('conversations', [PortalConversationController::class, 'index'])->name('conversations.index');
Route::get('conversations/create', [PortalConversationController::class, 'create'])->name('conversations.create');
Route::post('conversations', [PortalConversationController::class, 'store'])->name('conversations.store');
Route::get('conversations/{conversation}', [PortalConversationController::class, 'show'])->name('conversations.show');
Route::post('conversations/{conversation}/messages', [PortalConversationController::class, 'sendMessage'])->name('conversations.messages.store');
Route::get('projects/{project}/conversations', [PortalConversationController::class, 'projectConversations'])->name('projects.conversations.index');
Route::post('projects/{project}/conversations', [PortalConversationController::class, 'startProjectConversation'])->name('projects.conversations.store');

// Plan 278-D — Inbox (new email-client-style surface)
Route::get('inbox', [PortalInboxController::class, 'index'])->name('inbox.index');
Route::get('inbox/conversation/{conversation}', [PortalInboxController::class, 'show'])->name('inbox.show');
Route::post('inbox/conversation/{conversation}/messages', [PortalInboxController::class, 'sendMessage'])->name('inbox.send');
Route::get('inbox/poll', [PortalInboxController::class, 'poll'])
    ->middleware('throttle:60,1')
    ->name('inbox.poll');

// Plan 278-E — Reference attachments + Discuss-this entrypoint.
Route::post('inbox/start-with-reference', [PortalInboxController::class, 'startWithReference'])
    ->name('inbox.start-with-reference');
Route::get('inbox/referenceable-search', [PortalInboxController::class, 'referenceableSearch'])
    ->middleware('throttle:reference-search')
    ->name('inbox.referenceable-search');

// Project Plans
Route::get('projects/{project}/plans', [PortalProjectPlanController::class, 'index'])->name('projects.plans.index');
Route::get('plans/{plan}', [PortalProjectPlanController::class, 'show'])->name('plans.show');
Route::post('plans/{plan}/approve', [PortalProjectPlanController::class, 'approve'])->name('plans.approve');
Route::post('plans/{plan}/request-changes', [PortalProjectPlanController::class, 'requestChanges'])->name('plans.request-changes');
Route::get('plans/{plan}/pdf', [PortalProjectPlanController::class, 'downloadPdf'])->name('plans.pdf');

// Amendments
Route::get('amendments/{amendment}', [PortalProjectPlanController::class, 'showAmendment'])->name('amendments.show');
Route::post('amendments/{amendment}/sign', [PortalProjectPlanController::class, 'signAmendment'])->name('amendments.sign');

// ===========================================
// Client Collaboration Features (Plan 036)
// ===========================================

// Document Requests
Route::prefix('document-requests')->name('document-requests.')->group(function () {
    Route::get('/', [PortalDocumentRequestController::class, 'index'])->name('index');
    Route::get('/{documentRequest}', [PortalDocumentRequestController::class, 'show'])->name('show');
    Route::post('/{documentRequest}/submit', [PortalDocumentRequestController::class, 'submit'])->name('submit');
    Route::get('/{documentRequest}/files/{fileId}/download', [PortalDocumentRequestController::class, 'downloadFile'])->name('files.download');
});

// Deliverable Approvals
Route::prefix('deliverables')->name('deliverables.')->group(function () {
    Route::get('/', [PortalDeliverableApprovalController::class, 'index'])->name('index');
    Route::get('/{approval}', [PortalDeliverableApprovalController::class, 'show'])->name('show');
    Route::post('/{approval}/approve', [PortalDeliverableApprovalController::class, 'approve'])->name('approve');
    Route::post('/{approval}/reject', [PortalDeliverableApprovalController::class, 'reject'])->name('reject');
    Route::post('/{approval}/revision', [PortalDeliverableApprovalController::class, 'requestRevision'])->name('revision');
});

// Project-specific deliverables
Route::get('projects/{project}/deliverables', [PortalDeliverableApprovalController::class, 'projectApprovals'])->name('projects.deliverables');

// Client Uploads
Route::prefix('uploads')->name('uploads.')->group(function () {
    Route::get('/', [ClientUploadController::class, 'index'])->name('index');
    Route::post('/', [ClientUploadController::class, 'store'])->name('store');
    Route::get('/{upload}/download', [ClientUploadController::class, 'download'])->name('download');
    Route::delete('/{upload}', [ClientUploadController::class, 'destroy'])->name('destroy');
});

// Milestone Acceptance
Route::get('projects/{project}/milestones/{milestone}/acceptance', [MilestoneAcceptanceController::class, 'show'])->name('projects.milestones.acceptance');
Route::post('projects/{project}/milestones/{milestone}/accept', [MilestoneAcceptanceController::class, 'accept'])->name('projects.milestones.accept');
Route::post('projects/{project}/milestones/{milestone}/reject', [MilestoneAcceptanceController::class, 'reject'])->name('projects.milestones.reject');

// Project Feedback
Route::get('projects/{project}/feedback', [ProjectFeedbackController::class, 'index'])->name('projects.feedback.index');
Route::post('projects/{project}/feedback', [ProjectFeedbackController::class, 'store'])->name('projects.feedback.store');
Route::get('projects/{project}/feedback/{feedback}', [ProjectFeedbackController::class, 'show'])->name('projects.feedback.show');

// Satisfaction Surveys
Route::prefix('surveys')->name('surveys.')->group(function () {
    Route::get('/create', [SurveyController::class, 'create'])->name('create');
    Route::post('/', [SurveyController::class, 'store'])->name('store');
    Route::get('/projects/{project}', [SurveyController::class, 'projectSurvey'])->name('project');
});

// Notification Preferences
Route::prefix('settings')->name('settings.')->group(function () {
    Route::get('/notifications', [NotificationPreferenceController::class, 'edit'])->name('notifications');
    Route::put('/notifications', [NotificationPreferenceController::class, 'update'])->name('notifications.update');
    Route::post('/notifications/reset', [NotificationPreferenceController::class, 'reset'])->name('notifications.reset');
});

// User Jobs (Background Job Status)
Route::prefix('jobs')->name('jobs.')->group(function () {
    Route::get('/', [UserJobController::class, 'index'])->name('index');
    Route::get('/pending', [UserJobController::class, 'pending'])->name('pending');
    Route::get('/widget', [UserJobController::class, 'widget'])->name('widget');
    Route::get('/impact', [UserJobController::class, 'impact'])->name('impact');
    Route::get('/impact/data', [UserJobController::class, 'impactData'])->name('impact.data');
    Route::get('/{job}', [UserJobController::class, 'show'])->name('show');
    Route::get('/{job}/impact', [UserJobController::class, 'jobImpact'])->name('job-impact');
    Route::post('/{job}/acknowledge', [UserJobController::class, 'acknowledge'])->name('acknowledge');
});

// ===========================================
// Discovery Flow (Plan 117)
// ===========================================

Route::prefix('discovery')->name('discovery.')->group(function () {
    Route::get('/', [PortalDiscoveryController::class, 'index'])->name('index');
    Route::get('/questionnaire', [PortalDiscoveryController::class, 'questionnaire'])->name('questionnaire');
    Route::post('/questionnaire/save', [PortalDiscoveryController::class, 'saveProgress'])->name('save-progress');
    Route::post('/questionnaire/submit', [PortalDiscoveryController::class, 'submit'])->name('submit');
    Route::get('/status', [PortalDiscoveryController::class, 'status'])->name('status');
    Route::get('/book-call', [PortalDiscoveryController::class, 'bookCall'])->name('book-call');
    Route::post('/book-call', [PortalDiscoveryController::class, 'confirmBooking'])->name('confirm-booking');
    Route::get('/available-slots', [PortalDiscoveryController::class, 'getAvailableSlots'])->name('available-slots');
});

// ===========================================
// Client Meeting Management (Plan 151)
// ===========================================

Route::prefix('meetings')->name('meetings.')->group(function () {
    Route::get('/', [PortalMeetingController::class, 'index'])->name('index');
    Route::get('/schedule', [PortalMeetingController::class, 'schedule'])->name('schedule');
    Route::post('/schedule', [PortalMeetingController::class, 'confirmSchedule'])->name('confirm-schedule');
    Route::get('/{meeting}', [PortalMeetingController::class, 'show'])->name('show');
    Route::get('/{meeting}/reschedule', [PortalMeetingController::class, 'reschedule'])->name('reschedule');
    Route::post('/{meeting}/reschedule', [PortalMeetingController::class, 'confirmReschedule'])->name('confirm-reschedule');
    Route::post('/{meeting}/cancel', [PortalMeetingController::class, 'cancel'])->name('cancel');
});

// ===========================================
// Proposals (Plan 151)
// ===========================================

Route::prefix('proposals')->name('proposals.')->group(function () {
    Route::get('/', [PortalProposalController::class, 'index'])->name('index');
    Route::get('/{proposal}', [PortalProposalController::class, 'show'])->name('show');
    Route::post('/{proposal}/comment', [PortalProposalController::class, 'addComment'])->name('comment');
    Route::post('/{proposal}/approve', [PortalProposalController::class, 'approve'])->name('approve');
    Route::post('/{proposal}/reject', [PortalProposalController::class, 'reject'])->name('reject');
});

// ===========================================
// Audits (Plan 208)
// ===========================================

Route::prefix('audits')->name('audits.')->group(function () {
    Route::get('/', [PortalAuditController::class, 'index'])->name('index');
    Route::get('/overview', [PortalAuditDashboardController::class, 'index'])->name('overview');

    // Trends report (Phase 7.4) - before audit ID routes
    Route::get('/trends', [PortalAuditController::class, 'trends'])->name('trends');
    Route::get('/trends/data', [PortalAuditController::class, 'getTrendsData'])->name('trends.data');
    Route::get('/compare', [PortalAuditController::class, 'compareAudits'])->name('compare');

    // History & Analysis (Phase 8) - before audit ID routes
    Route::get('/history', [PortalAuditController::class, 'history'])->name('history');
    Route::get('/history/data', [PortalAuditController::class, 'getHistoryData'])->name('history.data');
    Route::get('/improvement', [PortalAuditController::class, 'improvementAnalysis'])->name('improvement');
    Route::get('/recurring-issues', [PortalAuditController::class, 'recurringIssues'])->name('recurring-issues');
    Route::get('/{audit}', [PortalAuditController::class, 'show'])->name('show');
    Route::get('/{audit}/dashboard', [PortalAuditController::class, 'dashboard'])->name('dashboard');
    Route::get('/{audit}/remediation', [PortalAuditController::class, 'remediationTracker'])->name('remediation');
    Route::get('/{audit}/score-impact', [PortalAuditController::class, 'getScoreImpact'])->name('score-impact');

    // Finding actions
    Route::post('/{audit}/findings/{finding}/comment', [PortalAuditController::class, 'addComment'])->name('findings.comment');
    Route::post('/{audit}/findings/{finding}/resolve', [PortalAuditController::class, 'markResolved'])->name('findings.resolve');
    Route::patch('/{audit}/findings/{finding}/remediation', [PortalAuditController::class, 'updateRemediation'])->name('findings.remediation');
    Route::patch('/{audit}/findings/{finding}/status', [PortalAuditController::class, 'updateClientStatus'])->name('findings.status');
    Route::post('/{audit}/findings/{finding}/verify', [PortalAuditController::class, 'requestVerification'])->name('findings.verify');
    Route::post('/{audit}/findings/{finding}/dispute', [PortalAuditController::class, 'createDispute'])->name('findings.dispute');
    Route::post('/{audit}/findings/{finding}/track-view', [PortalAuditController::class, 'trackFindingView'])->name('findings.track-view');

    // Threaded comments (Phase 6.1)
    Route::get('/{audit}/findings/{finding}/comments', [PortalAuditController::class, 'getComments'])->name('findings.comments');
    Route::post('/{audit}/findings/{finding}/comments/{comment}/resolve', [PortalAuditController::class, 'resolveThread'])->name('findings.comments.resolve');
    Route::post('/{audit}/findings/{finding}/comments/{comment}/reopen', [PortalAuditController::class, 'reopenThread'])->name('findings.comments.reopen');

    // Clarification requests (Phase 6.3)
    Route::post('/{audit}/findings/{finding}/clarify', [PortalAuditController::class, 'requestClarification'])->name('findings.clarify');
    Route::get('/{audit}/pending-clarifications', [PortalAuditController::class, 'getPendingClarifications'])->name('pending-clarifications');

    // Executive summary (Phase 7.1)
    Route::get('/{audit}/executive-summary', [PortalAuditController::class, 'executiveSummary'])->name('executive-summary');
    Route::get('/{audit}/executive-summary/data', [PortalAuditController::class, 'getExecutiveSummaryData'])->name('executive-summary.data');

    // Export (Phase 7.3)
    Route::get('/{audit}/export', [PortalAuditController::class, 'export'])->name('export');

    // Evidence management
    Route::post('/{audit}/findings/{finding}/evidence', [PortalAuditController::class, 'uploadEvidence'])->name('findings.evidence.upload');
    Route::delete('/{audit}/findings/{finding}/evidence/{evidence}', [PortalAuditController::class, 'deleteEvidence'])->name('findings.evidence.delete');
    Route::get('/{audit}/findings/{finding}/history', [PortalAuditController::class, 'getStatusHistory'])->name('findings.history');

    // Assignment management (Phase 5.2)
    Route::get('/{audit}/team-members', [PortalAuditController::class, 'getTeamMembers'])->name('team-members');
    Route::post('/{audit}/findings/{finding}/assign', [PortalAuditController::class, 'assignFinding'])->name('findings.assign');
    Route::post('/{audit}/bulk-assign', [PortalAuditController::class, 'bulkAssign'])->name('bulk-assign');
    Route::get('/{audit}/assignment-stats', [PortalAuditController::class, 'getAssignmentStats'])->name('assignment-stats');

    // Team progress (Phase 5.3)
    Route::get('/{audit}/team-progress', [PortalAuditTeamController::class, 'teamProgress'])->name('team-progress');
    Route::get('/{audit}/team-activity', [PortalAuditTeamController::class, 'getActivity'])->name('team-activity');
    Route::post('/{audit}/team/{member}/send-reminder', [PortalAuditTeamController::class, 'sendReminder'])->name('team.send-reminder');
    Route::get('/{audit}/team/{member}/findings', [PortalAuditTeamController::class, 'getMemberFindings'])->name('team.member-findings');

    // Share findings (Phase 5.4)
    Route::post('/{audit}/findings/{finding}/share', [PortalAuditController::class, 'shareFinding'])->name('findings.share');
    Route::get('/{audit}/findings/{finding}/share-links', [PortalAuditController::class, 'getFindingShareLinks'])->name('findings.share-links');
    Route::delete('/{audit}/findings/{finding}/share-links/{link}', [PortalAuditController::class, 'deactivateShareLink'])->name('findings.share-links.deactivate');
});

// ===========================================
// Team Management (Plan 212-E Phase 5)
// ===========================================

// Redirect to team page for user's primary client
Route::get('team', [PortalTeamController::class, 'redirectToTeam'])->name('team');

Route::prefix('team/{client}')->name('team.')->group(function () {
    Route::get('/', [PortalTeamController::class, 'index'])->name('index');
    Route::post('/invite', [PortalTeamController::class, 'invite'])->name('invite');
    Route::post('/invitations/{invitation}/resend', [PortalTeamController::class, 'resendInvitation'])->name('resend-invitation');
    Route::delete('/invitations/{invitation}', [PortalTeamController::class, 'cancelInvitation'])->name('cancel-invitation');
    Route::patch('/members/{member}', [PortalTeamController::class, 'updateMember'])->name('update-member');
    Route::delete('/members/{member}', [PortalTeamController::class, 'removeMember'])->name('remove-member');
});

Youez - 2016 - github.com/yon3zu
LinuXploit