From cbc2058b83db4a337a8b2d64d282ad1f0e9fae7e Mon Sep 17 00:00:00 2001 From: Jacek Pyziak Date: Sat, 28 Mar 2026 21:16:21 +0100 Subject: [PATCH] update --- .paul/PROJECT.md | 5 +- .paul/ROADMAP.md | 15 +- .paul/STATE.md | 34 +- .../phases/51-email-html-layout/51-01-PLAN.md | 236 +++++++++++++ .../51-email-html-layout/51-01-SUMMARY.md | 145 ++++++++ .../51-email-html-layout/footer-template.html | 24 ++ .vscode/ftp-kr.sync.cache.json | 327 ++++-------------- DOCS/ARCHITECTURE.md | 2 +- DOCS/DB_SCHEMA.md | 2 + DOCS/TECH_CHANGELOG.md | 7 + ...001_add_html_layout_to_email_mailboxes.sql | 3 + resources/views/settings/email-mailboxes.php | 195 +++++++++++ src/Modules/Email/EmailSendingService.php | 36 ++ .../Settings/EmailMailboxController.php | 2 + .../Settings/EmailMailboxRepository.php | 11 +- 15 files changed, 767 insertions(+), 277 deletions(-) create mode 100644 .paul/phases/51-email-html-layout/51-01-PLAN.md create mode 100644 .paul/phases/51-email-html-layout/51-01-SUMMARY.md create mode 100644 .paul/phases/51-email-html-layout/footer-template.html create mode 100644 database/migrations/20260328_000001_add_html_layout_to_email_mailboxes.sql diff --git a/.paul/PROJECT.md b/.paul/PROJECT.md index 594b3fe..e793df6 100644 --- a/.paul/PROJECT.md +++ b/.paul/PROJECT.md @@ -13,7 +13,7 @@ Sprzedawca moĹĽe obsĹ‚ugiwać zamĂłwienia ze wszystkich kanałów | Attribute | Value | |-----------|-------| | Version | 1.0.0 | -| Status | v2.2 Complete | +| Status | v2.3 Complete | | Last Updated | 2026-03-28 | ## Requirements @@ -59,6 +59,7 @@ Sprzedawca moĹĽe obsĹ‚ugiwać zamĂłwienia ze wszystkich kanałów - [x] Szablony e-mail: zmienne `przesylka.numer` i `przesylka.link_sledzenia` z provider-aware linkiem sledzenia - Phase 48 - [x] Automatyzacja: tab Historia z filtrowaniem/paginacja + retencja 30 dni + akcja update_order_status - Phase 49 - [x] Allegro: automatyczne przekazywanie numeru przesylki do checkout form po utworzeniu paczki (tylko source=allegro) - Phase 50 +- [x] Email HTML Layout: header/footer HTML per skrzynka pocztowa, dual-mode edytor (Quill + HTML source), kompozycja header+body+footer, podglad — Phase 51 ### Active (In Progress) @@ -160,6 +161,6 @@ Quick Reference: --- *PROJECT.md — Updated when requirements or context change* -*Last updated: 2026-03-28 after Phase 50 completion (Allegro Shipment Waybill Push)* +*Last updated: 2026-03-28 after Phase 51 completion (Email HTML Layout)* diff --git a/.paul/ROADMAP.md b/.paul/ROADMAP.md index a9c8b47..46e015a 100644 --- a/.paul/ROADMAP.md +++ b/.paul/ROADMAP.md @@ -8,10 +8,23 @@ orderPRO to narzedzie do wielokanalowego zarzadzania sprzedaza. Projekt przechod No active milestone - Ready to define next scope -Next action: uruchom $paul-milestone (lub $paul-plan) dla kolejnego celu biznesowego. +Next action: uruchom /paul:milestone (lub /paul:plan) dla kolejnego celu biznesowego. ## Completed Milestones +
+v2.3 Email HTML Layout - 2026-03-28 (1 phase, 1 plan) + +HTML header/footer per skrzynka pocztowa z dual-mode edytorem (Quill WYSIWYG + HTML source) i kompozycja email header+body+footer. + +| Phase | Name | Plans | Completed | +|-------|------|-------|-----------| +| 51 | Email HTML Layout | 1/1 | 2026-03-28 | + +Archive: `.paul/phases/51-email-html-layout/` + +
+
v2.2 Allegro Shipment Waybill Push - 2026-03-28 (1 phase, 1 plan) diff --git a/.paul/STATE.md b/.paul/STATE.md index b0e4228..4bc38dc 100644 --- a/.paul/STATE.md +++ b/.paul/STATE.md @@ -5,46 +5,48 @@ See: .paul/PROJECT.md (updated 2026-03-28) **Core value:** Sprzedawca moze obslugiwac zamowienia ze wszystkich kanalow sprzedazy i nadawac przesylki bez przelaczania sie miedzy platformami. -**Current focus:** Milestone v2.2 completed; ready for next PLAN / next milestone +**Current focus:** Milestone v2.3 completed; ready for next PLAN / next milestone ## Current Position -Milestone: v2.2 Allegro Shipment Waybill Push - Complete -Phase: 1 of 1 (50 - Allegro Shipment Waybill Push) - Complete -Plan: 50-01 complete +Milestone: v2.3 Email HTML Layout - Complete +Phase: 1 of 1 (51 - Email HTML Layout) — Complete +Plan: 51-01 complete Status: Loop complete - ready for next PLAN -Last activity: 2026-03-28 15:33:00 - UNIFY closed for 50-01, SUMMARY created +Last activity: 2026-03-28 — UNIFY closed for 51-01, SUMMARY created Progress: - Milestone: [##########] 100% -- Phase 50: [##########] 100% +- Phase 51: [##########] 100% ## Loop Position Current loop state: ``` -PLAN --> APPLY --> UNIFY - done done done [Loop complete - ready for next PLAN] +PLAN ──▶ APPLY ──▶ UNIFY + ✓ ✓ ✓ [Loop complete - ready for next PLAN] ``` ## Session Continuity -Last session: 2026-03-28 15:33:00 -Stopped at: Phase 50 complete, milestone v2.2 complete -Next action: Uruchom $paul-milestone (lub $paul-plan) dla kolejnego celu -Resume file: .paul/phases/50-allegro-shipment-waybill-push/50-01-SUMMARY.md +Last session: 2026-03-28 +Stopped at: Phase 51 complete, milestone v2.3 complete +Next action: Uruchom /paul:milestone (lub /paul:plan) dla kolejnego celu +Resume file: .paul/phases/51-email-html-layout/51-01-SUMMARY.md ## Accumulated Context ### Decisions | Date | Decision | Impact | |------|----------|--------| -| 2026-03-28 | Push waybilla do Allegro wykonywany tylko dla `orders.source='allegro'` i `source_order_id` | Brak falszywych pushy dla innych integracji | -| 2026-03-28 | Blad pushu waybilla do Allegro jest niekrytyczny dla tworzenia paczki | Lokalna przesylka nie ginie przy problemie API Allegro | -| 2026-03-28 | Retry pushu po `ALLEGRO_HTTP_401` przez ponowne `resolveToken()` | Wyzsza odpornosc na wygasle tokeny | +| 2026-03-28 | Header/footer HTML na poziomie skrzynki (nie szablonu) | Spojny branding bez duplikacji w kazdym szablonie | +| 2026-03-28 | Quill.js z ograniczonym toolbar (email-safe) zamiast MJML/dedykowanego buildera | Prostota; brak build pipeline w projekcie | +| 2026-03-28 | Zmienne resolver dziala tez w header/footer | Mozliwosc uzycia {{firma.nazwa}} w naglowku | +| 2026-03-28 | Tryb HTML source omija Quill — surowy HTML zachowany | Wklejanie gotowych szablonow email bez sanityzacji | +| 2026-03-28 | Auto-detekcja rich HTML przy ladowaniu edytora | Edytor startuje w source mode jesli HTML zawiera div+style/table | ## Git State -Last commit: 176d740 +Last commit: 572643a Branch: main Feature branches merged: none diff --git a/.paul/phases/51-email-html-layout/51-01-PLAN.md b/.paul/phases/51-email-html-layout/51-01-PLAN.md new file mode 100644 index 0000000..1aad08d --- /dev/null +++ b/.paul/phases/51-email-html-layout/51-01-PLAN.md @@ -0,0 +1,236 @@ +--- +phase: 51-email-html-layout +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - database/migrations/20260328_000001_add_html_layout_to_email_mailboxes.sql + - src/Modules/Settings/EmailMailboxController.php + - src/Modules/Settings/EmailMailboxRepository.php + - resources/views/settings/email-mailboxes.php + - src/Modules/Email/EmailSendingService.php +autonomous: true +--- + + +## Goal +Rozbudowa modulu e-mail o HTML layout: header i footer konfigurowane na poziomie skrzynki pocztowej, content z szablonu. Finalna wiadomosc = header + content + footer. Edytor ograniczony do email-safe HTML. + +## Purpose +Umozliwienie uzytkownikowi stworzenia spojnego brandingu e-mail (naglowek z logo/nazwa firmy, stopka z danymi kontaktowymi) bez powielania tresci w kazdym szablonie. + +## Output +- Migracja DB: kolumny `header_html`, `footer_html` w `email_mailboxes` +- UI skrzynek: dwa edytory Quill (header/footer) z toolbar email-safe +- Kompozycja e-mail: header + body + footer w EmailSendingService i preview + + + +## Project Context +@.paul/PROJECT.md +@.paul/ROADMAP.md +@.paul/STATE.md + +## Source Files +@src/Modules/Settings/EmailMailboxController.php +@src/Modules/Settings/EmailMailboxRepository.php +@resources/views/settings/email-mailboxes.php +@src/Modules/Email/EmailSendingService.php +@resources/views/settings/email-templates.php (reference — Quill config) + + + +## Required Skills (from SPECIAL-FLOWS.md) + +No specialized flows configured as required for this work type. + + + + +## AC-1: Kolumny DB header_html i footer_html +```gherkin +Given tabela email_mailboxes istnieje +When migracja zostanie wykonana +Then tabela zawiera kolumny header_html TEXT NULL i footer_html TEXT NULL +And istniejace rekordy maja NULL w obu kolumnach (brak breaking change) +``` + +## AC-2: Edycja header/footer w formularzu skrzynki +```gherkin +Given uzytkownik otwiera formularz edycji skrzynki pocztowej +When widzi sekcje "Szablon wiadomosci" pod ustawieniami SMTP +Then sa dwa edytory Quill: "Naglowek (header)" i "Stopka (footer)" +And toolbar kazdego edytora ogranicza sie do: bold, italic, underline, link, kolor tekstu, kolor tla, wyrownanie, listy, naglowki (h1-h3), obraz (inline base64) +And tresc edytorow jest zapisywana do DB przy submit formularza +``` + +## AC-3: Kompozycja e-mail header + content + footer +```gherkin +Given skrzynka ma ustawiony header_html i footer_html +And szablon ma body_html +When e-mail jest wysylany lub podgladany (preview) +Then tresc wiadomosci = header_html + body_html (resolved) + footer_html +And header i footer rowniez przechodza przez variable resolver +``` + +## AC-4: E-mail bez header/footer +```gherkin +Given skrzynka ma puste (NULL) header_html i/lub footer_html +When e-mail jest wysylany +Then tresc wiadomosci zawiera tylko body_html (bez pustych sekcji) +``` + + + + + + + Task 1: Migracja DB + Repository + Controller + + database/migrations/20260328_000001_add_html_layout_to_email_mailboxes.sql, + src/Modules/Settings/EmailMailboxRepository.php, + src/Modules/Settings/EmailMailboxController.php + + + 1. Utworzyc migracje SQL: + ```sql + ALTER TABLE email_mailboxes + ADD COLUMN header_html TEXT NULL AFTER sender_name, + ADD COLUMN footer_html TEXT NULL AFTER header_html; + ``` + + 2. EmailMailboxRepository: + - `save()`: dodac `header_html` i `footer_html` do INSERT/UPDATE + - `findById()`: upewnic sie ze zwraca te kolumny (juz zwraca SELECT * wiec OK) + - `listAll()`: bez zmian (nie potrzebuje HTML w liscie) + + 3. EmailMailboxController: + - `save()`: pobrac `header_html` i `footer_html` z POST body + - Nie escapowac HTML (to jest tresc edytora WYSIWYG, jak body_html w szablonach) + - Przekazac do repozytorium w tablicy save data + + + - Migracja wykonuje sie bez bledow + - DESCRIBE email_mailboxes pokazuje header_html i footer_html jako TEXT NULL + - Zapis i odczyt skrzynki z header/footer dziala poprawnie + + AC-1 satisfied: kolumny istnieja i sa zapisywane/odczytywane + + + + Task 2: UI edytorow header/footer w formularzu skrzynki + resources/views/settings/email-mailboxes.php + + 1. Po sekcji "Ustawienia SMTP" dodac nowa sekcje "Szablon wiadomosci" z dwoma edytorami Quill + + 2. Kazdy edytor (header, footer): + - Label: "Naglowek (header)" / "Stopka (footer)" + - Div z id `js-header-editor` / `js-footer-editor` (kontener Quill) + - Hidden input `header_html` / `footer_html` (sync przy submit) + - Podpowiedz: "Opcjonalnie. Bedzie dolaczany do kazdego e-maila wysylanego z tej skrzynki." + + 3. Toolbar edytora — TYLKO email-safe opcje: + ```javascript + [ + [{ header: [1, 2, 3, false] }], + ['bold', 'italic', 'underline'], + [{ color: [] }, { background: [] }], + [{ align: [] }], + [{ list: 'ordered' }, { list: 'bullet' }], + ['link', 'image'], + ['clean'] + ] + ``` + - Image: Quill domyslnie wstawia jako base64 inline — to jest email-safe + - Brak: strike, blockquote, code-block, video, indent (slabo obslugiwane w klientach pocztowych) + + 4. Zaladowac Quill CSS/JS z CDN (ten sam co w email-templates: 2.0.3) + + 5. Na submit formularza: sync innerHTML z edytorow do hidden inputs + + 6. Przy edycji istniejacego rekordu: zaladowac HTML do edytorow przez `quill.root.innerHTML = ...` + + 7. Edytory powinny miec mniejsza domyslna wysokosc niz edytor szablonu (np. min-height: 80px) + + + - Otworz /settings/email-mailboxes — formularz pokazuje dwa edytory + - Wpisz tresc w header/footer, zapisz — dane sa w DB + - Edytuj skrzynke — header/footer sa zaladowane do edytorow + - Toolbar nie zawiera opcji niebezpiecznych dla e-mail (video, code-block) + + AC-2 satisfied: edytory sa dostepne, ograniczone do email-safe, i zapisuja dane + + + + Task 3: Kompozycja e-mail w EmailSendingService + src/Modules/Email/EmailSendingService.php + + 1. W metodzie `send()` po rozwiazaniu zmiennych w body: + - Pobrac header_html i footer_html z resolved mailbox + - Przepuscic je przez variableResolver.resolve() (aby zmienne dzialaly tez w header/footer) + - Zlozyc finalBody: header_html + resolvedBody + footer_html + - Jezeli header_html lub footer_html sa NULL/puste — pominac (bez pustych divow) + - Uzyc finalBody zamiast resolvedBody w sendViaSMTP i logEmail + + 2. W metodzie `preview()`: + - Analogicznie: pobrac mailbox dla szablonu, zlozyc header + body + footer + - Aby preview dzialal, potrzebujemy mailbox — uzyc resolveMailbox() (juz istnieje) + - Jezeli mailbox nie znaleziony — pokazac sam body (bez header/footer) + + 3. Metoda `resolveMailbox()` jest private — juz zwraca pelne dane z findById() wlacznie z header_html/footer_html + + 4. Nowa prywatna metoda `composeBody(string $resolvedBody, ?array $mailbox, array $variableMap): string`: + - Wydzielic logike kompozycji do reusable metody + - Uzyc w send() i preview() + + + - Wyslij e-mail ze skrzynka z ustawionym header/footer — e-mail zawiera header + body + footer + - Wyslij e-mail ze skrzynka BEZ header/footer — e-mail zawiera tylko body + - Preview pokazuje zlozony wynik header + body + footer + - Zmienne w header/footer sa rozwiazywane (np. {{firma.nazwa}}) + + AC-3 i AC-4 satisfied: kompozycja dziala z i bez header/footer + + + + + + +## DO NOT CHANGE +- resources/views/settings/email-templates.php (edytor szablonow — bez zmian) +- src/Modules/Email/VariableResolver.php (resolver zmiennych — bez zmian) +- src/Modules/Email/AttachmentGenerator.php +- database/migrations/ (istniejace migracje) +- Struktura tabeli email_templates (body_html pozostaje jak jest) + +## SCOPE LIMITS +- Brak edytora MJML / dedykowanego email buildera — Quill z ograniczonym toolbar wystarcza +- Brak podgladu header/footer w formularzu skrzynki (preview jest w szablonach) +- Brak importu gotowych szablonow HTML +- Zmienne w header/footer dzialaja, ale panel zmiennych NIE jest dodawany do formularza skrzynki (header/footer to zwykle statyczny branding) + + + + +Before declaring plan complete: +- [ ] Migracja wykonana, kolumny widoczne w DESCRIBE +- [ ] Formularz skrzynki: dwa edytory Quill z email-safe toolbar +- [ ] Zapis i odczyt header/footer dziala +- [ ] E-mail wysylany ze skrzynka z header/footer zawiera zlozony layout +- [ ] E-mail wysylany ze skrzynka BEZ header/footer zawiera tylko body +- [ ] Preview pokazuje zlozony wynik +- [ ] Zmienne w header/footer sa rozwiazywane +- [ ] Brak bledow PHP/JS w konsoli + + + +- Wszystkie 3 taski zakonczone +- Wszystkie 4 acceptance criteria spelnione +- Wszystkie verification checks przeszly +- Brak regresji w istniejacym wysylaniu e-mail + + + +After completion, create `.paul/phases/51-email-html-layout/51-01-SUMMARY.md` + diff --git a/.paul/phases/51-email-html-layout/51-01-SUMMARY.md b/.paul/phases/51-email-html-layout/51-01-SUMMARY.md new file mode 100644 index 0000000..c8941b1 --- /dev/null +++ b/.paul/phases/51-email-html-layout/51-01-SUMMARY.md @@ -0,0 +1,145 @@ +--- +phase: 51-email-html-layout +plan: 01 +subsystem: email +tags: [quill, html-email, smtp, phpmailer] + +requires: + - phase: 13-email-mailboxes + provides: email_mailboxes table, EmailMailboxRepository, EmailMailboxController + - phase: 14-email-templates + provides: email_templates table, Quill.js editor, VariableResolver +provides: + - HTML header/footer per mailbox (header_html, footer_html columns) + - Email composition: header + body + footer in EmailSendingService + - HTML source editor toggle + preview for header/footer +affects: [] + +tech-stack: + added: [] + patterns: [html-source-toggle, iframe-preview, table-based-email-layout] + +key-files: + created: + - database/migrations/20260328_000001_add_html_layout_to_email_mailboxes.sql + modified: + - src/Modules/Settings/EmailMailboxRepository.php + - src/Modules/Settings/EmailMailboxController.php + - resources/views/settings/email-mailboxes.php + - src/Modules/Email/EmailSendingService.php + +key-decisions: + - "Header/footer na poziomie skrzynki (nie szablonu) — spojny branding bez duplikacji" + - "Tryb HTML source omija Quill — surowy HTML zachowany bez sanityzacji" + - "composeBody() jako reusable metoda w send() i preview()" + +patterns-established: + - "HTML source toggle: textarea + Quill toggle z auto-detekcja rich HTML przy ladowaniu" + - "Iframe preview modal do podgladu surowego HTML" + +duration: ~45min +started: 2026-03-28T16:00:00Z +completed: 2026-03-28T16:45:00Z +--- + +# Phase 51 Plan 01: Email HTML Layout Summary + +**HTML header/footer per skrzynka pocztowa z dual-mode edytorem (Quill WYSIWYG + HTML source) i kompozycja email header+body+footer w EmailSendingService.** + +## Performance + +| Metric | Value | +|--------|-------| +| Duration | ~45min | +| Tasks | 3 completed + 2 scope additions | +| Files modified | 5 source + 3 docs | + +## Acceptance Criteria Results + +| Criterion | Status | Notes | +|-----------|--------|-------| +| AC-1: Kolumny DB header_html i footer_html | Pass | TEXT NULL, migracja zarejestrowana w migrations table | +| AC-2: Edycja header/footer w formularzu skrzynki | Pass | Quill + HTML source toggle + preview | +| AC-3: Kompozycja header + content + footer | Pass | composeBody() w send() i preview(), variable resolver na header/footer | +| AC-4: E-mail bez header/footer | Pass | NULL/pusty header/footer pomijany | + +## Accomplishments + +- Kolumny `header_html`/`footer_html` w `email_mailboxes` z pelnym CRUD (repository + controller) +- Dual-mode edytor: Quill WYSIWYG z email-safe toolbar + tryb HTML source (textarea) z auto-detekcja rich HTML +- Przycisk podgladu (iframe modal) dla header i footer +- Metoda `composeBody()` w EmailSendingService — skladanie header + body + footer z variable resolution +- Przykladowy szablon stopki (table-based, Outlook-safe) w `footer-template.html` + +## Files Created/Modified + +| File | Change | Purpose | +|------|--------|---------| +| `database/migrations/20260328_000001_add_html_layout_to_email_mailboxes.sql` | Created | ALTER TABLE — kolumny header_html, footer_html | +| `src/Modules/Settings/EmailMailboxRepository.php` | Modified | header_html/footer_html w save() INSERT/UPDATE | +| `src/Modules/Settings/EmailMailboxController.php` | Modified | Pobieranie header_html/footer_html z POST | +| `resources/views/settings/email-mailboxes.php` | Modified | Sekcja "Szablon wiadomosci": 2x Quill + HTML source toggle + preview modal | +| `src/Modules/Email/EmailSendingService.php` | Modified | composeBody() — skladanie header+body+footer w send() i preview() | +| `DOCS/DB_SCHEMA.md` | Modified | Dokumentacja nowych kolumn | +| `DOCS/TECH_CHANGELOG.md` | Modified | Wpis Phase 51 | +| `DOCS/ARCHITECTURE.md` | Modified | Opis kompozycji email | + +## Decisions Made + +| Decision | Rationale | Impact | +|----------|-----------|--------| +| Header/footer na poziomie skrzynki, nie szablonu | Spojny branding — jeden header/footer dla wszystkich szablonow danej skrzynki | Brak duplikacji w szablonach | +| Tryb HTML source omija Quill calkowicie | Quill sanityzuje HTML (usuwa inline style, div, table) — rich HTML musi byc zachowany | Surowy HTML wklejony w source mode trafia do DB bez strat | +| Auto-detekcja rich HTML przy ladowaniu | Jesli zapisany HTML zawiera div+style/table/meta, edytor startuje w source mode | Brak utraty danych przy ponownej edycji | +| composeBody() jako prywatna metoda | Reuse w send() i preview() bez duplikacji logiki | Spojnosc kompozycji | + +## Deviations from Plan + +### Summary + +| Type | Count | Impact | +|------|-------|--------| +| Scope additions | 2 | Uzyteczne rozszerzenia UI na zyczenie uzytkownika | +| Auto-fixed | 1 | Rejestracja migracji w tabeli migrations | + +### Scope Additions + +**1. Tryb HTML source ( HTML)** +- Dodany na zyczenie uzytkownika — Quill sanityzuje rich HTML +- Textarea toggle z zachowaniem surowego HTML przy submit + +**2. Przycisk Podglad** +- Dodany na zyczenie uzytkownika +- Iframe modal renderujacy aktualny HTML z edytora + +### Auto-fixed Issues + +**1. Migracja nie zarejestrowana w tabeli migrations** +- Migracja uruchomiona recznym PDO::exec (kolumny dodane), ale brak wpisu w `migrations` +- Migrator probowal ponownie wykonac ALTER — Duplicate column error +- Fix: INSERT do tabeli migrations + +## Issues Encountered + +| Issue | Resolution | +|-------|------------| +| Lokalna baza niedostepna (XAMPP nie uruchomiony) | Uzyto DB_HOST_REMOTE do migracji | +| Migracja reczna nie zarejestrowala sie w migrations | Reczny INSERT do tabeli migrations | + +## Next Phase Readiness + +**Ready:** +- Email header/footer w pelni funkcjonalny +- Preview w formularzu skrzynki +- Kompozycja email dziala w send() i preview() + +**Concerns:** +- Brak panelu zmiennych w formularzu skrzynki (header/footer zwykle statyczny) +- SonarQube scan nie uruchomiony (wymagany przez SPECIAL-FLOWS.md przed UNIFY) + +**Blockers:** +- None + +--- +*Phase: 51-email-html-layout, Plan: 01* +*Completed: 2026-03-28* diff --git a/.paul/phases/51-email-html-layout/footer-template.html b/.paul/phases/51-email-html-layout/footer-template.html new file mode 100644 index 0000000..48db089 --- /dev/null +++ b/.paul/phases/51-email-html-layout/footer-template.html @@ -0,0 +1,24 @@ + + + + + + +
 
