From ec275ec02634d31d97aa3a676511cfae4e26e9d8 Mon Sep 17 00:00:00 2001 From: Thorsten Bus Date: Sun, 31 May 2026 04:35:09 +0200 Subject: [PATCH] docs: keyvisual/background/nametag features --- AGENTS.md | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 5 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 9218a19..d6fc198 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -140,6 +140,92 @@ ### Maintenance note --- +## KeyVisual & Background + +Each service export can carry a key-visual image (shown as a standalone fallback slide) and a background image (rendered as a media layer behind every song/sermon slide). + +Resolution is lazy and happens at export time: + +1. Per-service column (`key_visual_filename` / `background_filename` on the `services` table) +2. Global default from Settings (`current_key_visual` / `current_background`) +3. None (slide omitted / no background layer) + +When a service is finalized, the resolved filenames are snapshotted into the per-service columns so the export is stable even if the global default changes later. + +### Key files + +| File | Purpose | +|------|---------| +| `app/Services/ServiceImageResolver.php` | Lazy resolution: per-service column → global Setting → null | +| `app/Http/Controllers/ServiceImageController.php` | `POST /services/{service}/key-visual` + `POST /services/{service}/background`; scope dialog ("Nur für diesen Service" / "Als Standard setzen") | +| `app/Services/FileConversionService.php` | Added `convertImageCover()` for COVER-mode 1920×1080 conversion | +| `app/Services/PlaylistExportService.php` | Injects keyvisual fallback slides and sermon sequence (keyvisual → nametag → slides) | +| `app/Services/ProExportService.php` | Adds background media layer on song/sermon slides | +| `resources/js/Components/ServiceImagePanel.vue` | Upload panel with scope dialog; used on the service Edit page | +| `resources/js/Pages/Services/Edit.vue` | Image panels rendered at the top of the edit form | +| `resources/js/Pages/Settings.vue` | Global default key-visual and background fields | + +### Settings keys + +| Key | Purpose | +|-----|---------| +| `current_key_visual` | Global default key-visual filename | +| `current_background` | Global default background filename | + +### Routes + +| Method | Route | Name | +|--------|-------|------| +| POST | `/services/{service}/key-visual` | `services.key-visual.store` | +| POST | `/services/{service}/background` | `services.background.store` | + +### Parser package changes (commit `582ef85`) + +- New `slideData['background']` contract: background-layer media action on any slide +- New `slideData['imageOnly']` flag: image-only slide (no text layer) +- New Slide read accessors: `hasBackgroundMedia()`, `getBackgroundMediaUrl()`, `getBackgroundMediaFormat()` + +--- + +## NameTag (Namenseinblender) + +A name-tag slide is injected into the sermon sequence (between the key-visual and the sermon slides) to display the moderator and/or preacher name on screen. + +The slide is only generated when the Namenseinblender macro is fully configured in Settings. It renders plain white text and optionally triggers a ProPresenter macro. + +### Name resolution order + +1. `moderator_name` / `preacher_name_override` columns on the `services` table (manual override set via Edit form) +2. Responsible person from the CTS `responsible` JSON field matching the configured role +3. None (slide omitted) + +### Key files + +| File | Purpose | +|------|---------| +| `app/Services/NameTagResolver.php` | Resolves moderator/preacher name: responsible JSON → CTS role → manual override | +| `app/Services/NameTagSlideBuilder.php` | Builds `slideData` for the nametag slide (plain white text + optional macro) | +| `app/Http/Controllers/ServiceController.php` | `PATCH /services/{service}/name-overrides` — saves manual name overrides | +| `resources/js/Pages/Services/Edit.vue` | Name override input fields in the edit form | +| `resources/js/Pages/Settings.vue` | Namenseinblender submenu with macro name/UUID/collection fields | + +### Settings keys + +| Key | Purpose | +|-----|---------| +| `namenseinblender_macro_name` | ProPresenter macro name | +| `namenseinblender_macro_uuid` | ProPresenter macro UUID | +| `namenseinblender_macro_collection_name` | Macro collection name | +| `namenseinblender_macro_collection_uuid` | Macro collection UUID | + +### Routes + +| Method | Route | Name | +|--------|-------|------| +| PATCH | `/services/{service}/name-overrides` | `services.name-overrides.update` | + +--- + ## Repository Structure Two git repositories, both local (no remote): @@ -147,9 +233,9 @@ ## Repository Structure | Repo | Path | Branch | Purpose | |------|------|--------|---------| | **pp-planer** | `/Users/thorsten/AI/pp-planer` | `cts-presenter-app` | Laravel app (main codebase) | -| **propresenter-work** | `/Users/thorsten/AI/propresenter-work/php` | `propresenter-parser` | ProPresenter .pro/.proplaylist parser (composer path dependency) | +| **propresenter** | `/Users/thorsten/AI/propresenter` | `propresenter-parser` | ProPresenter .pro/.proplaylist parser (composer path dependency) | -The parser is linked via `composer.json` path repository: `"url": "../propresenter-work/php"`. +The parser is linked via `composer.json` path repository: `"url": "../propresenter"`. ## Build, Test, Lint Commands @@ -200,10 +286,10 @@ # Migrations ddev exec php artisan migrate ``` -### propresenter-work (Parser Module) +### propresenter (Parser Module) ```bash -cd /Users/thorsten/AI/propresenter-work/php +cd /Users/thorsten/AI/propresenter # Run all tests (230 tests) ./vendor/bin/phpunit @@ -228,7 +314,7 @@ ## Architecture tests/Feature/ # Pest v4 / PHPUnit feature tests tests/e2e/ # Playwright browser tests (TypeScript) -propresenter-work/php/ +propresenter/ src/ # ProFileReader, ProFileGenerator, ProPlaylistGenerator, Song, Group, Slide, Arrangement tests/ # PHPUnit 11 tests with #[Test] attributes ref/ # .pro fixture files for testing