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

@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace App\Jobs;
use App\Models\Artwork;
use App\Services\Maturity\ArtworkMaturityService;
use App\Services\Vision\VisionService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
final class DetectArtworkMaturityJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
public int $tries = 3;
public int $timeout = 20;
public function __construct(
private readonly int $artworkId,
private readonly string $hash,
) {
$queue = (string) config('maturity.ai.queue', config('vision.queue', 'default'));
if ($queue !== '') {
$this->onQueue($queue);
}
}
public function backoff(): array
{
return [5, 30, 120];
}
public function handle(VisionService $vision, ArtworkMaturityService $maturity): void
{
if (! $vision->isEnabled()) {
return;
}
$artwork = Artwork::query()->with(['categories.contentType'])->find($this->artworkId);
if (! $artwork) {
return;
}
$detailed = $vision->analyzeArtworkMaturityDetailed($artwork, $this->hash);
$assessment = (array) ($detailed['assessment'] ?? []);
if ($assessment === []) {
$assessment = [
'status' => ArtworkMaturityService::AI_STATUS_FAILED,
'advisory' => 'Vision maturity analysis returned no assessment payload.',
];
}
$maturity->applyAiAssessment($artwork->fresh(), $assessment);
}
public function failed(\Throwable $exception): void
{
$artwork = Artwork::query()->find($this->artworkId);
if ($artwork) {
app(ArtworkMaturityService::class)->applyAiAssessment($artwork, [
'status' => ArtworkMaturityService::AI_STATUS_FAILED,
'advisory' => $exception->getMessage(),
]);
}
Log::warning('DetectArtworkMaturityJob failed', [
'artwork_id' => $this->artworkId,
'hash' => $this->hash,
'error' => $exception->getMessage(),
]);
}
}

View File

@@ -7,6 +7,7 @@ namespace App\Jobs;
use App\Services\Uploads\UploadPipelineService;
use App\Jobs\AnalyzeArtworkAiAssistJob;
use App\Jobs\AutoTagArtworkJob;
use App\Jobs\DetectArtworkMaturityJob;
use App\Jobs\GenerateArtworkEmbeddingJob;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
@@ -48,6 +49,7 @@ final class GenerateDerivativesJob implements ShouldQueue
// Auto-tagging is async and must never block publish.
AutoTagArtworkJob::dispatch($this->artworkId, $this->hash)->afterCommit();
DetectArtworkMaturityJob::dispatch($this->artworkId, $this->hash)->afterCommit();
GenerateArtworkEmbeddingJob::dispatch($this->artworkId, $this->hash)->afterCommit();
AnalyzeArtworkAiAssistJob::dispatch($this->artworkId)->afterCommit();
}

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace App\Jobs;
use App\Services\Profile\CreatorJourneyService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class RebuildCreatorJourneyJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $tries = 2;
public int $timeout = 300;
/**
* @param array<int> $userIds
*/
public function __construct(public readonly array $userIds)
{
}
public function handle(CreatorJourneyService $journeys): void
{
foreach ($this->userIds as $userId) {
$journeys->rebuildForUser((int) $userId);
}
}
}

View File

@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace App\Jobs;
use App\Services\ArtworkMedalService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class RecalculateArtworkMedalStatsJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
public function __construct(public readonly int $artworkId)
{
}
public function handle(ArtworkMedalService $medals): void
{
$medals->refreshArtworkMedalState($this->artworkId);
}
}