feat(14-email-templates): CRUD szablonów e-mail z Quill.js + załączniki

Phase 14 complete (2 plans):
- 14-01: CRUD szablonów, Quill.js editor, system zmiennych {{grupa.pole}}, podgląd, toggle
- 14-02: Select "Załącznik nr 1" z mapą ATTACHMENT_TYPES, kolumna w liście, migracja attachment_1

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-16 23:59:25 +01:00
parent 4d091b2441
commit 2f73a940de
12 changed files with 479 additions and 25 deletions

View File

@@ -0,0 +1,88 @@
---
phase: 14-email-templates
plan: 01
subsystem: database, ui
tags: [email, templates, quill, variables, crud]
requires:
- phase: 13-email-mailboxes
provides: Tabele email_mailboxes, email_templates, email_logs + SMTP CRUD
provides:
- CRUD szablonów e-mail z Quill.js
- System zmiennych {{grupa.pole}} z podglądem
- Toggle status (AJAX) + usuwanie z potwierdzeniem
affects: [14-email-templates/14-02, 15-email-sending]
tech-stack:
added: [quill.js 2.0.3 CDN]
patterns: [VARIABLE_GROUPS const, resolveVariables regex, Quill.js rich text]
key-files:
created:
- src/Modules/Settings/EmailTemplateController.php
- src/Modules/Settings/EmailTemplateRepository.php
- resources/views/settings/email-templates.php
modified:
- resources/views/layouts/app.php
- routes/web.php
- resources/scss/app.scss
key-decisions:
- "Quill.js CDN zamiast npm — brak build pipeline w projekcie"
- "VARIABLE_GROUPS jako stała w kontrolerze — centralna definicja zmiennych"
- "Namespace fixes: AuthService → App\\Modules\\Auth, Flash → App\\Core\\Support"
duration: ~45min
started: 2026-03-16
completed: 2026-03-16
---
# Phase 14 Plan 01: CRUD szablonów e-mail z Quill.js — Summary
**Pełny CRUD szablonów e-mail z edytorem Quill.js, systemem zmiennych {{grupa.pole}}, podglądem, toggle statusu i linkiem w sidebarze.**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~45min |
| Completed | 2026-03-16 |
| Tasks | 3 completed (2 auto + 1 checkpoint) |
| Files modified | 6 |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| CRUD szablonów | Pass | Lista, dodawanie, edycja, usuwanie |
| Quill.js editor | Pass | Rich text z toolbar |
| System zmiennych | Pass | Panel z grupami, wstawianie do edytora |
| Podgląd z rozwiązanymi zmiennymi | Pass | AJAX preview z sample data |
| Toggle aktywności | Pass | AJAX bez przeładowania |
## Accomplishments
- EmailTemplateController + EmailTemplateRepository (pełny CRUD)
- Quill.js 2.0.3 rich text editor z toolbar
- System zmiennych: 4 grupy (zamówienie, kupujący, adres, firma) z 16 zmiennymi
- Podgląd szablonu z rozwiązanymi zmiennymi (sample data)
- AJAX toggle statusu + usuwanie z OrderProAlerts.confirm
## Deviations from Plan
### Auto-fixed Issues
**1. Namespace bugs**
- AuthService: `App\Core\Auth\AuthService``App\Modules\Auth\AuthService`
- Flash: `App\Core\Session\Flash``App\Core\Support\Flash`
- Odkryte podczas testów na serwerze, naprawione natychmiast
## Next Phase Readiness
**Ready:**
- Szablony gotowe do rozszerzenia o załączniki (plan 14-02)
- resolveVariables() gotowy do użycia w fazie 15
---
*Phase: 14-email-templates, Plan: 01*
*Completed: 2026-03-16*

View File

