diff --git a/AGENTS.md b/AGENTS.md index ace3ed3..bc3b0c3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,7 +12,7 @@ ## 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 +- 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 @@ -20,7 +20,7 @@ ## General - 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 +- ProPresenter `.pro` file parser/generator is implemented as a separate composer package (`propresenter/parser`) linked via path repository ## The Plan @@ -95,3 +95,163 @@ ## SongDB Import - 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 | +|------|------|--------|---------| +| **cts-work** | `/Users/thorsten/AI/cts-work` | `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 + +### cts-work (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://cts-work.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 + +``` +cts-work/ + 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 `