T8: Service List Page - ServiceController with index, finalize, reopen actions - Services/Index.vue with status indicators (songs mapped/arranged, slides uploaded) - German UI with finalize/reopen toggle buttons - Status aggregation via SQL subqueries for efficiency - Tests: 3 passing (46 assertions) T9: Song CRUD Backend - SongController with full REST API (index, store, show, update, destroy) - SongService for default groups/arrangements creation - SongRequest validation (title required, ccli_id unique) - Search by title and CCLI ID - last_used_in_service accessor via service_songs join - Tests: 20 passing (85 assertions) T10: Slide Upload Component - SlideController with store, destroy, updateExpireDate - SlideUploader.vue with vue3-dropzone drag-and-drop - SlideGrid.vue with thumbnail grid and inline expire date editing - Multi-format support: images (sync), PPT (async job), ZIP (extract) - Type validation: information (global), moderation/sermon (service-specific) - Tests: 15 passing (37 assertions) T11: Arrangement Configurator - ArrangementController with store, clone, update, destroy - ArrangementConfigurator.vue with vue-draggable-plus - Drag-and-drop arrangement editor with colored group pills - Clone from default or existing arrangement - Color picker for group customization - Prevent deletion of last arrangement - Tests: 4 passing (17 assertions) T12: Song Matching Service - SongMatchingService with autoMatch, manualAssign, requestCreation, unassign - ServiceSongController API endpoints for song assignment - Auto-match by CCLI ID during CTS sync - Manual assignment with searchable song select - Email request for missing songs (MissingSongRequest mailable) - Tests: 14 passing (33 assertions) T13: Translation Service - TranslationService with fetchFromUrl, importTranslation, removeTranslation - TranslationController API endpoints - URL scraping (best-effort HTTP fetch with strip_tags) - Line-count distribution algorithm (match original slide line counts) - Mark song as translated, remove translation - Tests: 18 passing (18 assertions) All tests passing: 103/103 (488 assertions) Build: ✓ Vite production build successful German UI: All user-facing text in German with 'Du' form
3.4 KiB
3.4 KiB
- 2026-03-01: Fuer 1920x1080 Slide-Output ohne Upscaling funktioniert in Intervention Image v3 die Kombination aus schwarzer Canvas (
create()->fill('000000')),scaleDown(width: 1920, height: 1080)und zentriertemplace(...)stabil. - 2026-03-01: Bei Fake-Storage in Tests muessen Zielordner vor direktem Intervention-
save()explizit erstellt werden (makeDirectory/mkdir), sonst wirft InterventionNotWritableException. - 2026-03-01: Fuer Testverifikation von Letterbox/Pillarbox sind farbige PNG-Testbilder sinnvoller als
UploadedFile::fake()->image(...), weil Fake-Bilder sonst komplett schwarz sein koennen. - 2026-03-01: CTS-Sync laeuft stabil mit
EventRequest::where("from", heute)+EventAgendaRequest::fromEvent(...)->get(), wenn Services percts_event_idund Agenda-Songs per (service_id,order) upserted werden; CCLI-Matching bleibt strikt aufsongs.ccli_idund setzt nur dannsong_id/matched_at. - 2026-03-01: SongController CRUD nutzt
auth:sanctumMiddleware;actingAs()in Tests funktioniert damit problemlos (Sanctum unterstuetzt Session-Auth in Tests). - 2026-03-01: SQLite gibt
date-Spalten alsYYYY-MM-DD 00:00:00zurueck stattYYYY-MM-DD— Accessor musssubstr($date, 0, 10)nutzen fuer saubere Date-Only Werte. - 2026-03-01:
Attribute::get()in Laravel 12 fuer berechnete Accessors statt altemget{Name}Attribute()Pattern. Snake_caselast_used_in_servicemapped automatisch auflastUsedInService()Methode. - 2026-03-01: Default-Gruppen (Strophe 1=#3B82F6, Refrain=#10B981, Bridge=#F59E0B) und Default-Arrangement 'Normal' werden automatisch bei Song-Erstellung via SongService erzeugt.
- 2026-03-01:
Rule::unique('songs', 'ccli_id')->ignore($songId)->whereNull('deleted_at')stellt sicher, dass Soft-Deleted Songs die Unique-Constraint nicht blockieren. - 2026-03-01:
bootstrap/app.phpbraucht explizitapi: __DIR__.'/../routes/api.php'inwithRouting()— ist nicht automatisch registriert in Laravel 12. - 2026-03-01: Service-Listenstatus laesst sich performant in einem Query aggregieren via
withCount(...)fuer Song-Metriken plusaddSelect-Subqueries fuerhas_sermon_slidesund datumsabhaengigeinfo_slides_count(inkl. globalerinformation-Slides mitservice_id = null). - 2026-03-01: TranslationService line-count distribution: iterate groups (by order) → slides (by order), for each slide count lines in
text_content, then slice that many lines from the translated text array.array_slice+ offset tracking works cleanly. - 2026-03-01: URL scraping is best-effort only:
Http::timeout(10)->get($url)+strip_tags()+trim(). Return null on any failure — no exceptions bubble up. PHP 8.1+ allowscatch (\Exception)without variable capture. - 2026-03-01: Translation routes:
POST /api/translation/fetch-url(preview),POST /api/songs/{song}/translation/import(save),DELETE /api/songs/{song}/translation(remove). All underauth:sanctummiddleware. - 2026-03-01:
removeTranslationuses a two-step approach: collect slide IDs viaSongSlide::whereIn('song_group_id', $song->groups()->pluck('id'))then bulk-updatetext_content_translated = null, avoiding N+1 queries. - 2026-03-01: Der Arrangement-Konfigurator bleibt stabil bei mehrfachen Gruppeninstanzen, wenn die Sequenz mit Vue-Keys im Muster
${group.id}-${index}gerendert und die Reihenfolge nach jedem Drag-End sofort perrouter.put(..., { preserveScroll: true })gespeichert wird.