ChurchService presenter software show creator ## Description There is tool (churchtools - called cts from now on) to plan a church service, that contains all parts of the service (information, songs, sermon, prayer, etc.). Use CTS API for services: . All the wording in the frontend and communication has to be in German with Du, not Sie. ## TechStack - Laravel (Vue+Inertia) App, with Sqlite (switchable to MySQL) - use DB for caching the API data and just "Update" the DB from the API - use CTS API with existing env `CTS_API_TOKEN` (.env for LIVE, .env.example with same content for you) for auth - ONLY DO READS, NO WRITES OR CHANGES ARE ALLOWED ## General - Login should be done via OAUTH for all churchtools users () and linked to an automatically created local user. - There should be Button in the Top Bar, to refresh the Data from the CTS API and a timestamp with the latest refresh. - LoggedIn User should be visible in the Top Bar - every action should be immediately persistent, no separate "save" button required, unless explicitly described. - ProPresenter `.pro` file parser/generator is implemented as a separate composer package (`propresenter/parser`) linked via path repository ## The Plan We use the data from the API, to create a form to finalize the service setup and to create a file for the presenter software at the end. 1. Show all today or future services in a list, with details (Title, Preacher, 'beamer technican', qty of songs, last changed, finalized_at) and state of the setup (No or Yes at...): - x/y songs found and mapped - x/y songs verified arrangement - sermon slides uploaded - X info slides uploaded - finalized at 2. for every service, show Action Buttons: - if finalized: ReOpen and Download - if NOT finalized: Edit and Finalize 3. - ReOpen and Finalize just change the status of the service - Edit shows a form, with these Blocks to edit (details of these blocks are below) - information - moderation - sermon - songs ## Form Blocks ### Block: Information - show list of thumbnails for all uploaded slides with a muted upload date field with uploader name, and a prominent Expiredate field - each thumbnail could be delete (softdelete) or can inline change the date with a datepicker - add big plus icon/area for drag'n'drop or click for fileupload new files with a datepicker for a date, that was added to all files as expire date - automatically show these files to all future services, till the expire date is after the service date ### Block: Moderation Same features as `Block Information` but without the datepicker and only relevant for this service. ### Block: Sermon Same features as `Block Moderation`. ### Block: Songs - Show all songs (Name, CCLI ID, has Translation ..) from the service in the right order. - on every update from the CTS API, try to match the song with the CCLI-ID to an existing song from the DB - if NOT matched - show a button "request creation", which causes an EMAIL to a configured mail address, with the song and the CCLI Id and the ask for create the song - and show a searchable select field of all songs in the DB (CCLI ID included and searchable) to manually assign a song from the DB to this service song - if song found: - if song is translated, show checkbox (default:true) for use the version with translation - every song has a body for the arrangement selection/configuration - select field with all existing arrangements - "add" Button to create a new arangmengt (clone from master order) and ask for a name - "clone" Button to clone the selected arragenement and ask for a name - show the groups of the arrangement and make possible to rearange or add a group to the arrangement via drag'n'drop, like `rev/form-song-arangment-config.jpg` - every song with a selected arrangement ("normal" should selected always as default) should have two buttons: - preview: show the text of the song in the order of the arrangement configuration, prominent highlighted which textpart was with group - download: download the preview as a nice pdf with header/footer and copyright footer from the Song DB. ## File Upload - could be a zip file, contained multiple other files of types below, handle as mass upload - could me multiple files, so handle each one as a single file for types below - could be an image file (png, jpg, jpeg) -> always convert to jpg 1920x1080 (dont cut parts of an image, keep orientation and ratio) - could be a ppt or pptx (powerpoint) -> convert to multiple JPG with 1920x1080 (see jpg convert) ## SongDB Import There should be a menu item for songDB in the Top. - it shows all songs from the DB, with created, last update, ccliID, last_used_in_service every song has a delete (soft_delete), download, translate and an edit button - edit: shows a popup with Name, CCLI and copyright text (all that is available from song metadata) and the arrangement configurator from the service->song block - download: download generated .pro file from the songDB for this song - translate: allow add a full text or an URL to the Full text, and then start an editor, that shows two columns for every slide of every group. Left the original text, right a texteditor, with the imported text - always the same line qty of text from the original is used from the given translated text. Save this as translation for this song, and mark it as `with translation`. - UploadArea for drag'n'drop and click for upload, to upload a .pro file, a zip file with multiple .pro files, or a bunch of .pro files, which should be parsed (this module was integrated later, so show an Exception here till this was finalized) and added into the song DB. --- ## Repository Structure Two git repositories, both local (no remote): | 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) | The parser is linked via `composer.json` path repository: `"url": "../propresenter-work/php"`. ## Build, Test, Lint Commands ### pp-planer (Laravel App) ```bash # First-time setup composer setup # install, .env, key:generate, migrate, npm install, npm build # Dev server (Laravel + Vite + Queue + Logs) composer dev # Build frontend npm run build # Run ALL PHP tests (206 tests, clears config cache first) composer test php artisan test # Single test file php artisan test tests/Feature/ServiceControllerTest.php # Single test method php artisan test --filter=test_service_kann_abgeschlossen_werden # Test suite php artisan test --testsuite=Feature php artisan test --testsuite=Unit # PHP formatting (Laravel Pint, default preset — no pint.json) ./vendor/bin/pint ./vendor/bin/pint --test # check only # E2E tests (requires dev server at http://pp-planer.test) npx playwright test npx playwright test tests/e2e/service-list.spec.ts # Migrations php artisan migrate ``` ### propresenter-work (Parser Module) ```bash cd /Users/thorsten/AI/propresenter-work/php # Run all tests (230 tests) ./vendor/bin/phpunit # Single test file ./vendor/bin/phpunit tests/ProFileReaderTest.php ``` ## Architecture ``` pp-planer/ app/Http/Controllers/ # Inertia controllers (Inertia::render or JSON) app/Models/ # Eloquent models (factories in database/factories/) app/Services/ # Business logic (ChurchToolsService, ProExportService, etc.) app/Jobs/ # Queue jobs (PowerPoint conversion) app/Mail/ # Mailable classes (German content) resources/js/Pages/ # Vue page components (mapped via Inertia::render) resources/js/Components/ # Reusable Vue components resources/js/Composables/ # Vue composables (useAutoSave) resources/js/Layouts/ # AuthenticatedLayout, GuestLayout tests/Feature/ # Pest v4 / PHPUnit feature tests tests/e2e/ # Playwright browser tests (TypeScript) propresenter-work/php/ src/ # ProFileReader, ProFileGenerator, ProPlaylistGenerator, Song, Group, Slide, Arrangement tests/ # PHPUnit 11 tests with #[Test] attributes ref/ # .pro fixture files for testing ``` ## Code Style -- PHP - **Formatter**: Laravel Pint (default Laravel preset, no custom config) - **Imports**: Fully qualified, one per line, alphabetical. App\ first, then Illuminate\, then external. - **Constructors**: Promoted properties with `private readonly`. Empty body: `{}` on same line. ```php public function __construct( private readonly SongMatchingService $songMatchingService, ) {} ``` - **Return types**: Always present. Use union types for multiple returns: `Response|JsonResponse`. - **String concat**: No spaces around `.` operator: `'Fehler: '.$e->getMessage()` - **Null safety**: Nullsafe `?->` and null coalescing `??`. Never suppress with `@`. - **Models**: `$fillable` array (never `$guarded`). `casts()` method (never `$casts` property). Typed relationship returns (`HasMany`, `BelongsTo`). `Attribute::get()` for computed accessors. - **Migrations**: Anonymous class: `return new class extends Migration {`. Methods: `up(): void`, `down(): void`. - **Error messages**: German, Du-form. Flash: `->with('success', '...')`. JSON: `'message'` key. - **Validation**: Inline `$request->validate([...])` with `Rule::in()` for enums. - **Transactions**: `DB::transaction(function () use (...): void { ... })` for multi-step writes. - **Constants**: `private const NAME = [...]` for fixed value sets. ## Code Style -- Vue / Frontend - **Vue 3 Composition API** only. Always `