Expand Link app with analytics, settings, and custom domains.
Deploy Ladill Link / deploy (push) Successful in 37s

Add Bitly-style branded domain support via Ladill Domains SSL API,
account analytics dashboard, settings page with default domain picker,
and fix SSO/dashboard issues from QR Plus template leftovers.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-06-27 12:16:34 +00:00
co-authored by Cursor
parent d9c91ad7d8
commit 9516fcb9f3
38 changed files with 1263 additions and 70 deletions
+13 -1
View File
@@ -1,8 +1,11 @@
<?php
use App\Http\Controllers\Auth\SsoLoginController;
use App\Http\Controllers\Link\AnalyticsController;
use App\Http\Controllers\Link\CustomDomainController;
use App\Http\Controllers\Link\LinkController;
use App\Http\Controllers\Link\OverviewController;
use App\Http\Controllers\Link\SettingsController;
use App\Http\Controllers\NotificationController;
use App\Http\Controllers\Public\LinkRedirectController;
use App\Http\Controllers\WalletBalanceController;
@@ -31,6 +34,14 @@ Route::middleware(['auth', 'platform.session'])->group(function () {
Route::post('/notifications/mark-all-read', [NotificationController::class, 'markAllAsRead'])->name('notifications.mark-all-read');
Route::get('/dashboard', [OverviewController::class, 'index'])->name('link.dashboard');
Route::get('/analytics', [AnalyticsController::class, 'index'])->name('link.analytics.index');
Route::get('/domains', [CustomDomainController::class, 'index'])->name('link.domains.index');
Route::post('/domains', [CustomDomainController::class, 'store'])->name('link.domains.store');
Route::post('/domains/{customDomain}/verify', [CustomDomainController::class, 'verify'])->name('link.domains.verify');
Route::post('/domains/{customDomain}/default', [CustomDomainController::class, 'makeDefault'])->name('link.domains.default');
Route::delete('/domains/{customDomain}', [CustomDomainController::class, 'destroy'])->name('link.domains.destroy');
Route::get('/settings', [SettingsController::class, 'index'])->name('link.settings');
Route::put('/settings/default-domain', [SettingsController::class, 'updateDefaultDomain'])->name('link.settings.default-domain');
Route::get('/links', [LinkController::class, 'index'])->name('user.links.index');
Route::get('/links/create', [LinkController::class, 'create'])->name('user.links.create');
Route::post('/links', [LinkController::class, 'store'])->name('user.links.store');
@@ -44,6 +55,7 @@ Route::middleware(['auth', 'platform.session'])->group(function () {
});
// Public short-link resolution — must be last so app routes are not shadowed.
Route::get('/{slug}', [LinkRedirectController::class, 'resolve'])
Route::match(['GET', 'POST', 'PATCH', 'DELETE'], '/{slug}/{path?}', [LinkRedirectController::class, 'resolve'])
->where('slug', '[a-z0-9][a-z0-9-]{1,30}[a-z0-9]')
->where('path', '.*')
->name('link.public.resolve');