# 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
