middleware('throttle:register'); Route::post('/login', [AuthController::class, 'login'])->middleware('throttle:login'); // Account activation (public) Route::post('/activate', [AuthController::class, 'activateAccount']); Route::post('/resend-activation', [AuthController::class, 'resendActivation']); Route::post('/cancel-registration', [AuthController::class, 'cancelRegistration']); // Plans (public - for pricing page) Route::get('/plans', [PlanController::class, 'index']); Route::get('/plans/{slug}', [PlanController::class, 'show']); // PayPal config (public - needed for frontend SDK) Route::get('/paypal/config', [SubscriptionController::class, 'paypalConfig']); // PayPal webhook (public - called by PayPal) Route::post('/paypal/webhook', [SubscriptionController::class, 'webhook']); // Subscription start for new users (public - used after registration) Route::post('/subscription/start', [SubscriptionController::class, 'startSubscription']); // Subscription confirm for new users (public - called after PayPal redirect) Route::post('/subscription/confirm-public', [SubscriptionController::class, 'confirmPublic']); // Email testing routes (should be protected in production) Route::post('/email/send-test', [EmailTestController::class, 'sendTest']); Route::get('/email/anti-spam-info', [EmailTestController::class, 'getAntiSpamInfo']); // Protected routes (require authentication) Route::middleware('auth:sanctum')->group(function () { // Auth routes Route::post('/logout', [AuthController::class, 'logout']); Route::get('/me', [AuthController::class, 'me']); Route::put('/profile', [AuthController::class, 'updateProfile']); Route::get('/user', function (Request $request) { return $request->user(); }); // ============================================ // Subscriptions (Assinaturas) // ============================================ Route::get('/subscription/status', [SubscriptionController::class, 'status']); Route::post('/subscription/subscribe', [SubscriptionController::class, 'subscribe']); Route::post('/subscription/confirm', [SubscriptionController::class, 'confirm']); Route::post('/subscription/cancel', [SubscriptionController::class, 'cancel']); Route::get('/subscription/invoices', [SubscriptionController::class, 'invoices']); // ============================================ // Contas (Accounts) - Com limite de plano // ============================================ // Rotas específicas ANTES do apiResource Route::post('accounts/recalculate-all', [AccountController::class, 'recalculateBalances']); Route::post('accounts/{id}/recalculate', [AccountController::class, 'recalculateBalance']); Route::post('accounts/{id}/adjust-balance', [AccountController::class, 'adjustBalance']); // Resource principal com middleware de limite no store Route::post('accounts', [AccountController::class, 'store'])->middleware('plan.limits:accounts'); Route::apiResource('accounts', AccountController::class)->except(['store']); Route::get('accounts-total', [AccountController::class, 'totalBalance']); // ============================================ // Centros de Custo (Cost Centers) // ============================================ Route::apiResource('cost-centers', CostCenterController::class); Route::post('cost-centers/{id}/keywords', [CostCenterController::class, 'addKeyword']); Route::delete('cost-centers/{id}/keywords/{keywordId}', [CostCenterController::class, 'removeKeyword']); Route::post('cost-centers/match', [CostCenterController::class, 'matchByText']); // ============================================ // Categorias (Categories) - Com limite de plano // ============================================ // Rotas específicas ANTES do apiResource Route::post('categories/categorize-batch/preview', [CategoryController::class, 'categorizeBatchPreview']); Route::post('categories/categorize-batch', [CategoryController::class, 'categorizeBatch']); Route::post('categories/categorize-batch/manual', [CategoryController::class, 'categorizeBatchManual']); Route::post('categories/match', [CategoryController::class, 'matchByText']); Route::post('categories/reorder', [CategoryController::class, 'reorder']); // Resource principal com middleware de limite no store Route::post('categories', [CategoryController::class, 'store'])->middleware('plan.limits:categories'); Route::apiResource('categories', CategoryController::class)->except(['store']); // Rotas com parâmetros (depois do apiResource) Route::post('categories/{id}/keywords', [CategoryController::class, 'addKeyword']); Route::delete('categories/{id}/keywords/{keywordId}', [CategoryController::class, 'removeKeyword']); // ============================================ // Contas Passivo (Liability Accounts) // ============================================ // Rotas específicas ANTES do apiResource (para evitar conflito com {id}) Route::get('liability-accounts/pending-reconciliation', [LiabilityAccountController::class, 'pendingReconciliation']); Route::get('liability-accounts/template', [LiabilityAccountController::class, 'downloadTemplate']); Route::get('liability-accounts/contract-types', [LiabilityAccountController::class, 'contractTypes']); Route::post('liability-accounts/import', [LiabilityAccountController::class, 'import']); Route::post('liability-accounts/wizard', [LiabilityAccountController::class, 'storeWithWizard']); Route::get('liability-summary', [LiabilityAccountController::class, 'summary']); // Resource principal Route::apiResource('liability-accounts', LiabilityAccountController::class); // Rotas com parâmetros (depois do apiResource) Route::get('liability-accounts/{id}/installments', [LiabilityAccountController::class, 'installments']); Route::put('liability-accounts/{accountId}/installments/{installmentId}', [LiabilityAccountController::class, 'updateInstallment']); // Conciliação de parcelas Route::get('liability-accounts/{accountId}/installments/{installmentId}/eligible-transactions', [LiabilityAccountController::class, 'eligibleTransactions']); Route::post('liability-accounts/{accountId}/installments/{installmentId}/reconcile', [LiabilityAccountController::class, 'reconcile']); Route::delete('liability-accounts/{accountId}/installments/{installmentId}/reconcile', [LiabilityAccountController::class, 'unreconcile']); // ============================================ // Contas Ativo (Asset Accounts) // ============================================ // Rotas específicas ANTES do apiResource Route::get('asset-accounts/asset-types', [AssetAccountController::class, 'assetTypes']); Route::post('asset-accounts/wizard', [AssetAccountController::class, 'storeWithWizard']); Route::get('asset-summary', [AssetAccountController::class, 'summary']); // Resource principal Route::apiResource('asset-accounts', AssetAccountController::class); // Rotas com parâmetros Route::put('asset-accounts/{assetAccount}/value', [AssetAccountController::class, 'updateValue']); Route::post('asset-accounts/{assetAccount}/dispose', [AssetAccountController::class, 'dispose']); // ============================================ // Transações (Transactions) - Com limite de plano // ============================================ Route::post('transactions', [TransactionController::class, 'store'])->middleware('plan.limits:transactions'); Route::apiResource('transactions', TransactionController::class)->except(['store']); Route::get('transactions-by-week', [TransactionController::class, 'byWeek']); Route::get('transactions-summary', [TransactionController::class, 'summary']); // Ações em transações Route::post('transactions/{transaction}/complete', [TransactionController::class, 'complete']); Route::post('transactions/{transaction}/quick-complete', [TransactionController::class, 'quickComplete']); Route::post('transactions/{transaction}/cancel', [TransactionController::class, 'cancel']); Route::post('transactions/{transaction}/revert', [TransactionController::class, 'revert']); Route::post('transactions/{transaction}/duplicate', [TransactionController::class, 'duplicate']); // Divisão de transações Route::post('transactions/{transaction}/split', [TransactionController::class, 'split']); Route::post('transactions/{transaction}/unsplit', [TransactionController::class, 'unsplit']); Route::get('transactions/{transaction}/splits', [TransactionController::class, 'getSplits']); // Transferências entre contas Route::post('transactions/transfer', [TransactionController::class, 'transfer']); Route::post('transactions/{transaction}/unlink-transfer', [TransactionController::class, 'unlinkTransfer']); // Conciliação com Passivos Route::get('transactions/{transaction}/liability-installments', [TransactionController::class, 'findLiabilityInstallments']); Route::post('transactions/{transaction}/reconcile-liability', [TransactionController::class, 'reconcileWithLiability']); // ============================================ // Importação de Extratos (Bank Statement Import) // ============================================ Route::post('import/upload', [ImportController::class, 'upload']); Route::post('import/headers', [ImportController::class, 'getHeaders']); Route::post('import/process', [ImportController::class, 'import']); Route::get('import/mappings', [ImportController::class, 'mappings']); Route::get('import/mappings/{id}', [ImportController::class, 'getMapping']); Route::put('import/mappings/{id}', [ImportController::class, 'updateMapping']); Route::delete('import/mappings/{id}', [ImportController::class, 'deleteMapping']); Route::get('import/presets', [ImportController::class, 'presets']); Route::post('import/presets/create', [ImportController::class, 'createFromPreset']); Route::get('import/history', [ImportController::class, 'history']); Route::get('import/fields', [ImportController::class, 'fields']); // Detecção de Transferências entre Contas (Transfer Detection) // ============================================================ Route::get('transfer-detection', [TransferDetectionController::class, 'index']); Route::get('transfer-detection/stats', [TransferDetectionController::class, 'stats']); Route::get('transfer-detection/{transaction}/pairs', [TransferDetectionController::class, 'findPairs']); Route::post('transfer-detection/confirm', [TransferDetectionController::class, 'confirm']); Route::post('transfer-detection/confirm-batch', [TransferDetectionController::class, 'confirmBatch']); Route::post('transfer-detection/ignore', [TransferDetectionController::class, 'ignore']); Route::post('transfer-detection/delete-both', [TransferDetectionController::class, 'deleteBoth']); // Detecção de Reembolsos (Refund Detection) // ============================================================ Route::get('refund-detection', [TransferDetectionController::class, 'refunds']); Route::post('refund-detection/confirm', [TransferDetectionController::class, 'confirmRefund']); Route::post('refund-detection/confirm-batch', [TransferDetectionController::class, 'confirmRefundBatch']); Route::post('refund-detection/ignore', [TransferDetectionController::class, 'ignoreRefund']); Route::post('refund-detection/undo', [TransferDetectionController::class, 'undoRefund']); // ============================================ // Dashboard // ============================================ Route::get('dashboard/summary', [DashboardController::class, 'summary']); Route::get('dashboard/cashflow', [DashboardController::class, 'cashflow']); Route::get('dashboard/expenses-by-category', [DashboardController::class, 'expensesByCategory']); Route::get('dashboard/income-by-category', [DashboardController::class, 'incomeByCategory']); Route::get('dashboard/payment-variances', [DashboardController::class, 'paymentVariances']); Route::get('dashboard/calendar', [DashboardController::class, 'calendar']); Route::get('dashboard/calendar-day', [DashboardController::class, 'calendarDay']); Route::get('dashboard/upcoming', [DashboardController::class, 'upcomingTransactions']); Route::get('dashboard/overdue', [DashboardController::class, 'overdueTransactions']); // ============================================ // Transações Recorrentes (Recurring Transactions) // ============================================ // Rotas de listagem geral Route::get('recurring/frequencies', [RecurringTemplateController::class, 'frequencies']); Route::get('recurring/pending', [RecurringTemplateController::class, 'allPendingInstances']); Route::get('recurring/overdue', [RecurringTemplateController::class, 'overdueInstances']); Route::get('recurring/due-soon', [RecurringTemplateController::class, 'dueSoonInstances']); Route::post('recurring/regenerate-all', [RecurringTemplateController::class, 'regenerateAll']); // Criar a partir de transação existente Route::post('recurring/from-transaction', [RecurringTemplateController::class, 'createFromTransaction']); // Templates CRUD Route::apiResource('recurring', RecurringTemplateController::class)->parameters(['recurring' => 'recurringTemplate']); // Ações em templates Route::post('recurring/{recurringTemplate}/pause', [RecurringTemplateController::class, 'pause']); Route::post('recurring/{recurringTemplate}/resume', [RecurringTemplateController::class, 'resume']); Route::get('recurring/{recurringTemplate}/instances', [RecurringTemplateController::class, 'instances']); // Ações em instâncias Route::post('recurring-instances/{recurringInstance}/pay', [RecurringTemplateController::class, 'markAsPaid']); Route::post('recurring-instances/{recurringInstance}/reconcile', [RecurringTemplateController::class, 'reconcile']); Route::get('recurring-instances/{recurringInstance}/candidates', [RecurringTemplateController::class, 'findCandidates']); Route::post('recurring-instances/{recurringInstance}/skip', [RecurringTemplateController::class, 'skip']); Route::post('recurring-instances/{recurringInstance}/cancel', [RecurringTemplateController::class, 'cancel']); Route::put('recurring-instances/{recurringInstance}', [RecurringTemplateController::class, 'updateInstance']); // ============================================ // Business - Precificação de Produtos (Admin Only) // ============================================ Route::middleware('admin.only')->group(function () { // User Management (Admin Only) Route::get('admin/users/summary', [UserManagementController::class, 'summary']); Route::get('admin/users', [UserManagementController::class, 'index']); Route::post('admin/users', [UserManagementController::class, 'store']); Route::get('admin/users/{id}', [UserManagementController::class, 'show']); Route::put('admin/users/{id}', [UserManagementController::class, 'update']); Route::post('admin/users/{id}/reset-password', [UserManagementController::class, 'resetPassword']); Route::post('admin/users/{id}/change-plan', [UserManagementController::class, 'changePlan']); Route::delete('admin/users/{id}', [UserManagementController::class, 'destroy']); // Configurações de Negócio (Markup) Route::get('business-settings/default', [BusinessSettingController::class, 'getDefault']); Route::apiResource('business-settings', BusinessSettingController::class); Route::post('business-settings/{id}/recalculate-markup', [BusinessSettingController::class, 'recalculateMarkup']); Route::post('business-settings/{id}/simulate-price', [BusinessSettingController::class, 'simulatePrice']); // Fichas Técnicas de Produtos (CMV) Route::get('product-sheets/categories', [ProductSheetController::class, 'categories']); Route::get('product-sheets/item-types', [ProductSheetController::class, 'itemTypes']); Route::apiResource('product-sheets', ProductSheetController::class); Route::post('product-sheets/{id}/items', [ProductSheetController::class, 'addItem']); Route::put('product-sheets/{sheetId}/items/{itemId}', [ProductSheetController::class, 'updateItem']); Route::delete('product-sheets/{sheetId}/items/{itemId}', [ProductSheetController::class, 'removeItem']); Route::post('product-sheets/{id}/recalculate-price', [ProductSheetController::class, 'recalculatePrice']); Route::post('product-sheets/{id}/duplicate', [ProductSheetController::class, 'duplicate']); // Fichas Técnicas de Serviços (CSV - Custo do Serviço Vendido) Route::get('service-sheets/categories', [ServiceSheetController::class, 'categories']); Route::get('service-sheets/item-types', [ServiceSheetController::class, 'itemTypes']); Route::post('service-sheets/simulate', [ServiceSheetController::class, 'simulate']); Route::apiResource('service-sheets', ServiceSheetController::class); Route::post('service-sheets/{id}/items', [ServiceSheetController::class, 'addItem']); Route::put('service-sheets/{sheetId}/items/{itemId}', [ServiceSheetController::class, 'updateItem']); Route::delete('service-sheets/{sheetId}/items/{itemId}', [ServiceSheetController::class, 'removeItem']); Route::post('service-sheets/{id}/duplicate', [ServiceSheetController::class, 'duplicate']); // Campanhas Promocionais (Black Friday, etc.) Route::get('campaigns/presets', [PromotionalCampaignController::class, 'presets']); Route::post('campaigns/preview', [PromotionalCampaignController::class, 'preview']); Route::apiResource('campaigns', PromotionalCampaignController::class); Route::post('campaigns/{id}/duplicate', [PromotionalCampaignController::class, 'duplicate']); Route::post('campaigns/{id}/products', [PromotionalCampaignController::class, 'addProducts']); Route::delete('campaigns/{id}/products', [PromotionalCampaignController::class, 'removeProducts']); Route::put('campaigns/{campaignId}/products/{productId}', [PromotionalCampaignController::class, 'updateProductDiscount']); }); // End admin.only group // ============================================ // Metas Financieras (Financial Goals) // ============================================ Route::apiResource('financial-goals', FinancialGoalController::class); Route::post('financial-goals/{id}/contributions', [FinancialGoalController::class, 'addContribution']); Route::delete('financial-goals/{goalId}/contributions/{contributionId}', [FinancialGoalController::class, 'removeContribution']); // ============================================ // Presupuestos (Budgets) - Com limite de plano // ============================================ Route::get('budgets/available-categories', [BudgetController::class, 'availableCategories']); Route::get('budgets/year-summary', [BudgetController::class, 'yearSummary']); Route::post('budgets/copy-to-next-month', [BudgetController::class, 'copyToNextMonth']); Route::post('budgets', [BudgetController::class, 'store'])->middleware('plan.limits:budgets'); Route::apiResource('budgets', BudgetController::class)->except(['store']); // ============================================ // Reportes (Reports) // ============================================ Route::prefix('reports')->group(function () { Route::get('summary', [ReportController::class, 'summary']); Route::get('executive-summary', [ReportController::class, 'executiveSummary']); Route::get('by-category', [ReportController::class, 'byCategory']); Route::get('by-cost-center', [ReportController::class, 'byCostCenter']); Route::get('monthly-evolution', [ReportController::class, 'monthlyEvolution']); Route::get('by-day-of-week', [ReportController::class, 'byDayOfWeek']); Route::get('top-expenses', [ReportController::class, 'topExpenses']); Route::get('compare-periods', [ReportController::class, 'comparePeriods']); Route::get('accounts', [ReportController::class, 'accountsReport']); Route::get('projection', [ReportController::class, 'projection']); Route::get('projection-chart', [ReportController::class, 'projectionChart']); Route::get('recurring', [ReportController::class, 'recurringReport']); Route::get('liabilities', [ReportController::class, 'liabilities']); Route::get('future-transactions', [ReportController::class, 'futureTransactions']); Route::get('overdue', [ReportController::class, 'overdueTransactions']); }); // ============================================ // Salud Financiera (Financial Health) // ============================================ Route::get('financial-health', [FinancialHealthController::class, 'index']); Route::get('financial-health/history', [FinancialHealthController::class, 'history']); // ============================================ // Preferências do Usuário (User Preferences) // ============================================ Route::get('preferences', [UserPreferenceController::class, 'index']); Route::put('preferences', [UserPreferenceController::class, 'update']); Route::post('preferences/test-notification', [UserPreferenceController::class, 'testNotification']); // ============================================ // Site Settings (Admin only - Configurações do Site) // ============================================ Route::middleware('admin.only')->prefix('admin/site-settings')->group(function () { Route::get('/', [SiteSettingsController::class, 'index']); Route::get('/cnxifly/status', [SiteSettingsController::class, 'getCnxiflyStatus']); Route::post('/cnxifly/toggle', [SiteSettingsController::class, 'toggleCnxiflyPage']); Route::post('/cnxifly/deploy', [SiteSettingsController::class, 'deployCnxiflyPage']); Route::get('/{key}', [SiteSettingsController::class, 'show']); Route::put('/{key}', [SiteSettingsController::class, 'update']); }); });