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

@@ -386,6 +386,7 @@ final class PersonalizedFeedService
->with([
'user:id,name,username',
'user.profile:user_id,avatar_hash',
'group:id,name,slug,headline,avatar_path,followers_count',
'categories:id,name,slug,content_type_id,parent_id,sort_order',
'categories.contentType:id,name,slug',
'tags:id,name,slug',
@@ -407,6 +408,8 @@ final class PersonalizedFeedService
$primaryCategory = $artwork->categories->sortBy('sort_order')->first();
$primaryTag = $artwork->tags->sortBy('name')->first();
$source = (string) ($item['source'] ?? 'mixed');
$publisher = $this->mapPublisherPayload($artwork);
$isGroupPublisher = ($publisher['type'] ?? null) === 'group';
$responseItems[] = [
'id' => $artwork->id,
@@ -414,14 +417,18 @@ final class PersonalizedFeedService
'title' => $artwork->title,
'thumbnail_url' => $artwork->thumb_url,
'thumbnail_srcset' => $artwork->thumb_srcset,
'author' => $artwork->user?->name,
'username' => $artwork->user?->username,
'author' => $isGroupPublisher ? ($publisher['name'] ?? 'Skinbase Group') : $artwork->user?->name,
'username' => $isGroupPublisher ? null : $artwork->user?->username,
'author_id' => $artwork->user?->id,
'avatar_url' => AvatarUrl::forUser(
(int) ($artwork->user?->id ?? 0),
$artwork->user?->profile?->avatar_hash,
64
),
'avatar_url' => $isGroupPublisher
? ($publisher['avatar_url'] ?? null)
: AvatarUrl::forUser(
(int) ($artwork->user?->id ?? 0),
$artwork->user?->profile?->avatar_hash,
64
),
'published_as_type' => $artwork->publishedAsType(),
'publisher' => $publisher,
'content_type_name' => $primaryCategory?->contentType?->name ?? '',
'content_type_slug' => $primaryCategory?->contentType?->slug ?? '',
'category_name' => $primaryCategory?->name ?? '',
@@ -490,6 +497,32 @@ final class PersonalizedFeedService
};
}
/**
* @return array<string, mixed>|null
*/
private function mapPublisherPayload(Artwork $artwork): ?array
{
if ($artwork->publishedAsType() !== Artwork::PUBLISHED_AS_GROUP) {
return null;
}
$group = $artwork->group;
if (! $group) {
return null;
}
return [
'id' => (int) $group->id,
'type' => 'group',
'name' => (string) $group->name,
'slug' => (string) $group->slug,
'headline' => (string) ($group->headline ?? ''),
'avatar_url' => $group->avatarUrl(),
'profile_url' => $group->publicUrl(),
'followers_count' => (int) ($group->followers_count ?? 0),
];
}
private function resolveAlgoVersion(?string $algoVersion = null, ?int $userId = null): string
{
if ($algoVersion !== null && $algoVersion !== '') {

View File

@@ -958,6 +958,7 @@ final class RecommendationServiceV2
->with([
'user:id,name,username',
'user.profile:user_id,avatar_hash',
'group:id,name,slug,headline,avatar_path,followers_count',
'categories:id,name,slug,content_type_id,parent_id,sort_order',
'categories.contentType:id,name,slug',
'tags:id,name,slug',
@@ -991,20 +992,26 @@ final class RecommendationServiceV2
$rankingSignals = (array) ($item['ranking_signals'] ?? []);
$rankingSignals['local_embedding_present'] = $hasLocalEmbedding;
$rankingSignals['vector_indexed_at'] = $vectorIndexedAt;
$publisher = $this->mapPublisherPayload($artwork);
$isGroupPublisher = ($publisher['type'] ?? null) === 'group';
$responseItems[] = [
'id' => $artwork->id,
'slug' => $artwork->slug,
'title' => $artwork->title,
'thumbnail_url' => $artwork->thumb_url,
'thumbnail_srcset' => $artwork->thumb_srcset,
'author' => $artwork->user?->name,
'username' => $artwork->user?->username,
'author' => $isGroupPublisher ? ($publisher['name'] ?? 'Skinbase Group') : $artwork->user?->name,
'username' => $isGroupPublisher ? null : $artwork->user?->username,
'author_id' => $artwork->user?->id,
'avatar_url' => AvatarUrl::forUser(
(int) ($artwork->user?->id ?? 0),
$artwork->user?->profile?->avatar_hash,
64
),
'avatar_url' => $isGroupPublisher
? ($publisher['avatar_url'] ?? null)
: AvatarUrl::forUser(
(int) ($artwork->user?->id ?? 0),
$artwork->user?->profile?->avatar_hash,
64
),
'published_as_type' => $artwork->publishedAsType(),
'publisher' => $publisher,
'content_type_name' => $primaryCategory?->contentType?->name ?? '',
'content_type_slug' => $primaryCategory?->contentType?->slug ?? '',
'category_name' => $primaryCategory?->name ?? '',
@@ -1323,6 +1330,32 @@ final class RecommendationServiceV2
return $typed;
}
/**
* @return array<string, mixed>|null
*/
private function mapPublisherPayload(Artwork $artwork): ?array
{
if ($artwork->publishedAsType() !== Artwork::PUBLISHED_AS_GROUP) {
return null;
}
$group = $artwork->group;
if (! $group) {
return null;
}
return [
'id' => (int) $group->id,
'type' => 'group',
'name' => (string) $group->name,
'slug' => (string) $group->slug,
'headline' => (string) ($group->headline ?? ''),
'avatar_url' => $group->avatarUrl(),
'profile_url' => $group->publicUrl(),
'followers_count' => (int) ($group->followers_count ?? 0),
];
}
private function v3Enabled(): bool
{
return (bool) config('discovery.v3.enabled', false);