- dev/betrieb/deploy.sh: Deploy nur per Tag, mit --seed (Seeder im Wartungsmodus) und --initial (Vorschau/Live einmalig an Ort und Stelle auf Git umstellen) - dev/betrieb/vorschau-auffrischen.sh: Live-DB und Live-Medien in die Vorschau (Generalprobe) - InteriorReleaseSeeder: alle Inhaltsschritte des Relaunchs in einem Lauf, idempotent; Displays, Playlists und Mediathek bleiben unberührt - DisplayInteriorBrandingSeeder überschreibt keinen inzwischen gepflegten Claim mehr - Monitoring: GlitchTip (Server + Browser), /health mit Token, Scheduler-Herzschlag, Alarme per Mail und ntfy, Version in about und /health - public/build versioniert; .gitignore: macOS-Muster Icon traf resources/views/flux/icon/ - Runbook: dev/betrieb/README.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
88 lines
3.8 KiB
PHP
88 lines
3.8 KiB
PHP
<?php
|
||
|
||
use App\Enums\DisplayVersionType;
|
||
use App\Models\Display;
|
||
use App\Models\DisplayMedia;
|
||
use App\Models\DisplayPlaylist;
|
||
use App\Models\DisplayVersion;
|
||
use App\Models\DisplayVersionItem;
|
||
use Database\Seeders\InteriorReleaseSeeder;
|
||
use FluxCms\Core\Models\CmsContent;
|
||
use FluxCms\Core\Models\CmsMedia;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Storage;
|
||
|
||
/**
|
||
* Release-Seeder für Vorschau und Live (08.10.2026): bringt den alten Website-Stand auf den
|
||
* neuen, lässt Displays und Mediathek stehen und ändert beim zweiten Lauf nichts mehr.
|
||
*/
|
||
beforeEach(function () {
|
||
Storage::fake('public');
|
||
});
|
||
|
||
/**
|
||
* Inhalt der Tabellen, die der Release-Seeder beschreibt – ohne Zeitstempel.
|
||
*
|
||
* @return array<string, mixed>
|
||
*/
|
||
function releaseSnapshot(): array
|
||
{
|
||
$tables = ['flux_cms_contents', 'cms_brands', 'cms_articles', 'flux_cms_media', 'display_versions', 'display_version_items', 'display_media', 'displays'];
|
||
|
||
return collect($tables)->mapWithKeys(fn (string $table): array => [
|
||
$table => DB::table($table)->orderBy('id')->get()
|
||
->map(fn (object $row): array => collect((array) $row)->except(['created_at', 'updated_at'])->all())
|
||
->all(),
|
||
])->all();
|
||
}
|
||
|
||
it('brings the old website content up to date and keeps the displays and the media library', function () {
|
||
// Alter Website-Stand, wie er auf Live liegt
|
||
CmsContent::create(['group' => 'home', 'key' => 'hero', 'type' => 'json', 'order' => 0, 'value' => [
|
||
'de' => ['title' => 'Connecting Design and Property', 'subtitle' => 'Alt'],
|
||
]]);
|
||
|
||
// Seit der Vorschau auf Live gepflegt: Display, Modul, Playlist, Display-Mediathek, CMS-Mediathek
|
||
$module = DisplayVersion::factory()->create([
|
||
'type' => DisplayVersionType::B2in,
|
||
'settings' => ['theme' => 'dark', 'header_logo_url' => '/_cabinet/assets/b2in-interior-logo-negative.svg', 'header_claim' => 'Herbstaktion'],
|
||
]);
|
||
$item = DisplayVersionItem::factory()->create([
|
||
'display_version_id' => $module->id,
|
||
'content' => ['image_url' => '/storage/display-media/herbst.webp', 'duration' => 8],
|
||
]);
|
||
$display = Display::factory()->create(['name' => 'Kundenstopper']);
|
||
$playlist = DisplayPlaylist::factory()->create(['display_id' => $display->id]);
|
||
$displayMedia = DisplayMedia::factory()->create(['filename' => 'herbst.webp']);
|
||
$upload = CmsMedia::create([
|
||
'filename' => 'kunde-upload.jpg', 'disk' => 'public', 'path' => 'cms/media/originals/kunde.jpg',
|
||
'type' => 'image', 'mime_type' => 'image/jpeg', 'file_size' => 1, 'collection' => 'Website', 'conversions' => [],
|
||
]);
|
||
|
||
$this->seed(InteriorReleaseSeeder::class);
|
||
|
||
$hero = CmsContent::query()->where('group', 'home')->where('key', 'hero')->first()->getTranslation('value', 'de');
|
||
expect($hero['title'])->not->toContain('Connecting Design')
|
||
->and($hero['slides'])->toHaveCount(11);
|
||
|
||
expect($module->fresh()->settings['header_claim'])->toBe('Herbstaktion')
|
||
->and($item->fresh()->content)->toBe(['image_url' => '/storage/display-media/herbst.webp', 'duration' => 8])
|
||
->and($display->fresh()->name)->toBe('Kundenstopper')
|
||
->and($playlist->fresh())->not->toBeNull()
|
||
->and($displayMedia->fresh()->filename)->toBe('herbst.webp')
|
||
->and($upload->fresh())->not->toBeNull()
|
||
->and(CmsMedia::query()->where('filename', 'b2in/slideshow/rotpunkt-fenix-house.webp')->exists())->toBeTrue();
|
||
|
||
$this->get('/')->assertSuccessful()->assertSee('B2in Interior');
|
||
$this->get('/marken')->assertSuccessful();
|
||
$this->get('/about')->assertSuccessful();
|
||
});
|
||
|
||
it('changes nothing on a second run', function () {
|
||
$this->seed(InteriorReleaseSeeder::class);
|
||
$first = releaseSnapshot();
|
||
|
||
$this->seed(InteriorReleaseSeeder::class);
|
||
|
||
expect(releaseSnapshot())->toEqual($first);
|
||
});
|