# Learnings — macros-and-labels-import ## [2026-05-03] Session ses_210cd1557ffeGs4SEGrt7hnvyS — Plan Created ### Parser Library - Source at `/Users/thorsten/AI/propresenter/src/` (NOT `/Users/thorsten/AI/propresenter-work/php/` per stale AGENTS.md) - VCS repo: `https://git.stadtmission-butzbach.de/public/propresenter-php.git` (dev-master) - New classes (NOT yet in vendor/): `MacrosFileReader`, `LabelsFileReader`, `Macro`, `MacroLibrary`, `MacroCollection`, `Label`, `LabelLibrary` - `MacrosFileReader::read(string $filePath): MacroLibrary` — raw protobuf binary, no extension - `LabelsFileReader::read(string $filePath): LabelLibrary` — same - `Label::getName()` returns protobuf `text` field — name is the identity (no UUID for labels) - `Macro::getColor()` returns `?array{r,g,b,a}` floats 0..1 — need `MacroColorConverter` to get hex - `Label::getColorHex()` already returns `#RRGGBB` — mirror its formula for macros - **PHP 8.4 required** by parser. App currently requires `^8.2` — BLOCKER for T0.1 ### DB Schema Key Facts - `slides.type` enum is `[information, moderation, sermon]` ONLY — no `agenda_item` - `agenda_item` part_type = slide where `service_agenda_item_id IS NOT NULL` at runtime - `song_groups.color` is NOT NULLABLE (migration says so) — new `labels.color` IS nullable - `service_songs.song_id` is `cascadeOnDelete` — wiping `songs` auto-cascades to `service_songs` ### Export Flow - `ProExportService::buildGroups()` lines 38-69 — macro injection point - `ProExportService::buildMacroData()` lines 71-86 — reads 4 legacy settings keys - Currently injects macro ONLY when group name is "COPYRIGHT" (case-insensitive) - `ProImportService::import(UploadedFile $file): array` — method signature (NOT `importFromFile`) ### Settings Pattern - `Setting::get($key, $default)` / `Setting::set($key, $value)` — simple key/value - `settings` table: `key UNIQUE, value TEXT` ### Critical Decisions - song_groups → labels: global table, "drop all data" migration (no backwards compat) - Hybrid macro scope: global defaults in Settings; per-(service, part_type) override via "Anpassen" - Override = snapshot of globals at creation time; future global changes don't propagate - Stacking: all matching assignments fire, ordered by `macro_assignments.order ASC` - Hidden macros/labels: skip at export, warning badge in editor - Label colors: read-only in UI; Labels file import is sole authority; .pro auto-discovery only sets color on CREATE - FK rules: `restrictOnDelete` on macro/label refs (use `hidden_at`); `cascadeOnDelete` on service-scoped rows ### Migration/Test Notes - `tests/Pest.php` already applies `RefreshDatabase` to all `Feature` tests; no extra setup needed for `Feature/Migrations` - SQLite unique constraint errors can be asserted with `->toThrow(\Exception::class)` in migration tests