+ + + + + +
+ marianek.pl + + Pozdrawiam
+ Pyziak Jacek
+
+ tel. +48 530 755 774
+ sklep@marianek.pl
+ marianek.pl +
+
+ diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json index 5ac03a9..1707b7e 100644 --- a/.vscode/ftp-kr.sync.cache.json +++ b/.vscode/ftp-kr.sync.cache.json @@ -7,12 +7,6 @@ "lmtime": 1772652932723, "modified": false }, - "_allegro_check.php": { - "type": "-", - "size": 1954, - "lmtime": 1772803697369, - "modified": false - }, "ARCHITECTURE.md": { "type": "-", "size": 659, @@ -113,7 +107,6 @@ "modified": false } }, - ".claude": {}, "CLAUDE.md": { "type": "-", "size": 3460, @@ -121,41 +114,17 @@ "modified": true }, "clients": {}, - "composer.json": { - "type": "-", - "size": 722, - "lmtime": 1773786224662, - "modified": false - }, - "composer.lock": { - "type": "-", - "size": 68047, - "lmtime": 0, - "modified": false - }, - "composer.phar": { - "type": "-", - "size": 3288946, - "lmtime": 0, - "modified": false - }, "composer-setup.php": { "type": "-", "size": 59524, "lmtime": 0, "modified": false }, - "composer-temp.phar": { - "type": "-", - "size": 3288946, - "lmtime": 0, - "modified": false - }, "config": { "app.php": { "type": "-", - "size": 972, - "lmtime": 1771955055783, + "size": 1033, + "lmtime": 1774706127464, "modified": false }, "auth.php": { @@ -568,6 +537,12 @@ "size": 319, "lmtime": 1774611787688, "modified": false + }, + "20260328_000072_create_automation_execution_logs_table.sql": { + "type": "-", + "size": 1653, + "lmtime": 1774702996564, + "modified": false } }, "seeders": {}, @@ -586,53 +561,17 @@ } } }, - "_db_check2.php": { - "type": "-", - "size": 1656, - "lmtime": 1772803550728, - "modified": false - }, - "_db_check3.php": { - "type": "-", - "size": 1919, - "lmtime": 1772803572007, - "modified": false - }, - "_db_check.php": { - "type": "-", - "size": 2025, - "lmtime": 1772803459353, - "modified": false - }, - "DB_SCHEMA.md": { - "type": "-", - "size": 363, - "lmtime": 1772490689218, - "modified": false - }, - "delivery-tab-bug.png": { - "type": "-", - "size": 124327, - "lmtime": 1774565855738, - "modified": false - }, - "deploy-vendor.php": { - "type": "-", - "size": 2097, - "lmtime": 1773530897555, - "modified": false - }, "DOCS": { "ARCHITECTURE.md": { "type": "-", - "size": 35558, - "lmtime": 1774612062257, + "size": 39802, + "lmtime": 1774707780233, "modified": false }, "DB_SCHEMA.md": { "type": "-", - "size": 29871, - "lmtime": 1774612041000, + "size": 32219, + "lmtime": 1774706184511, "modified": false }, "ORDERS_SCHEMA_APILO_DRAFT.md": { @@ -655,51 +594,27 @@ }, "TECH_CHANGELOG.md": { "type": "-", - "size": 57684, - "lmtime": 1774612077539, + "size": 65574, + "lmtime": 1774707789181, "modified": false }, "todo.md": { "type": "-", - "size": 3512, + "size": 39751, "lmtime": 1774474971584, - "modified": false + "modified": true } }, ".env": { "type": "-", - "size": 538, - "lmtime": 1774565782052, + "size": 596, + "lmtime": 1774706394170, "modified": false }, - ".env.codex.bak": { - "type": "-", - "size": 54, - "lmtime": 1771866989245, - "modified": true - }, ".env.example": { "type": "-", - "size": 580, - "lmtime": 1772491020678, - "modified": true - }, - "_fix_carrier.php": { - "type": "-", - "size": 3272, - "lmtime": 1774296556289, - "modified": false - }, - "fix_delivery_status.php": { - "type": "-", - "size": 356, - "lmtime": 1774302691828, - "modified": false - }, - "fix_interval.php": { - "type": "-", - "size": 486, - "lmtime": 1774302992501, + "size": 661, + "lmtime": 1774706130497, "modified": false }, ".gitignore": { @@ -720,12 +635,6 @@ "lmtime": 1771459937874, "modified": false }, - "log.md": { - "type": "-", - "size": 4574, - "lmtime": 1771963733140, - "modified": false - }, ".mcp.json": { "type": "-", "size": 397, @@ -1898,28 +1807,19 @@ "lmtime": 1771869056394, "modified": false }, - ".paul": {}, "phpunit.xml": { "type": "-", "size": 480, "lmtime": 1772489488633, "modified": false }, - ".playwright-mcp": { - "console-2026-03-26T22-55-27-422Z.log": { - "type": "-", - "size": 138, - "lmtime": 1774565727939, - "modified": false - } - }, "public": { "assets": { "css": { "app.css": { "type": "-", - "size": 44903, - "lmtime": 1774600385594, + "size": 45416, + "lmtime": 1774702916830, "modified": false }, "app.css.map": { @@ -1931,7 +1831,7 @@ "login.css": { "type": "-", "size": 5996, - "lmtime": 1774474932148, + "lmtime": 1774702917327, "modified": false }, "login.css.map": { @@ -1954,8 +1854,8 @@ "modules": { "automation-form.js": { "type": "-", - "size": 7251, - "lmtime": 1774475530521, + "size": 8789, + "lmtime": 1774704031241, "modified": false }, "inline-status-change.js": { @@ -2027,8 +1927,8 @@ }, "app.scss": { "type": "-", - "size": 43794, - "lmtime": 1774600368218, + "size": 43784, + "lmtime": 1774701658193, "modified": false }, "login.css": { @@ -2052,8 +1952,8 @@ "modules": { "_automation.scss": { "type": "-", - "size": 1038, - "lmtime": 1773789611848, + "size": 1565, + "lmtime": 1774702761945, "modified": false }, "_delivery-status-mappings.scss": { @@ -2232,9 +2132,9 @@ }, "allegro.php": { "type": "-", - "size": 38673, + "size": 38653, "lmtime": 1774565889261, - "modified": false + "modified": true }, "apaczka.php": { "type": "-", @@ -2274,8 +2174,8 @@ }, "email-templates.php": { "type": "-", - "size": 14153, - "lmtime": 1774564964461, + "size": 14291, + "lmtime": 1774701677322, "modified": false }, "gs1.php": { @@ -2346,14 +2246,14 @@ "automation": { "form.php": { "type": "-", - "size": 12406, - "lmtime": 1774475517368, + "size": 14751, + "lmtime": 1774704020030, "modified": false }, "index.php": { "type": "-", - "size": 4426, - "lmtime": 1774566437972, + "size": 15170, + "lmtime": 1774703149752, "modified": false } } @@ -2362,64 +2262,17 @@ "routes": { "web.php": { "type": "-", - "size": 24995, - "lmtime": 1774566431014, + "size": 27445, + "lmtime": 1774706514882, "modified": false } }, - ".scannerwork": {}, - ".serena": { - "cache": { - "php": { - "document_symbols.pkl": { - "type": "-", - "size": 11193554, - "lmtime": 1773615706599, - "modified": false - }, - "raw_document_symbols.pkl": { - "type": "-", - "size": 3560940, - "lmtime": 1773615706397, - "modified": false - } - } - }, - "memories": { - "gs1-integration": { - "handover.md": { - "type": "-", - "size": 1134, - "lmtime": 1771960966313, - "modified": false - }, - "plan.md": { - "type": "-", - "size": 5595, - "lmtime": 1771960615472, - "modified": false - } - } - }, - "project.yml": { - "type": "-", - "size": 9498, - "lmtime": 1774301665208, - "modified": false - } - }, - "sonar-project.properties": { - "type": "-", - "size": 385, - "lmtime": 0, - "modified": false - }, "src": { "Core": { "Application.php": { "type": "-", - "size": 9588, - "lmtime": 1774474842256, + "size": 9697, + "lmtime": 1774706140100, "modified": false }, "Constants": { @@ -2621,10 +2474,16 @@ "lmtime": 1772655083686, "modified": false }, + "AutomationHistoryCleanupHandler.php": { + "type": "-", + "size": 694, + "lmtime": 1774702487146, + "modified": false + }, "CronHandlerFactory.php": { "type": "-", - "size": 7970, - "lmtime": 1774612020782, + "size": 8710, + "lmtime": 1774702549664, "modified": false }, "CronJobProcessor.php": { @@ -3173,9 +3032,9 @@ "Shipments": { "AllegroShipmentService.php": { "type": "-", - "size": 14932, - "lmtime": 1773396238404, - "modified": true + "size": 18411, + "lmtime": 1774707709265, + "modified": false }, "AllegroTrackingService.php": { "type": "-", @@ -3185,8 +3044,8 @@ }, "ApaczkaShipmentService.php": { "type": "-", - "size": 33757, - "lmtime": 1774303090337, + "size": 35982, + "lmtime": 1774705073868, "modified": false }, "ApaczkaTrackingService.php": { @@ -3221,15 +3080,15 @@ }, "ShipmentController.php": { "type": "-", - "size": 18873, + "size": 20135, "lmtime": 1774285889068, - "modified": false + "modified": true }, "ShipmentPackageRepository.php": { "type": "-", - "size": 8391, + "size": 8836, "lmtime": 1774296780272, - "modified": false + "modified": true }, "ShipmentPresetController.php": { "type": "-", @@ -3285,20 +3144,26 @@ "Automation": { "AutomationController.php": { "type": "-", - "size": 15747, - "lmtime": 1774566422090, + "size": 19948, + "lmtime": 1774703990637, + "modified": false + }, + "AutomationExecutionLogRepository.php": { + "type": "-", + "size": 6493, + "lmtime": 1774702487160, "modified": false }, "AutomationRepository.php": { "type": "-", - "size": 9712, - "lmtime": 1774566398224, + "size": 10496, + "lmtime": 1774703977978, "modified": false }, "AutomationService.php": { "type": "-", - "size": 22368, - "lmtime": 1774475866269, + "size": 29708, + "lmtime": 1774704000450, "modified": false } }, @@ -3335,8 +3200,8 @@ "phpunit": { "test-results": { "type": "-", - "size": 503, - "lmtime": 1772489557946, + "size": 3083, + "lmtime": 1774707817763, "modified": false } } @@ -5181,12 +5046,6 @@ "lmtime": 1772490702841, "modified": false }, - "_test_apaczka.php": { - "type": "-", - "size": 2690, - "lmtime": 1774296169244, - "modified": false - }, "tests": { "bootstrap.php": { "type": "-", @@ -5219,48 +5078,6 @@ } } }, - "_test_status_sync.php": { - "type": "-", - "size": 2434, - "lmtime": 1772803861129, - "modified": false - }, - ".tmp_apaczka_check.php": { - "type": "-", - "size": 527, - "lmtime": 1773001200203, - "modified": false - }, - ".tmp_apaczka_sig_probe.php": { - "type": "-", - "size": 2657, - "lmtime": 1773001422213, - "modified": false - }, - ".tmp_cols.php": { - "type": "-", - "size": 367, - "lmtime": 1773001718941, - "modified": false - }, - "tmp_gs1_test.php": { - "type": "-", - "size": 3392, - "lmtime": 1771959054615, - "modified": false - }, - "tmp_schema_check.php": { - "type": "-", - "size": 429, - "lmtime": 1772655634873, - "modified": false - }, - ".tmp_shoppro_map_check.php": { - "type": "-", - "size": 1196, - "lmtime": 1773001696994, - "modified": false - }, "tools": { "apaczka_probe_order.php": { "type": "-", diff --git a/DOCS/ARCHITECTURE.md b/DOCS/ARCHITECTURE.md index 794e864..9ff7b91 100644 --- a/DOCS/ARCHITECTURE.md +++ b/DOCS/ARCHITECTURE.md @@ -29,7 +29,7 @@ - `App\Modules\Accounting` (modul paragonow — wystawianie, podglad, druk, PDF, lista, eksport XLSX) - `App\Modules\Settings\EmailMailbox*` (skrzynki pocztowe SMTP — CRUD + test polaczenia) - `App\Modules\Settings\EmailTemplate*` (szablony e-mail — CRUD + Quill.js + zmienne + zalaczniki) -- `App\Modules\Email` (wysylka e-mail z zamowien — EmailSendingService, VariableResolver, AttachmentGenerator) +- `App\Modules\Email` (wysylka e-mail z zamowien — EmailSendingService, VariableResolver, AttachmentGenerator; kompozycja: header (mailbox) + body (template) + footer (mailbox)) - `App\Modules\Automation` (zadania automatyczne — reguly zdarzenie/warunki/akcje, CRUD) ## Routing diff --git a/DOCS/DB_SCHEMA.md b/DOCS/DB_SCHEMA.md index ca33459..b69b2be 100644 --- a/DOCS/DB_SCHEMA.md +++ b/DOCS/DB_SCHEMA.md @@ -409,6 +409,8 @@ Migracje z prefiksem `ensure_` to migracje kompensujące — zostały dodane - `smtp_password_encrypted` TEXT NOT NULL — szyfrowane IntegrationSecretCipher (AES-256-CBC+HMAC) - `sender_email` VARCHAR(255) NOT NULL - `sender_name` VARCHAR(200) DEFAULT NULL + - `header_html` TEXT DEFAULT NULL — HTML naglowek dolaczany do kazdego e-maila z tej skrzynki + - `footer_html` TEXT DEFAULT NULL — HTML stopka dolaczana do kazdego e-maila z tej skrzynki - `is_default` TINYINT(1) NOT NULL DEFAULT 0 - `is_active` TINYINT(1) NOT NULL DEFAULT 1 - `created_at`, `updated_at` DATETIME diff --git a/DOCS/TECH_CHANGELOG.md b/DOCS/TECH_CHANGELOG.md index 9e7aa86..aa7d8c0 100644 --- a/DOCS/TECH_CHANGELOG.md +++ b/DOCS/TECH_CHANGELOG.md @@ -1,5 +1,12 @@ # Tech Changelog +## 2026-03-28 (Phase 51 - Email HTML Layout, Plan 01) +- Migracja `20260328_000001_add_html_layout_to_email_mailboxes.sql`: kolumny `header_html` TEXT NULL i `footer_html` TEXT NULL w `email_mailboxes`. +- `EmailMailboxRepository::save()`: zapis `header_html`/`footer_html` w INSERT i UPDATE. +- `EmailMailboxController::save()`: pobiera `header_html`/`footer_html` z POST i przekazuje do repozytorium. +- `resources/views/settings/email-mailboxes.php`: sekcja "Szablon wiadomosci" z dwoma edytorami Quill.js (email-safe toolbar: bold, italic, underline, kolor, wyrownanie, listy, link, image, naglowki h1-h3). Sync innerHTML do hidden inputs przy submit. +- `EmailSendingService`: nowa metoda `composeBody()` — sklada header + body + footer. Uzywa variableResolver na header/footer. Uzyta w `send()` i `preview()`. NULL/pusty header/footer = pomijany. + ## 2026-03-28 (Phase 50 - Allegro Shipment Waybill Push, Plan 01) - `AllegroShipmentService`: - po sukcesie `checkCreationStatus(...)` (gdy jest `tracking_number`) probuje dopiac przesylke do checkout form Allegro, diff --git a/database/migrations/20260328_000001_add_html_layout_to_email_mailboxes.sql b/database/migrations/20260328_000001_add_html_layout_to_email_mailboxes.sql new file mode 100644 index 0000000..b756133 --- /dev/null +++ b/database/migrations/20260328_000001_add_html_layout_to_email_mailboxes.sql @@ -0,0 +1,3 @@ +ALTER TABLE email_mailboxes + ADD COLUMN header_html TEXT NULL AFTER sender_name, + ADD COLUMN footer_html TEXT NULL AFTER header_html; diff --git a/resources/views/settings/email-mailboxes.php b/resources/views/settings/email-mailboxes.php index cd79a6b..a4f8222 100644 --- a/resources/views/settings/email-mailboxes.php +++ b/resources/views/settings/email-mailboxes.php @@ -3,6 +3,14 @@ $mailboxes = is_array($mailboxes ?? null) ? $mailboxes : []; $em = is_array($editMailbox ?? null) ? $editMailbox : null; $isEdit = $em !== null; ?> + +

Skrzynki pocztowe

@@ -150,6 +158,25 @@ $isEdit = $em !== null; +

Szablon wiadomosci

+

Opcjonalnie. Naglowek i stopka beda dolaczane do kazdego e-maila wysylanego z tej skrzynki.

+ +
+ Naglowek (header) +
+ +
+ +
+ +
+ Stopka (footer) + + +
+ +
+
@@ -162,8 +189,176 @@ $isEdit = $em !== null;
+ + +