--- phase: 14-email-templates plan: 01 type: execute wave: 1 depends_on: ["13-01"] files_modified: - src/Modules/Settings/EmailTemplateController.php - src/Modules/Settings/EmailTemplateRepository.php - resources/views/settings/email-templates.php - resources/views/settings/email-template-form.php - routes/web.php - resources/views/layouts/app.php - resources/scss/app.scss - public/assets/css/app.css autonomous: false --- ## Goal CRUD szablonów wiadomości e-mail z edytorem rich-text (Quill.js) i systemem zmiennych do personalizacji treści (np. {{order.number}}, {{buyer.name}}). ## Purpose Użytkownik musi mieć możliwość tworzenia i zarządzania szablonami e-mail, które w fazie 15 będą używane do wysyłki wiadomości z poziomu zamówień. Szablony muszą obsługiwać zmienne dynamiczne rozwiązywane z danych zamówienia. ## Output - EmailTemplateController + EmailTemplateRepository (CRUD) - Widok listy szablonów + formularz edycji z Quill.js - System zmiennych: definicja dostępnych zmiennych, wstawianie z UI, podgląd - Link w sidebarze Settings ## Project Context @.paul/PROJECT.md @.paul/ROADMAP.md @.paul/STATE.md ## Prior Work @.paul/phases/13-email-mailboxes/13-01-SUMMARY.md - email_templates table already created (Phase 13) - EmailMailboxRepository::listActive() ready for mailbox select - Pattern: EmailMailboxController CRUD (same structure to follow) ## Source Files @database/migrations/20260315_000055_create_email_templates_table.sql @src/Modules/Settings/EmailMailboxController.php @src/Modules/Settings/EmailMailboxRepository.php @resources/views/settings/email-mailboxes.php @routes/web.php @resources/views/layouts/app.php ## Required Skills (from SPECIAL-FLOWS.md) | Skill | Priority | When to Invoke | Loaded? | |-------|----------|----------------|---------| | sonar-scanner | required | Po APPLY, przed UNIFY | ○ | ## Skill Invocation Checklist - [ ] sonar-scanner uruchomiony po APPLY ## AC-1: Lista szablonów ```gherkin Given użytkownik jest zalogowany i przechodzi do Ustawienia > Szablony e-mail When strona się ładuje Then widzi tabelę z kolumnami: Nazwa, Temat, Skrzynka, Status, Akcje And każdy szablon ma przyciski: Edytuj, Włącz/Wyłącz, Usuń ``` ## AC-2: Tworzenie i edycja szablonu ```gherkin Given użytkownik jest na stronie szablonów e-mail When wypełnia formularz (nazwa, temat, skrzynka, treść HTML) i zapisuje Then szablon jest zapisany w bazie z poprawnym body_html z Quill.js And po edycji istniejącego szablonu treść Quill jest załadowana poprawnie ``` ## AC-3: Edytor Quill.js z toolbarem ```gherkin Given użytkownik edytuje treść szablonu When korzysta z edytora Then dostępne są: bold, italic, underline, listy, linki, nagłówki, kolory, wyrównanie And treść jest zapisywana jako HTML w polu body_html ``` ## AC-4: System zmiennych — wstawianie ```gherkin Given użytkownik edytuje szablon When klika przycisk "Wstaw zmienną" i wybiera zmienną z listy (np. {{zamowienie.numer}}) Then zmienna jest wstawiana do treści edytora w miejscu kursora And zmienne są wizualnie wyróżnione w edytorze (np. badge/tag) ``` ## AC-5: System zmiennych — definicja ```gherkin Given system zmiennych jest zaimplementowany When użytkownik otwiera listę zmiennych Then widzi pogrupowane zmienne: - Zamówienie: numer, źródło, kwota, waluta, data - Kupujący: imię i nazwisko, email, telefon, login - Adres dostawy: ulica, miasto, kod pocztowy, kraj - Firma: nazwa, NIP (jeśli faktura) And każda zmienna ma opis i placeholder (np. {{zamowienie.numer}}) ``` ## AC-6: Toggle statusu i usuwanie ```gherkin Given szablon istnieje na liście When użytkownik klika Włącz/Wyłącz Then status is_active się zmienia (toggle AJAX) When użytkownik klika Usuń i potwierdzi (OrderProAlerts.confirm) Then szablon jest usunięty z bazy ``` ## AC-7: Podgląd szablonu z przykładowymi danymi ```gherkin Given użytkownik edytuje szablon z zmiennymi When klika przycisk "Podgląd" Then widzi modal z treścią szablonu gdzie zmienne są zastąpione przykładowymi danymi And temat wiadomości jest również rozwiązany z przykładowymi danymi ``` Task 1: EmailTemplateRepository + EmailTemplateController + routes src/Modules/Settings/EmailTemplateRepository.php, src/Modules/Settings/EmailTemplateController.php, routes/web.php **EmailTemplateRepository** (wzorowany na EmailMailboxRepository): - listAll(): array — pobiera wszystkie szablony JOIN email_mailboxes (nazwa skrzynki), ORDER BY name - findById(int $id): ?array — jeden szablon po ID - save(array $data): void — INSERT lub UPDATE (id > 0 = update) - delete(int $id): void — DELETE po ID - toggleStatus(int $id): void — toggle is_active (UPDATE SET is_active = NOT is_active) - listActive(): array — szablony z is_active=1 (do użycia w fazie 15) - Medoo + prepared statements, bez surowego SQL **EmailTemplateController** (wzorowany na EmailMailboxController): - __construct(TemplateEngine, Translator, Auth, EmailTemplateRepository, EmailMailboxRepository) - index(Request): Response — lista szablonów + formularz (edit mode jeśli ?edit=ID) - save(Request): Response — walidacja (name, subject, body_html required) + CSRF + zapis + redirect z Flash - delete(Request): Response — CSRF + usunięcie + redirect z Flash - toggleStatus(Request): Response — AJAX POST, JSON response {success: true} - preview(Request): Response — AJAX POST, przyjmuje subject + body_html, zwraca JSON z resolved variables (przykładowe dane) - getVariables(Request): Response — AJAX GET, zwraca JSON z definicją dostępnych zmiennych pogrupowanych **Definicja zmiennych** (statyczna metoda lub stała w kontrolerze): ``` Zamówienie: {{zamowienie.numer}} — Numer wewnętrzny (OP...) {{zamowienie.numer_zewnetrzny}} — Numer z platformy {{zamowienie.zrodlo}} — Źródło (Allegro/shopPRO/...) {{zamowienie.kwota}} — Kwota brutto {{zamowienie.waluta}} — Waluta (PLN/EUR/...) {{zamowienie.data}} — Data zamówienia Kupujący: {{kupujacy.imie_nazwisko}} — Imię i nazwisko {{kupujacy.email}} — Adres e-mail {{kupujacy.telefon}} — Telefon {{kupujacy.login}} — Login platformy Adres dostawy: {{adres.ulica}} — Ulica z numerem {{adres.miasto}} — Miasto {{adres.kod_pocztowy}} — Kod pocztowy {{adres.kraj}} — Kraj Firma: {{firma.nazwa}} — Nazwa firmy {{firma.nip}} — NIP ``` **Metoda resolveVariables(string $text, array $sampleData): string** - Zamienia {{klucz.pole}} na wartości z $sampleData - Dla podglądu: używa przykładowych (hardcoded) danych - Dla wysyłki (faza 15): otrzyma prawdziwe dane zamówienia **Routes** (dodać w web.php obok email-mailboxes): - GET /settings/email-templates → index - POST /settings/email-templates/save → save - POST /settings/email-templates/delete → delete - POST /settings/email-templates/toggle → toggleStatus - POST /settings/email-templates/preview → preview (AJAX) - GET /settings/email-templates/variables → getVariables (AJAX) - Klasy się ładują bez Fatal Error (PHP syntax check) - Routes zarejestrowane poprawnie - Strona /settings/email-templates renderuje się bez błędów AC-1, AC-2, AC-5, AC-6, AC-7 backend satisfied Task 2: Widoki — lista szablonów + formularz z Quill.js + system zmiennych UI resources/views/settings/email-templates.php, resources/views/settings/email-template-form.php, resources/views/layouts/app.php, resources/scss/app.scss, public/assets/css/app.css **Widok listy** (resources/views/settings/email-templates.php): - Tabela: Nazwa, Temat, Skrzynka (nazwa lub "—"), Status (badge), Akcje - Przycisk "Edytuj" → ?edit=ID - Toggle status: AJAX POST do /settings/email-templates/toggle (jak w mailboxes) - Usuwanie: window.OrderProAlerts.confirm() → POST /settings/email-templates/delete - Flash messages (success/error) - Przycisk "Nowy szablon" → przejście do formularza **Formularz edycji** (osobny plik lub sekcja w tym samym widoku): - Pola: nazwa (input), temat (input — z możliwością wpisania zmiennych ręcznie), skrzynka (select z listActive), status (checkbox) - Edytor Quill.js: - Załadować z CDN: quill@2 (https://cdn.quilljs.com/2.0.3/quill.snow.css + quill.js) - Toolbar: bold, italic, underline, strike, headers (h1-h3), lists (ordered/bullet), link, color, background, align - Hidden input #body_html synchronizowany z Quill content on form submit - Panel zmiennych (sidebar lub dropdown): - Przycisk "Wstaw zmienną" otwiera listę pogrupowaną (pobrana AJAX z /variables) - Klik na zmienną → wstawia {{zmienna.pole}} w miejsce kursora w Quill - Przycisk "Podgląd": - AJAX POST do /settings/email-templates/preview z subject + body_html - Wynik w modalu (resolved subject + resolved body_html) - Przycisk "Zapisz" → submit formularza **Sidebar** (resources/views/layouts/app.php): - Dodać link "Szablony e-mail" pod "Skrzynki pocztowe" w sekcji Settings - activeSettings === 'email-templates' **Style** (resources/scss/app.scss → public/assets/css/app.css): - Styl dla kontenera Quill (.ql-editor min-height: 200px) - Styl dla panelu zmiennych (.email-var-list, .email-var-group, .email-var-item) - Styl dla modala podglądu (reuse istniejący .modal jeśli jest, lub prosty modal) - Kompaktowy layout zgodnie z zasadami projektu **Nie używać** natywnych alert()/confirm() — tylko OrderProAlerts. **Quill CDN** — nie dodawać jako zależność npm/composer, wystarczy CDN w widoku. - Quill.js ładuje się i renderuje edytor - Formularz zapisuje poprawnie (body_html zawiera HTML z Quill) - Zmienne wstawiane w edytor poprawnie - Podgląd wyświetla resolved template - SCSS skompilowane do CSS AC-1, AC-2, AC-3, AC-4, AC-5, AC-6, AC-7 UI satisfied CRUD szablonów e-mail z Quill.js i systemem zmiennych 1. Otwórz: /settings/email-templates 2. Sprawdź: link "Szablony e-mail" widoczny w sidebarze 3. Kliknij "Nowy szablon": a. Wypełnij nazwę, temat (np. "Potwierdzenie zamówienia {{zamowienie.numer}}") b. Wybierz skrzynkę z listy c. W Quill wpisz treść, użyj formatowania (bold, listy) d. Kliknij "Wstaw zmienną" → wybierz np. {{kupujacy.imie_nazwisko}} e. Kliknij "Podgląd" → sprawdź czy zmienne zamienione na przykładowe dane f. Zapisz szablon 4. Na liście: sprawdź czy szablon się pojawił z poprawną nazwą/tematem/skrzynką 5. Edytuj szablon — sprawdź czy Quill załadował treść HTML poprawnie 6. Toggle status (włącz/wyłącz) — badge powinien się zmienić 7. Usuń szablon — potwierdzenie OrderProAlerts, usunięcie z listy Type "approved" to continue, or describe issues to fix ## DO NOT CHANGE - database/migrations/* (tabela email_templates już istnieje z fazy 13) - src/Modules/Settings/EmailMailboxController.php (tylko import/reuse) - src/Modules/Settings/EmailMailboxRepository.php (tylko wywołanie listActive) ## SCOPE LIMITS - Nie implementować wysyłki e-mail (faza 15) - Nie dodawać PHPMailer/SwiftMailer (faza 15) - Nie modyfikować tabeli email_templates (schemat zamrożony) - Quill.js z CDN — bez npm/bundlera - Zmienne rozwiązywane tylko z przykładowymi danymi (prawdziwe dane zamówienia w fazie 15) Before declaring plan complete: - [ ] /settings/email-templates renderuje się bez błędów PHP - [ ] CRUD: create, read, update, delete szablonów działa - [ ] Quill.js edytor ładuje się i zapisuje HTML - [ ] System zmiennych: lista, wstawianie, podgląd z przykładowymi danymi - [ ] Toggle statusu via AJAX działa - [ ] Usuwanie z potwierdzeniem OrderProAlerts działa - [ ] Link w sidebarze Settings aktywny - [ ] SCSS skompilowane, brak inline styles w widokach - [ ] Brak natywnych alert()/confirm() - [ ] CSRF walidowany we wszystkich POST - Wszystkie AC-1 do AC-7 spełnione - Wszystkie taski zakończone - Checkpoint human-verify approved - Brak błędów PHP, brak broken UI After completion, create `.paul/phases/14-email-templates/14-01-SUMMARY.md`