---
phase: 13-email-mailboxes
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - database/migrations/20260315_000054_create_email_mailboxes_table.sql
  - database/migrations/20260315_000055_create_email_templates_table.sql
  - database/migrations/20260315_000056_create_email_logs_table.sql
  - src/Modules/Settings/EmailMailboxController.php
  - src/Modules/Settings/EmailMailboxRepository.php
  - resources/views/settings/email-mailboxes.php
  - src/Core/Application.php
autonomous: false
---

<objective>
## Goal
Stworzyć fundament bazodanowy modułu e-mail (3 tabele) oraz pełny CRUD skrzynek pocztowych SMTP w sekcji Ustawienia z walidacją połączenia.

## Purpose
Skrzynki pocztowe to fundament wysyłki e-mail — szablony (faza 14) i wysyłka z zamówień (faza 15) zależą od skonfigurowanych skrzynek SMTP.

## Output
- 3 migracje SQL (email_mailboxes, email_templates, email_logs)
- CRUD skrzynek pocztowych w Ustawienia > Skrzynki pocztowe
- Endpoint testowania połączenia SMTP
</objective>

<context>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md

## Source Files
@src/Modules/Settings/ReceiptConfigController.php (wzorzec CRUD w Settings)
@src/Modules/Settings/ReceiptConfigRepository.php (wzorzec repository)
@src/Modules/Settings/IntegrationSecretCipher.php (szyfrowanie haseł)
@resources/views/settings/accounting.php (wzorzec widoku list+edit)
@resources/views/layouts/app.php (nawigacja sidebar)
@src/Core/Application.php (routing)
</context>

<skills>
## Required Skills (from SPECIAL-FLOWS.md)

| Skill | Priority | When to Invoke | Loaded? |
|-------|----------|----------------|---------|
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |

**BLOCKING:** sonar-scanner musi być uruchomiony przed UNIFY.

## Skill Invocation Checklist
- [ ] sonar-scanner uruchomiony po APPLY
</skills>

<acceptance_criteria>

## AC-1: Migracje tworzą 3 tabele
```gherkin
Given baza danych bez tabel email_*
When uruchomiona zostanie migracja przez Ustawienia > Baza danych
Then tabele email_mailboxes, email_templates, email_logs istnieją z poprawnymi kolumnami i FK
```

## AC-2: CRUD skrzynek pocztowych
```gherkin
Given użytkownik na stronie /settings/email-mailboxes
When dodaje nową skrzynkę (nazwa, serwer, port, użytkownik, hasło)
Then skrzynka pojawia się na liście z zaszyfrowanym hasłem w DB
And można ją edytować i usunąć
```

## AC-3: Walidacja połączenia SMTP
```gherkin
Given użytkownik wypełnił formularz skrzynki pocztowej
When kliknie "Testuj połączenie"
Then system próbuje nawiązać połączenie SMTP z podanymi danymi
And wyświetla komunikat sukcesu lub szczegółowy błąd
```

## AC-4: Nawigacja
```gherkin
Given użytkownik zalogowany do panelu
When przechodzi do Ustawienia
Then widzi pozycję "Skrzynki pocztowe" w menu Settings
And kliknięcie prowadzi do /settings/email-mailboxes
```

</acceptance_criteria>

<tasks>