@@ -0,0 +1,213 @@
---
phase: 14-email-templates
plan: 02
type: execute
wave: 1
depends_on: ["14-01"]
files_modified:
- database/migrations/20260316_000001_add_attachment1_to_email_templates.sql
- src/Modules/Settings/EmailTemplateRepository.php
- src/Modules/Settings/EmailTemplateController.php
- resources/views/settings/email-templates.php
- DOCS/DB_SCHEMA.md
autonomous: false
---
<objective>
## Goal
Dodać pole "Załącznik nr 1" do szablonów e-mail z opcją "paragon". Pole zapisywane w DB jako `attachment_1 VARCHAR(50)`, wyświetlane jako select w formularzu szablonu.
## Purpose
Przygotowanie infrastruktury załączników na poziomie szablonu — faza 15 (wysyłka e-mail) odczyta tę konfigurację i automatycznie dołączy PDF paragonu do wiadomości, jeśli istnieje.
## Output
- Migracja SQL dodająca kolumnę `attachment_1`
- Repository/Controller obsługujący nowe pole
- Select w widoku z opcjami "— brak —" / "Paragon"
- Zaktualizowany DB_SCHEMA.md
</objective>
<context>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
## Prior Work
@.paul/phases/14-email-templates/14-01-PLAN.md — CRUD szablonów, Quill.js, system zmiennych
## Source Files
@src/Modules/Settings/EmailTemplateController.php
@src/Modules/Settings/EmailTemplateRepository.php
@resources/views/settings/email-templates.php
@DOCS/DB_SCHEMA.md
</context>
<skills>
## Required Skills (from SPECIAL-FLOWS.md)
| Skill | Priority | When to Invoke | Loaded? |
|-------|----------|----------------|---------|
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |
</skills>
<acceptance_criteria>
## AC-1: Kolumna attachment_1 w bazie danych
```gherkin
Given tabela email_templates istnieje
When migracja 20260316_000001 zostanie wykonana
Then kolumna attachment_1 VARCHAR(50) DEFAULT NULL istnieje w tabeli email_templates
```
## AC-2: Zapis i odczyt attachment_1 przez formularz
```gherkin
Given użytkownik edytuje szablon e-mail
When wybierze "Paragon" w polu "Załącznik nr 1" i zapisze
Then wartość 'receipt' jest zapisana w kolumnie attachment_1
And przy ponownej edycji select pokazuje "Paragon" jako wybraną opcję
```
## AC-3: Opcja "brak" czyści attachment_1
```gherkin
Given szablon ma ustawiony attachment_1 = 'receipt'
When użytkownik zmieni select na " brak " i zapisze
Then wartość attachment_1 w bazie to NULL
```
## AC-4: Lista szablonów pokazuje informację o załączniku
```gherkin
Given szablon ma attachment_1 = 'receipt'
When użytkownik otwiera listę szablonów
Then w kolumnie "Załącznik" widoczne jest "Paragon"
And dla szablonów bez załącznika kolumna pokazuje ""
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Migracja DB + aktualizacja Repository i Controller</name>
<files>
database/migrations/20260316_000001_add_attachment1_to_email_templates.sql,
src/Modules/Settings/EmailTemplateRepository.php,
src/Modules/Settings/EmailTemplateController.php
</files>
<action>
1. Utworzyć migrację SQL:
```sql
ALTER TABLE email_templates ADD COLUMN attachment_1 VARCHAR(50) DEFAULT NULL AFTER mailbox_id;
```
2. EmailTemplateRepository — dodać `attachment_1` do:
- `listAll()` — dodać do SELECT (i do listActive() też)
- `findById()` — dodać do SELECT
- `save()` — dodać do INSERT i UPDATE, wartość: NULL gdy puste/'none', string gdy wybrane
3. EmailTemplateController — dodać stałą ATTACHMENT_TYPES jako centralną mapę:
```php
private const ATTACHMENT_TYPES = [
'receipt' => 'Paragon',
];
```
Dodanie nowego typu w przyszłości = jedna linia w tej tablicy.
4. EmailTemplateController::index() — przekazać `'attachmentTypes' => self::ATTACHMENT_TYPES` do widoku.
5. EmailTemplateController::save() — pobrać `attachment_1` z requestu:
- Jeśli wartość to '' → null
- Jeśli wartość istnieje w kluczach ATTACHMENT_TYPES → zapisz
- Inaczej → null (walidacja)
- Przekazać do repository
</action>
<verify>
- Migracja wykonana na serwerze bez błędów
- DESCRIBE email_templates pokazuje kolumnę attachment_1
- Zapis szablonu z attachment_1 = 'receipt' widoczny w DB
</verify>
<done>AC-1, AC-2, AC-3 satisfied</done>
</task>
<task type="auto">
<name>Task 2: Select w widoku + kolumna w liście + aktualizacja DB_SCHEMA</name>
<files>
resources/views/settings/email-templates.php,
DOCS/DB_SCHEMA.md
</files>
<action>
1. Widok — formularz: dodać select "Załącznik nr 1" w nowym wierszu form-grid-2 (pod tematem/aktywny).
Select generowany dynamicznie z `$attachmentTypes` (przekazane z kontrolera):
```php
<option value="">— brak —</option>
<?php foreach ($attachmentTypes as $key => $label): ?>
<option value="<?= $e($key) ?>" ...selected...><?= $e($label) ?></option>
<?php endforeach; ?>
```
Drugi slot w tym wierszu zostawić pusty lub użyć na przyszły attachment_2.
2. Widok — tabela listy: dodać kolumnę "Załącznik" między "Skrzynka" a "Status":
- Odczytać label z `$attachmentTypes[$tpl['attachment_1']]` jeśli klucz istnieje
- W przeciwnym razie → "—"
3. DOCS/DB_SCHEMA.md — dodać opis kolumny attachment_1 w sekcji email_templates.
</action>
<verify>
- Formularz wyświetla select z dwoma opcjami
- Przy edycji szablonu z attachment_1='receipt' select zaznacza "Paragon"
- Lista szablonów pokazuje kolumnę "Załącznik"
</verify>
<done>AC-2, AC-3, AC-4 satisfied</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<what-built>Select "Załącznik nr 1" w formularzu szablonu + kolumna "Załącznik" w liście</what-built>
<how-to-verify>
1. Wejdź na /settings/email-templates
2. Sprawdź czy lista ma kolumnę "Załącznik"
3. Edytuj istniejący szablon — sprawdź select "Załącznik nr 1" z opcjami "— brak —" i "Paragon"
4. Wybierz "Paragon", zapisz
5. Ponownie edytuj — select powinien mieć "Paragon" zaznaczony
6. W liście przy tym szablonie kolumna "Załącznik" powinna pokazywać "Paragon"
7. Zmień na "— brak —", zapisz — kolumna powinna pokazywać "—"
</how-to-verify>
<resume-signal>Type "approved" to continue, or describe issues to fix</resume-signal>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- resources/views/layouts/app.php — sidebar already configured in 14-01
- Logika wysyłania maili — to jest faza 15
- Quill.js editor i system zmiennych — bez zmian
## SCOPE LIMITS
- Tylko konfiguracja załącznika na poziomie szablonu (jaki typ)
- NIE implementować generowania/dołączania pliku — to faza 15
- Tylko jeden slot załącznika (attachment_1), bez dynamicznego dodawania
</boundaries>
<verification>
Before declaring plan complete:
- [ ] Migracja wykonana, kolumna attachment_1 istnieje
- [ ] Zapis/odczyt attachment_1 działa (receipt / null)
- [ ] Select w formularzu z poprawnymi opcjami
- [ ] Kolumna "Załącznik" w liście szablonów
- [ ] DB_SCHEMA.md zaktualizowany
- [ ] Brak regresji w istniejącym CRUD szablonów
</verification>
<success_criteria>
- Kolumna attachment_1 w DB
- Formularz szablonu pozwala wybrać "Paragon" lub "brak"
- Lista szablonów informuje o skonfigurowanym załączniku
- Faza 15 może odczytać attachment_1 z szablonu i na tej podstawie dołączyć PDF
</success_criteria>
<output>
After completion, create `.paul/phases/14-email-templates/14-02-SUMMARY.md`
</output>

View File

@@ -0,0 +1,112 @@
---
phase: 14-email-templates
plan: 02
subsystem: database, ui
tags: [email, templates, attachments, receipt]
requires:
- phase: 14-email-templates/14-01
provides: CRUD szablonów e-mail, Quill.js editor, system zmiennych
provides:
- Konfiguracja załącznika na poziomie szablonu (attachment_1)
- Mapa typów załączników ATTACHMENT_TYPES w kontrolerze
affects: [15-email-sending]
tech-stack:
added: []
patterns: [ATTACHMENT_TYPES const map for extensible attachment options]
key-files:
created:
- database/migrations/20260316_000001_add_attachment1_to_email_templates.sql
modified:
- src/Modules/Settings/EmailTemplateController.php
- src/Modules/Settings/EmailTemplateRepository.php
- resources/views/settings/email-templates.php
- DOCS/DB_SCHEMA.md
key-decisions:
- "ATTACHMENT_TYPES jako stała mapa w kontrolerze — rozszerzalność bez zmian DB/widoku"
- "attachment_1 VARCHAR(50) zamiast ENUM — elastyczność dodawania nowych typów"
patterns-established:
- "Centralna mapa typów załączników: dodanie nowego typu = 1 linia w ATTACHMENT_TYPES"
duration: ~15min
started: 2026-03-16
completed: 2026-03-16
---
# Phase 14 Plan 02: Załączniki w szablonach e-mail — Summary
**Select "Załącznik nr 1" w szablonach e-mail z opcją "Paragon", rozszerzalną mapą typów ATTACHMENT_TYPES, kolumną w liście i pełnym CRUD.**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~15min |
| Started | 2026-03-16 |
| Completed | 2026-03-16 |
| Tasks | 3 completed (2 auto + 1 checkpoint) |
| Files modified | 5 |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Kolumna attachment_1 w DB | Pass | VARCHAR(50) DEFAULT NULL, zweryfikowane DESCRIBE |
| AC-2: Zapis i odczyt przez formularz | Pass | receipt zapisywane/odczytywane poprawnie |
| AC-3: Opcja "brak" czyści attachment_1 | Pass | Pusta wartość → NULL w DB |
| AC-4: Kolumna "Załącznik" w liście | Pass | "Paragon" / "—" wyświetlane poprawnie |
## Accomplishments
- Kolumna `attachment_1` w `email_templates` z migracją na serwerze
- Centralna mapa `ATTACHMENT_TYPES` w kontrolerze — dodanie nowego typu załącznika = 1 linia PHP
- Select w formularzu generowany dynamicznie z mapy (nie hardkodowany)
- Kolumna "Zalacznik" w liście szablonów z rozwiązywaniem label z mapy
- Walidacja po stronie serwera: tylko klucze z ATTACHMENT_TYPES akceptowane
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `database/migrations/20260316_000001_add_attachment1_to_email_templates.sql` | Created | Migracja: kolumna attachment_1 |
| `src/Modules/Settings/EmailTemplateController.php` | Modified | ATTACHMENT_TYPES const, walidacja, przekazanie do widoku |
| `src/Modules/Settings/EmailTemplateRepository.php` | Modified | attachment_1 w SELECT, INSERT, UPDATE |
| `resources/views/settings/email-templates.php` | Modified | Select w formularzu + kolumna w tabeli |
| `DOCS/DB_SCHEMA.md` | Modified | Opis kolumny attachment_1 |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| ATTACHMENT_TYPES jako stała mapa | User request: w przyszłości inne typy niż paragon | Dodanie nowego typu = 1 linia w tablicy PHP |
| VARCHAR(50) zamiast ENUM | Nowe typy bez ALTER TABLE | Elastyczność kosztem minimalnej walidacji (robiona w PHP) |
| Walidacja przez array_key_exists | Tylko znane typy akceptowane | Bezpieczeństwo: nieznane wartości → NULL |
## Deviations from Plan
None — plan executed exactly as written.
## Issues Encountered
None.
## Next Phase Readiness
**Ready:**
- Faza 15 może odczytać `attachment_1` z szablonu (`listActive()` zawiera pole)
- Jeśli `attachment_1 === 'receipt'` → dołączyć PDF paragonu (dompdf już dostępny z fazy 11)
- Mapa ATTACHMENT_TYPES może być referencją dla logiki generowania załączników
**Concerns:**
- Brak — prosta konfiguracja, logika generowania w fazie 15
**Blockers:**
- None
---
*Phase: 14-email-templates, Plan: 02*
*Completed: 2026-03-16*