Upload wizard:
- Refactored UploadWizard into modular steps (Step1FileUpload, Step2Details, Step3Publish)
- Extracted reusable hooks: useUploadMachine, useFileValidation, useVisionTags
- Extracted reusable components: CategorySelector, ContentTypeSelector
- Added TagPicker component (studio-style list picker with AI badge + new-tag insertion)
- Fixed TagInput auto-open bug (hasFocusedRef guard)
- Replaced TagInput with TagPicker in UploadSidebar
Vision AI tag suggestions:
- Add UploadVisionSuggestController: sync POST /api/uploads/{id}/vision-suggest
- Calls vision.klevze.net/analyze/all on upload completion (before step 2 opens)
- Two-phase useVisionTags: immediate gateway call + background DB polling
- Trigger fires on uploadReady (not step change) so tags arrive before user sees step 2
- Added vision.gateway config block with VISION_GATEWAY_URL env
Artwork versioning system:
- ArtworkVersion / ArtworkVersionEvent models
- ArtworkVersioningService: createNewVersion, restoreVersion, rate limiting, ranking decay
- Migrations: artwork_versions, artwork_version_events, versioning columns on artworks
- Studio API routes: GET versions, POST restore/{version_id}
- Feature tests: ArtworkVersioningTest (13 cases)
45 lines
952 B
PHP
45 lines
952 B
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
|
|
/**
|
|
* App\Models\ArtworkVersion
|
|
*
|
|
* Represents a single immutable snapshot of an artwork file.
|
|
* Only one version per artwork is marked is_current = true at a time.
|
|
*/
|
|
class ArtworkVersion extends Model
|
|
{
|
|
protected $table = 'artwork_versions';
|
|
|
|
protected $fillable = [
|
|
'artwork_id',
|
|
'version_number',
|
|
'file_path',
|
|
'file_hash',
|
|
'width',
|
|
'height',
|
|
'file_size',
|
|
'change_note',
|
|
'is_current',
|
|
];
|
|
|
|
protected $casts = [
|
|
'is_current' => 'boolean',
|
|
'version_number' => 'integer',
|
|
'width' => 'integer',
|
|
'height' => 'integer',
|
|
'file_size' => 'integer',
|
|
];
|
|
|
|
public function artwork(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Artwork::class);
|
|
}
|
|
}
|