<task type="auto">
  <name>Task 1: Migracje SQL — 3 tabele email</name>
  <files>
    database/migrations/20260315_000054_create_email_mailboxes_table.sql,
    database/migrations/20260315_000055_create_email_templates_table.sql,
    database/migrations/20260315_000056_create_email_logs_table.sql
  </files>
  <action>
    **Tabela `email_mailboxes`:**
    - id INT UNSIGNED AUTO_INCREMENT PK
    - name VARCHAR(100) NOT NULL — nazwa wyświetlana (np. "Główna skrzynka")
    - smtp_host VARCHAR(255) NOT NULL
    - smtp_port SMALLINT UNSIGNED NOT NULL DEFAULT 587
    - smtp_encryption ENUM('tls','ssl','none') NOT NULL DEFAULT 'tls'
    - smtp_username VARCHAR(255) NOT NULL
    - smtp_password_encrypted TEXT NOT NULL — szyfrowane przez IntegrationSecretCipher
    - sender_email VARCHAR(255) NOT NULL — adres nadawcy (from)
    - sender_name VARCHAR(200) DEFAULT NULL — nazwa nadawcy
    - is_default TINYINT(1) NOT NULL DEFAULT 0
    - is_active TINYINT(1) NOT NULL DEFAULT 1
    - created_at DATETIME DEFAULT CURRENT_TIMESTAMP
    - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

    **Tabela `email_templates`:**
    - id INT UNSIGNED AUTO_INCREMENT PK
    - name VARCHAR(200) NOT NULL — nazwa szablonu
    - subject VARCHAR(500) NOT NULL — temat e-mail (może zawierać zmienne)
    - body_html TEXT NOT NULL — treść HTML (Quill output)
    - mailbox_id INT UNSIGNED DEFAULT NULL — FK do email_mailboxes (nullable = domyślna)
    - is_active TINYINT(1) NOT NULL DEFAULT 1
    - created_at DATETIME DEFAULT CURRENT_TIMESTAMP
    - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    - FOREIGN KEY (mailbox_id) REFERENCES email_mailboxes(id) ON DELETE SET NULL

    **Tabela `email_logs`:**
    - id BIGINT UNSIGNED AUTO_INCREMENT PK
    - template_id INT UNSIGNED DEFAULT NULL — FK do email_templates
    - mailbox_id INT UNSIGNED DEFAULT NULL — FK do email_mailboxes
    - order_id INT UNSIGNED DEFAULT NULL — FK do orders
    - recipient_email VARCHAR(255) NOT NULL
    - recipient_name VARCHAR(200) DEFAULT NULL
    - subject VARCHAR(500) NOT NULL
    - body_html TEXT NOT NULL — treść po rozwinięciu zmiennych
    - attachments_json JSON DEFAULT NULL — lista załączników [{name, path, type}]
    - status ENUM('sent','failed','pending') NOT NULL DEFAULT 'pending'
    - error_message TEXT DEFAULT NULL
    - sent_at DATETIME DEFAULT NULL
    - created_at DATETIME DEFAULT CURRENT_TIMESTAMP
    - FOREIGN KEY (template_id) REFERENCES email_templates(id) ON DELETE SET NULL
    - FOREIGN KEY (mailbox_id) REFERENCES email_mailboxes(id) ON DELETE SET NULL
    - INDEX idx_email_logs_order (order_id)
    - INDEX idx_email_logs_status (status)
    - INDEX idx_email_logs_sent_at (sent_at)

    Wszystkie migracje idempotentne (IF NOT EXISTS).
  </action>
  <verify>Uruchomić migrację przez /settings/database — tabele widoczne w bazie</verify>
  <done>AC-1 satisfied: 3 tabele email_* istnieją z poprawnymi kolumnami i FK</done>
</task>

