Wire admin studio SSR and search infrastructure

This commit is contained in:
2026-05-01 11:46:06 +02:00
parent 257b0dbef6
commit 18cea8b0f0
329 changed files with 197465 additions and 2741 deletions

View File

@@ -28,6 +28,7 @@ Route::middleware(['web', 'throttle:60,1'])->prefix('leaderboard')->name('api.le
Route::get('artworks', [\App\Http\Controllers\Api\LeaderboardController::class, 'artworks'])->name('artworks');
Route::get('groups', [\App\Http\Controllers\Api\LeaderboardController::class, 'groups'])->name('groups');
Route::get('stories', [\App\Http\Controllers\Api\LeaderboardController::class, 'stories'])->name('stories');
Route::get('worlds', [\App\Http\Controllers\Api\LeaderboardController::class, 'worlds'])->name('worlds');
});
Route::middleware(['web', 'auth', 'creator.access'])->prefix('stories')->name('api.stories.')->group(function () {
@@ -49,7 +50,7 @@ Route::middleware(['web', 'auth', 'normalize.username'])->prefix('profile/cover'
// ── Per-artwork signal tracking (public) ────────────────────────────────────
// GET /api/art/{id}/similar → up to 12 similar artworks (Meilisearch)
// POST /api/art/{id}/view → record a view (session-deduped, 5 per 10 min)
// POST /api/art/{id}/view → record a page visit as a view
// POST /api/art/{id}/download → record a download, returns file URL (10/min)
Route::middleware(['web', 'throttle:300,1'])
->get('art/{id}/similar', \App\Http\Controllers\Api\SimilarArtworksController::class)
@@ -61,7 +62,7 @@ Route::middleware(['web', 'throttle:120,1'])
->whereNumber('id')
->name('api.art.similar-ai');
Route::middleware(['web', 'throttle:5,10'])
Route::middleware(['web', 'throttle:120,1'])
->post('art/{id}/view', \App\Http\Controllers\Api\ArtworkViewController::class)
->middleware('forum.bot.protection:api_write')
->whereNumber('id')
@@ -86,6 +87,27 @@ Route::middleware(['web', 'throttle:social-read'])
->where('username', '[A-Za-z0-9_-]{3,20}')
->name('api.profile.activity');
Route::middleware(['web', 'throttle:social-read'])
->get('profile/{username}/journey', \App\Http\Controllers\Api\ProfileJourneyController::class)
->where('username', '[A-Za-z0-9_-]{3,20}')
->name('api.profile.journey');
// Public profile AI biography (read, included in profile payload via journey endpoint)
Route::middleware(['web', 'throttle:social-read'])
->get('profile/{username}/ai-biography', [\App\Http\Controllers\Api\ProfileAiBiographyController::class, 'show'])
->where('username', '[A-Za-z0-9_-]{3,20}')
->name('api.profile.ai-biography');
// Creator-facing AI biography management (authenticated)
Route::middleware(['web', 'auth'])->prefix('creator/profile/ai-biography')->name('api.creator.ai-biography.')->group(function () {
Route::get('/', [\App\Http\Controllers\Api\AiBiographyController::class, 'status'])->name('status');
Route::post('/generate', [\App\Http\Controllers\Api\AiBiographyController::class, 'generate'])->name('generate')->middleware('throttle:5,1');
Route::post('/regenerate', [\App\Http\Controllers\Api\AiBiographyController::class, 'regenerate'])->name('regenerate')->middleware('throttle:5,1');
Route::patch('/', [\App\Http\Controllers\Api\AiBiographyController::class, 'update'])->name('update')->middleware('throttle:20,1');
Route::post('/hide', [\App\Http\Controllers\Api\AiBiographyController::class, 'hide'])->name('hide');
Route::post('/show', [\App\Http\Controllers\Api\AiBiographyController::class, 'show'])->name('show');
});
Route::middleware(['web', 'throttle:social-read'])
->get('comments', [\App\Http\Controllers\Api\SocialCompatibilityController::class, 'comments'])
->name('api.social.comments.index');
@@ -117,6 +139,13 @@ Route::prefix('rank')->name('api.rank.')->middleware(['throttle:60,1'])->group(f
// ── Studio Pro API (authenticated) ─────────────────────────────────────────────
Route::middleware(['web', 'auth'])->prefix('studio')->name('api.studio.')->group(function () {
Route::post('events', [\App\Http\Controllers\Studio\StudioEventsApiController::class, 'store'])->name('events.store');
Route::get('upload-queue', [\App\Http\Controllers\Studio\StudioUploadQueueApiController::class, 'index'])->name('upload-queue.index');
Route::post('upload-queue/batches', [\App\Http\Controllers\Studio\StudioUploadQueueApiController::class, 'store'])->name('upload-queue.store');
Route::post('upload-queue/bulk', [\App\Http\Controllers\Studio\StudioUploadQueueApiController::class, 'bulk'])->name('upload-queue.bulk');
Route::post('upload-queue/items/{id}/fail', [\App\Http\Controllers\Studio\StudioUploadQueueApiController::class, 'markFailed'])->whereNumber('id')->name('upload-queue.items.fail');
Route::post('upload-queue/items/{id}/retry', [\App\Http\Controllers\Studio\StudioUploadQueueApiController::class, 'retry'])->whereNumber('id')->name('upload-queue.items.retry');
Route::post('worlds/media/upload', [\App\Http\Controllers\Studio\StudioWorldMediaApiController::class, 'store'])->middleware(['throttle:20,1', 'forum.bot.protection:api_write'])->name('worlds.media.upload');
Route::delete('worlds/media', [\App\Http\Controllers\Studio\StudioWorldMediaApiController::class, 'destroy'])->middleware(['throttle:20,1', 'forum.bot.protection:api_write'])->name('worlds.media.destroy');
Route::put('preferences', [\App\Http\Controllers\Studio\StudioPreferencesApiController::class, 'updatePreferences'])->name('preferences.settings');
Route::put('preferences/profile', [\App\Http\Controllers\Studio\StudioPreferencesApiController::class, 'updateProfile'])->name('preferences.profile');
Route::put('preferences/featured', [\App\Http\Controllers\Studio\StudioPreferencesApiController::class, 'updateFeatured'])->name('preferences.featured');
@@ -138,6 +167,7 @@ Route::middleware(['web', 'auth'])->prefix('studio')->name('api.studio.')->group
Route::post('artworks/{id}/ai/events', [\App\Http\Controllers\Studio\StudioArtworkAiAssistApiController::class, 'event'])->whereNumber('id')->name('artworks.ai.events');
Route::post('artworks/{id}/ai/regenerate', [\App\Http\Controllers\Studio\StudioArtworkAiAssistApiController::class, 'regenerate'])->whereNumber('id')->name('artworks.ai.regenerate');
Route::post('artworks/{id}/replace-file', [\App\Http\Controllers\Studio\StudioArtworksApiController::class, 'replaceFile'])->whereNumber('id')->name('artworks.replaceFile');
Route::post('artworks/{id}/revise-media', [\App\Http\Controllers\Studio\StudioArtworksApiController::class, 'reviseMedia'])->whereNumber('id')->name('artworks.reviseMedia');
// Versioning
Route::get('artworks/{id}/versions', [\App\Http\Controllers\Studio\StudioArtworksApiController::class, 'versions'])->whereNumber('id')->name('artworks.versions');
Route::post('artworks/{id}/restore/{version_id}', [\App\Http\Controllers\Studio\StudioArtworksApiController::class, 'restoreVersion'])->whereNumber('id')->whereNumber('version_id')->name('artworks.restoreVersion');