pp-planer/AGENTS.md
Thorsten Bus fa3162b2b7 docs: add build commands and architecture overview to AGENTS.md
Add build/test/lint commands, architecture overview, PHP/Vue/test
code style conventions, and key project constraints. Include dompdf
config, vite HMR note, and sisyphus evidence files.
2026-03-02 23:03:14 +01:00

210 lines
11 KiB
Markdown

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: <https://api.church.tools/package-CT.ChurchService.html>.
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` for auth - ONLY DO READS, NO WRITES OR CHANGES ARE ALLOWED
## General
- Login should be done via OAUTH for all churchtools users (<https://churchtools.academy/de/help/system-einstellungen/oauth-login-systemeinstellungen/oauth-zwischen-zwei-churchtools-systemen/>) 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.
- parser and generator of song files (.pro) are added later, to just add simple placeholder and wait for the detailed spec to implement
## 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.
---
## Build, Test, Lint Commands
```bash
# Setup (first time)
composer setup
# Dev server (Laravel + Vite + Queue + Logs via concurrently)
composer dev
# Build frontend
npm run build
# Run all PHP tests (clears config cache first)
composer test
# or directly:
php artisan test
# Run a single PHP test file
php artisan test tests/Feature/ServiceControllerTest.php
# Run a single test method
php artisan test --filter=test_service_kann_abgeschlossen_werden
# Run only Unit or Feature suite
php artisan test --testsuite=Unit
php artisan test --testsuite=Feature
# PHP code formatting (Laravel Pint - default Laravel preset)
./vendor/bin/pint
# Check only (no changes):
./vendor/bin/pint --test
# Run e2e tests (requires running dev server at http://cts-work.test)
npx playwright test
# Single e2e file:
npx playwright test tests/e2e/service-list.spec.ts
# Migrations
php artisan migrate
```
## Architecture Overview
```
app/
Http/Controllers/ # Inertia controllers, return Inertia::render() or JSON
Http/Requests/ # Form request validation
Http/Middleware/ # HandleInertiaRequests shares props
Models/ # Eloquent models with factories in database/factories/
Services/ # Business logic (ChurchToolsService, SongService, etc.)
Jobs/ # Queue jobs (PowerPoint conversion)
Mail/ # Mailable classes
Cts/ # CTS API spike/sync utilities
resources/js/
Pages/ # Vue page components (mapped via Inertia::render)
Components/ # Reusable Vue components
Composables/ # Vue composables (useAutoSave)
Layouts/ # AuthenticatedLayout, GuestLayout, MainLayout
tests/
Feature/ # HTTP/integration tests (class-based, PHPUnit style)
Unit/ # Unit tests
e2e/ # Playwright browser tests (TypeScript)
```
## Code Style — PHP
- **Formatter**: Laravel Pint (default Laravel preset, no custom config)
- **Indentation**: 4 spaces
- **Imports**: Fully qualified, one per line, grouped (PHP classes, then Laravel, then app)
- **Models**: Use `$fillable` array (not `$guarded`). Use `casts()` method (not `$casts` property). Relationships return typed `HasMany`/`BelongsTo`/etc.
- **Controllers**: Return type hints (`Response`, `JsonResponse`, `RedirectResponse`). Use route-model binding. Use `Inertia::render()` for page responses.
- **Migrations**: Anonymous class style: `return new class () extends Migration { ... }`
- **Error messages**: German. Flash via `->with('success', '...')`. JSON errors use `message` key.
- **Null safety**: Use nullsafe operator `?->` and null coalescing `??`
- **DB operations**: Prefer Eloquent, fall back to `DB::table()` for bulk upserts in sync code
- **SoftDeletes**: Used on `Song` model. Use `whereNull('deleted_at')` in manual queries.
## Code Style — Vue / Frontend
- **Vue 3 Composition API** only, always `<script setup>`. No Options API.
- **Props**: `defineProps({ propName: { type: Type, default: value } })`
- **Emits**: `defineEmits(['event-name'])`
- **Imports**: Use `@/` alias for `resources/js/`. Vue imports from `'vue'`, Inertia from `'@inertiajs/vue3'`.
- **Functions**: Prefer `function name() {}` declarations in components (not `const name = () => {}`)
- **Styling**: Tailwind CSS v4 utility classes inline. Scoped `<style>` only when necessary (e.g. drag-and-drop).
- **State**: `ref()` for reactive state, `computed()` for derived. Use `watch()` for side effects.
- **Routing**: Use `route('name', params)` (Ziggy) for URL generation. Use `router.post/get/delete` from Inertia.
- **Testing attributes**: Add `data-testid="..."` on interactive elements for Playwright e2e tests.
- **All user-facing text must be German** (Du-form, not Sie).
## Code Style — Tests
- **Framework**: Pest v4 (wraps PHPUnit). Feature tests are class-based extending `TestCase` with `RefreshDatabase`.
- **Naming**: `test_snake_case_german_description` (e.g. `test_service_kann_abgeschlossen_werden`)
- **Auth**: `$this->actingAs(User::factory()->create())`
- **Vite**: Call `$this->withoutVite()` before testing Inertia page renders
- **Time**: Use `Carbon::setTestNow('2026-03-01 10:00:00')` for deterministic time
- **Assertions**: `assertInertia(fn ($page) => $page->component('...')->has('...')->where('...'))` for Inertia responses
- **DB**: Tests use in-memory SQLite (configured in `phpunit.xml`)
- **e2e**: Playwright (TypeScript), `tests/e2e/`, baseURL `http://cts-work.test`, auth via `auth.setup.ts`
## Key Conventions
- **CTS API is READ-ONLY** — never write/modify data via ChurchTools API
- **Immediate persistence** — all user actions save instantly, no separate "save" button
- **German locale** — `APP_LOCALE=de`, all UI text in German, Du-form
- **File uploads** — images convert to JPG 1920x1080 (maintain aspect ratio, no cropping); PPT/PPTX convert to multiple JPGs
- **Named routes** — all routes have names, use `route('name')` everywhere
- **ProPresenter (.pro) parser** — placeholder only, not yet implemented