<task type="auto">
  <name>Task 2: CRUD skrzynek pocztowych + test SMTP</name>
  <files>
    src/Modules/Settings/EmailMailboxController.php,
    src/Modules/Settings/EmailMailboxRepository.php,
    resources/views/settings/email-mailboxes.php,
    src/Core/Application.php,
    resources/views/layouts/app.php
  </files>
  <action>
    **EmailMailboxRepository** (wzorzec jak ReceiptConfigRepository):
    - listAll(): array — wszystkie skrzynki (hasło NIE zwracane w liście)
    - findById(int $id): ?array — z odszyfrowanym hasłem (do edycji)
    - save(array $data): int — insert/update; hasło szyfrowane IntegrationSecretCipher
    - delete(int $id): bool — usunięcie skrzynki
    - findDefault(): ?array — skrzynka z is_default=1

    **EmailMailboxController** (wzorzec jak ReceiptConfigController):
    - index(Request): Response — lista + formularz edycji (?edit=ID)
    - save(Request): Response — walidacja + zapis; pola: name, smtp_host, smtp_port, smtp_encryption, smtp_username, smtp_password, sender_email, sender_name, is_default
    - delete(Request): Response — usunięcie z potwierdzeniem
    - testConnection(Request): Response — AJAX POST; próba fsockopen/stream_socket_client do smtp_host:smtp_port z timeoutem 5s; odpowiedź JSON {success, message}

    **Walidacja testConnection:**
    - Odczytaj dane z POST (lub z DB jeśli id podane)
    - Odszyfruj hasło jeśli z DB
    - Spróbuj otworzyć socket do smtp_host:smtp_port (stream_socket_client, timeout 5s)
    - Jeśli OK: EHLO + AUTH LOGIN z username/password
    - Zwróć JSON: {success: true/false, message: "Połączenie OK" / "Błąd: ..."}
    - Użyj natywnego PHP (fsockopen/stream_socket_client + SMTP commands) — NIE dodawaj PHPMailer/SwiftMailer w tej fazie

    **Widok email-mailboxes.php** (wzorzec jak accounting.php):
    - Tabela skrzynek: Nazwa, Serwer, Port, Email nadawcy, Status (aktywna/nieaktywna), Domyślna (badge), Akcje (edytuj/usuń)
    - Formularz dodawania/edycji: name, smtp_host, smtp_port (default 587), smtp_encryption (select: TLS/SSL/Brak), smtp_username, smtp_password (type=password, placeholder "••••" przy edycji), sender_email, sender_name, is_default (checkbox)
    - Przycisk "Testuj połączenie" — AJAX POST do /settings/email-mailboxes/test, wynik w alert
    - Flash messages na sukces/błąd zapisu/usunięcia

    **Routing w Application.php:**
    - GET /settings/email-mailboxes → EmailMailboxController::index
    - POST /settings/email-mailboxes/save → EmailMailboxController::save
    - POST /settings/email-mailboxes/delete → EmailMailboxController::delete
    - POST /settings/email-mailboxes/test → EmailMailboxController::testConnection

    **Nawigacja w app.php:**
    - Dodać link "Skrzynki pocztowe" w sekcji Settings sidebar (ikona: ✉ lub odpowiednia z istniejącego zestawu)
    - currentSettings === 'email-mailboxes'

    **Hasło przy edycji:**
    - Jeśli pole password puste przy save — zachowaj istniejące zaszyfrowane hasło
    - Jeśli wypełnione — zaszyfruj nowe

    Avoid: Nie dodawać żadnych zewnętrznych bibliotek mailingowych (PHPMailer, SwiftMailer) — w tej fazie wystarczy natywny socket do testu połączenia. Biblioteka mailingowa będzie dodana w fazie 15.
  </action>
  <verify>
    1. Otworzyć /settings/email-mailboxes — widoczna pusta lista
    2. Dodać skrzynkę z danymi SMTP — pojawia się na liście
    3. Kliknąć "Testuj połączenie" — JSON response z wynikiem
    4. Edytować skrzynkę (bez zmiany hasła) — hasło zachowane
    5. Usunąć skrzynkę — znika z listy
  </verify>
  <done>AC-2, AC-3, AC-4 satisfied: CRUD skrzynek działa, test SMTP działa, nawigacja widoczna</done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <what-built>CRUD skrzynek pocztowych z testem połączenia SMTP</what-built>
  <how-to-verify>
    1. Uruchomić migrację: Ustawienia > Baza danych > Migruj
    2. Przejść do: Ustawienia > Skrzynki pocztowe
    3. Dodać skrzynkę testową (dowolny serwer SMTP)
    4. Kliknąć "Testuj połączenie" — sprawdzić wynik
    5. Edytować skrzynkę — zmienić nazwę, zostawić hasło puste → hasło zachowane
    6. Zaznaczyć "Domyślna" → badge na liście
    7. Usunąć skrzynkę → znika
  </how-to-verify>
  <resume-signal>Type "approved" to continue, or describe issues to fix</resume-signal>
</task>

</tasks>

<boundaries>

## DO NOT CHANGE
- src/Modules/Accounting/* (moduł paragonów stabilny)
- src/Modules/Orders/* (moduł zamówień — modyfikacje w fazie 15)
- database/migrations/000001-000053 (istniejące migracje)

## SCOPE LIMITS
- Ten plan tworzy tylko CRUD skrzynek pocztowych — szablony wiadomości to faza 14
- NIE dodawać bibliotek mailingowych (PHPMailer itp.) — to faza 15
- NIE implementować wysyłki maili — tylko test połączenia SMTP
- NIE modyfikować widoków zamówień

</boundaries>

<verification>
Before declaring plan complete:
- [ ] 3 migracje SQL wykonane poprawnie (tabele istnieją)
- [ ] CRUD skrzynek: dodawanie, edycja, usuwanie działa
- [ ] Hasło SMTP szyfrowane w bazie (IntegrationSecretCipher)
- [ ] Test połączenia SMTP zwraca JSON z wynikiem
- [ ] Nawigacja: link "Skrzynki pocztowe" w Settings sidebar
- [ ] Flash messages na sukces/błąd operacji
- [ ] Brak alert()/confirm() — użyty OrderProAlerts
- [ ] CSRF token w formularzach (_token)
- [ ] Wszystkie acceptance criteria spełnione
</verification>

<success_criteria>
- Wszystkie 3 tabele email_* istnieją w bazie
- CRUD skrzynek pocztowych w pełni funkcjonalny
- Test połączenia SMTP działa (JSON response)
- Hasła zaszyfrowane w DB
- Nawigacja w sidebar poprawna
- Brak błędów PHP, brak nowych ostrzeżeń
</success_criteria>

<output>
After completion, create `.paul/phases/13-email-mailboxes/13-01-SUMMARY.md`
</output>
