From 860db0405f6e3737ad01196ebd96ff0b4ae8674b Mon Sep 17 00:00:00 2001 From: Thorsten Bus Date: Sun, 3 May 2026 22:10:46 +0200 Subject: [PATCH] docs: record labels migration verification Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .sisyphus/evidence/task-1.1-pest.txt | 9 ++++ .sisyphus/evidence/task-1.1-schema.txt | 33 ++++++++++++++ .../macros-and-labels-import/decisions.md | 37 ++++++++++++++++ .../macros-and-labels-import/learnings.md | 43 +++++++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 .sisyphus/evidence/task-1.1-pest.txt create mode 100644 .sisyphus/evidence/task-1.1-schema.txt create mode 100644 .sisyphus/notepads/macros-and-labels-import/decisions.md create mode 100644 .sisyphus/notepads/macros-and-labels-import/learnings.md diff --git a/.sisyphus/evidence/task-1.1-pest.txt b/.sisyphus/evidence/task-1.1-pest.txt new file mode 100644 index 0000000..965076a --- /dev/null +++ b/.sisyphus/evidence/task-1.1-pest.txt @@ -0,0 +1,9 @@ +php artisan test tests/Feature/Migrations/LabelsTableTest.php + + PASS Tests\Feature\Migrations\LabelsTableTest + ✓ labels table has expected columns 0.40s + ✓ labels table enforces unique name 0.01s + ✓ labels table allows nullable color 0.01s + + Tests: 3 passed (4 assertions) + Duration: 0.54s diff --git a/.sisyphus/evidence/task-1.1-schema.txt b/.sisyphus/evidence/task-1.1-schema.txt new file mode 100644 index 0000000..222b656 --- /dev/null +++ b/.sisyphus/evidence/task-1.1-schema.txt @@ -0,0 +1,33 @@ +migrate:fresh output + + Dropping all tables ........................................... 13.01ms DONE + + INFO Preparing database. + + Creating migration table ....................................... 4.76ms DONE + + INFO Running migrations. + + 0001_01_01_000000_create_users_table ........................... 9.49ms DONE + 0001_01_01_000001_create_cache_table ........................... 4.35ms DONE + 0001_01_01_000002_create_jobs_table ............................ 4.88ms DONE + 2026_03_01_100000_extend_users_table ........................... 4.60ms DONE + 2026_03_01_100100_create_services_table ........................ 2.92ms DONE + 2026_03_01_100200_create_songs_table ........................... 2.08ms DONE + 2026_03_01_100300_create_song_groups_table ..................... 3.09ms DONE + 2026_03_01_100400_create_song_slides_table ..................... 5.10ms DONE + 2026_03_01_100500_create_song_arrangements_table ............... 3.19ms DONE + 2026_03_01_100600_create_song_arrangement_groups_table ......... 3.61ms DONE + 2026_03_01_100700_create_service_songs_table ................... 3.25ms DONE + 2026_03_01_100800_create_slides_table .......................... 3.68ms DONE + 2026_03_01_100900_create_cts_sync_log_table .................... 4.32ms DONE + 2026_03_02_100000_create_api_request_logs_table ................ 2.15ms DONE + 2026_03_02_121522_add_response_body_to_api_request_logs_table .. 1.31ms DONE + 2026_03_02_130249_add_cts_song_id_to_songs_and_service_songs_tables 3.30ms DONE + 2026_03_02_140000_add_sort_order_to_slides_table ............... 0.91ms DONE + 2026_03_02_200000_create_settings_table ........................ 2.48ms DONE + 2026_03_29_100001_create_service_agenda_items_table ............ 3.03ms DONE + 2026_03_29_100002_add_service_agenda_item_id_to_slides_table .. 13.03ms DONE + 2026_03_29_131045_add_missing_cts_song_id_to_service_songs_table 0.53ms DONE + 2026_03_29_131359_add_has_agenda_to_services_table ............. 1.24ms DONE + 2026_05_03_100100_create_labels_table .......................... 2.50ms DONE diff --git a/.sisyphus/notepads/macros-and-labels-import/decisions.md b/.sisyphus/notepads/macros-and-labels-import/decisions.md new file mode 100644 index 0000000..e0e6c2c --- /dev/null +++ b/.sisyphus/notepads/macros-and-labels-import/decisions.md @@ -0,0 +1,37 @@ +# Decisions — macros-and-labels-import + +## [2026-05-03] Architectural Decisions + +### Schema +- **labels table**: global, unique by name, nullable color, hidden_at (NOT deleted_at) +- **macros table**: unique by uuid (uppercase), hidden_at (NOT deleted_at) +- **macro_assignments**: restrictOnDelete on macro_id and label_id FKs +- **service_macro_overrides**: existence of row = override active; no extra boolean +- **song_arrangement_labels**: replaces song_arrangement_groups; references global label_id + +### Macro Assignment Semantics +- `part_type` enum: `information | moderation | sermon | song | agenda_item` +- `position` enum: `all_slides | first_slide | last_slide | by_label` +- `by_label` is valid for ALL part_types (not songs-only) — validated at app level if restriction needed +- Stacking: multiple assignments can fire on same slide — all applied in `order ASC` +- Override wins 100% — no globals bleed through when override exists + +### Override Semantics +- "Anpassen" snapshots current globals into `service_macro_assignments` rows +- "Auf Standard zurücksetzen" deletes the override row + cascades service_macro_assignments +- German tooltip: "Erstellt eine Kopie der aktuellen globalen Zuweisungen für diesen Gottesdienst. Spätere Änderungen an den globalen Zuweisungen wirken sich auf diesen Gottesdienst NICHT mehr aus." + +### Data Migration +- Destructive: `up()` deletes songs, song_groups, song_slides, song_arrangements, song_arrangement_groups +- `down()` throws RuntimeException (irreversible) +- Guard: `if (!Schema::hasTable('song_groups') || !DB::table('song_groups')->exists()) return;` +- Old 4 macro settings keys → migrated to global assignment if all present; then deleted + +### Label Color Priority +1. Labels file import → always sets/overwrites color +2. .pro song import → only sets color on CREATE (new label); existing color preserved +3. UI → read-only (no manual edit) + +### Current Migration Scope +- `labels` migration only defines the schema; no model or business logic belongs in this task +- Use `hidden_at` instead of `deleted_at` to align with soft-hide semantics diff --git a/.sisyphus/notepads/macros-and-labels-import/learnings.md b/.sisyphus/notepads/macros-and-labels-import/learnings.md new file mode 100644 index 0000000..3ccbbc5 --- /dev/null +++ b/.sisyphus/notepads/macros-and-labels-import/learnings.md @@ -0,0 +1,43 @@ +# 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