# Learnings: ProPresenter Generator and UI Fixes

## Task 6: Translated Textbox Positioning (2026-03-02)

### Implementation Pattern
- **Dual bounds methods**: Created `buildOriginalBounds()` and `buildTranslationBounds()` following same pattern as existing `buildBounds()`
- **Conditional logic in buildCue()**: Check for translation presence, use different bounds for each element
- **Optional parameter pattern**: Modified `buildSlideElement()` to accept `?Rect $bounds = null` parameter, defaulting to `buildBounds()` for backward compatibility

### Exact Values from TestTranslated.pro
- Original textbox: origin(150, 99.543), size(1620×182.946) — top position, ~183px tall
- Translation textbox: origin(150, 303.166), size(1620×113.889) — below, ~114px tall
- Non-translated: origin(150, 100), size(1620×880) — full height

### Testing Approach
- **PHPUnit tests**: Added two new tests to verify bounds for translated and non-translated slides
- **QA scenarios**: Used PHP CLI to generate, write, read back, and verify exact positioning values
- **Method access**: Used `getGraphicsElement()->getBounds()` to access protobuf bounds from TextElement wrapper

### Git Workflow
- **Symlinked vendor**: `vendor/propresenter/parser` is symlink to `/Users/thorsten/AI/propresenter-work/php`
- **Commit location**: Changes committed in propresenter-work repo, not cts-work
- **Branch**: propresenter-parser

### Test Results
- PHPUnit: 14/14 tests pass (95 assertions)
- Laravel: 203/203 tests pass (1115 assertions)
- QA verification: All positioning values match TestTranslated.pro reference exactly

## Task 8: .probundle Export fuer Service-Slide-Bloecke (2026-03-02)

### Export-Pattern
- Fuer ZIP-basierte Exporte ist `Storage::disk("public")->path(...)` teststabiler als harte `storage_path(...)`-Pfade, weil `Storage::fake("public")` dann direkt funktioniert.
- `.probundle` wurde als flaches ZIP umgesetzt: genau eine `.pro` plus alle Bilddateien auf Root-Ebene.
- Medienreferenzen in der `.pro` funktionieren robust mit Dateinamen (Root-Datei im Bundle) statt absoluten Pfaden.

### Controller-Integration
- Route-Parameter fuer Blocktyp (`information|moderation|sermon`) lassen sich sauber per Request-Validation nach `merge()` pruefen und liefern bei Fehlern korrekt 422 in JSON-Requests.
- Download-Response fuer temporaere Bundle-Dateien mit `deleteFileAfterSend(true)` vermeidet Temp-Muell.

### Test-Pattern
- Fuer BinaryFileResponse in Feature-Tests: Datei aus Response in eigenen Temp-Pfad kopieren und dann mit `ZipArchive` validieren.
- Vollsuite hatte einen sporadischen bestehenden Flake in `SongPdfTest`; Re-Run lief voll gruen (206/206).

## Scope-Audit Learnings (F4, 2026-03-02)

- Fuer strikte Scope-Fidelity prueft man nicht nur Dateiliste pro Commit, sondern auch unerwartete Hunks innerhalb der erwarteten Dateien (z.B. Header-Navigation oder Bulk-Delete-Features in einem Export-Task).
- Wenn ein Task auf vendor-Dateien zielt, die im Repo nicht versioniert sind, ist der Task aus Sicht des Git-Diffs nicht nachweisbar umgesetzt ("missing", auch wenn QA-Evidence existiert).
- Commit-Message-Match allein reicht nicht: Task 1/4/7/8 zeigen, dass ein passender Commit-Titel trotzdem deutliche Scope-Creep enthalten kann.
