feat: ship creator journey v2 and profile updates

This commit is contained in:
2026-04-12 21:42:07 +02:00
parent a2457f4e49
commit d5cff21ea2
335 changed files with 20147 additions and 1545 deletions

View File

@@ -9,10 +9,12 @@ use App\Services\ArtworkSearchService;
use App\Services\ArtworkService;
use App\Services\EarlyGrowth\AdaptiveTimeWindow;
use App\Services\EarlyGrowth\GridFiller;
use App\Services\Maturity\ArtworkMaturityService;
use App\Services\Recommendations\RecommendationFeedResolver;
use App\Services\UserSuggestionService;
use App\Services\ThumbnailPresenter;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
@@ -38,6 +40,7 @@ final class DiscoverController extends Controller
private readonly GridFiller $gridFiller,
private readonly CommunityActivityService $communityActivity,
private readonly UserSuggestionService $userSuggestions,
private readonly ArtworkMaturityService $maturity,
) {}
// ─── /discover/trending ──────────────────────────────────────────────────
@@ -178,6 +181,7 @@ final class DiscoverController extends Controller
->whereRaw('MONTH(published_at) = ?', [$today->month])
->whereRaw('DAY(published_at) = ?', [$today->day])
->whereRaw('YEAR(published_at) < ?', [$today->year])
->orderMissingThumbnailsLast()
->orderByDesc('published_at')
->paginate($perPage)
->withQueryString();
@@ -270,7 +274,8 @@ final class DiscoverController extends Controller
$artworks = collect($feedResult['data'] ?? [])->map(
fn (array $item) => $this->presentRecommendedArtwork($item)
)->values();
);
$artworks = $this->reorderDiscoverItemsByThumbnailHealth($artworks)->values();
$meta = $feedResult['meta'] ?? [];
$nextCursor = $meta['next_cursor'] ?? null;
@@ -345,6 +350,7 @@ final class DiscoverController extends Controller
->published()
->with(['user:id,name,username', 'categories:id,name,slug,content_type_id,parent_id,sort_order'])
->whereIn('user_id', $followingIds)
->orderMissingThumbnailsLast()
->orderByDesc('published_at')
->paginate($perPage)
->withQueryString();
@@ -416,6 +422,7 @@ final class DiscoverController extends Controller
'categories:id,name,slug,content_type_id,parent_id,sort_order',
'categories.contentType:id,slug,name',
])
->orderMissingThumbnailsLast()
->orderByDesc('published_at')
->orderByDesc('id')
->paginate($perPage)
@@ -438,6 +445,7 @@ final class DiscoverController extends Controller
->leftJoin('artwork_stats as discover_stats', 'discover_stats.artwork_id', '=', 'artworks.id')
->select('artworks.*')
->where('artworks.published_at', '>=', $cutoff)
->orderMissingThumbnailsLast()
->orderByDesc('discover_stats.ranking_score')
->orderByDesc('discover_stats.engagement_velocity')
->orderByDesc('discover_stats.views')
@@ -465,6 +473,7 @@ final class DiscoverController extends Controller
->selectRaw('COALESCE(discover_stats.heat_score, 0) as heat_score')
->selectRaw('COALESCE(discover_stats.engagement_velocity, 0) as engagement_velocity')
->where('artworks.published_at', '>=', $cutoff)
->orderMissingThumbnailsLast()
->orderByDesc('discover_stats.heat_score')
->orderByDesc('discover_stats.engagement_velocity')
->orderByDesc('artworks.published_at')
@@ -496,6 +505,7 @@ final class DiscoverController extends Controller
->selectRaw('COALESCE(discover_stats.engagement_velocity, 0) as engagement_velocity')
->selectRaw('COALESCE(recent_rising_activity.recent_signal_24h, 0) as recent_signal_24h')
->where('artworks.published_at', '>=', $cutoff)
->orderMissingThumbnailsLast()
->orderByDesc('recent_signal_24h')
->orderByDesc('artworks.published_at')
->orderByDesc('artworks.id')
@@ -599,7 +609,7 @@ final class DiscoverController extends Controller
$username = $isGroupPublisher ? '' : ($artwork->user?->username ?? '');
$profileUrl = $isGroupPublisher ? $group->publicUrl() : ($username !== '' ? '/@' . $username : null);
return (object) [
return (object) $this->maturity->decoratePayload([
'id' => $artwork->id,
'name' => $artwork->title,
'content_type_name' => $primaryCategory?->contentType?->name ?? '',
@@ -624,7 +634,7 @@ final class DiscoverController extends Controller
'published_at' => $artwork->published_at,
'width' => $artwork->width ?? null,
'height' => $artwork->height ?? null,
];
], $artwork, request()->user());
}
/**
@@ -676,6 +686,7 @@ final class DiscoverController extends Controller
->whereIn('user_id', $followingIds)
->where('published_at', '>=', now()->subDays(30))
->leftJoin('artwork_stats as ast', 'ast.artwork_id', '=', 'artworks.id')
->orderMissingThumbnailsLast()
->orderByDesc(DB::raw('COALESCE(ast.heat_score, 0)'))
->orderByDesc(DB::raw('COALESCE(ast.favorites, 0)'))
->orderByDesc('artworks.published_at')
@@ -703,4 +714,42 @@ final class DiscoverController extends Controller
->values()
->all();
}
/**
* @param Collection<int, object> $items
* @return Collection<int, object>
*/
private function reorderDiscoverItemsByThumbnailHealth(Collection $items): Collection
{
if ($items->isEmpty()) {
return $items;
}
$ids = $items
->pluck('id')
->filter(fn ($id) => is_numeric($id) && (int) $id > 0)
->map(fn ($id) => (int) $id)
->values();
if ($ids->isEmpty()) {
return $items;
}
$missingIds = Artwork::query()
->whereIn('id', $ids)
->where('has_missing_thumbnails', true)
->pluck('id')
->map(fn ($id) => (int) $id)
->flip();
if ($missingIds->isEmpty()) {
return $items;
}
$healthy = $items->reject(fn ($item) => $missingIds->has((int) ($item->id ?? 0)));
return $healthy
->concat($items->filter(fn ($item) => $missingIds->has((int) ($item->id ?? 0))))
->values();
}
}