--- phase: 06-sonarqube-quality plan: 01 type: execute wave: 1 depends_on: [] files_modified: - src/Core/Exceptions/OrderProException.php - src/Core/Exceptions/AllegroApiException.php - src/Core/Exceptions/AllegroOAuthException.php - src/Core/Exceptions/ApaczkaApiException.php - src/Core/Exceptions/ShipmentException.php - src/Core/Exceptions/IntegrationConfigException.php - src/Modules/Settings/AllegroApiClient.php - src/Modules/Settings/AllegroOAuthClient.php - src/Modules/Settings/AllegroTokenManager.php - src/Modules/Settings/AllegroIntegrationRepository.php - src/Modules/Settings/AllegroIntegrationController.php - src/Modules/Settings/AllegroOrderImportService.php - src/Modules/Settings/AllegroOrdersSyncService.php - src/Modules/Settings/ApaczkaApiClient.php - src/Modules/Settings/ApaczkaIntegrationRepository.php - src/Modules/Shipments/ApaczkaShipmentService.php - src/Modules/Shipments/AllegroShipmentService.php - src/Modules/Shipments/ShipmentController.php - src/Modules/Settings/IntegrationSecretCipher.php - src/Modules/Settings/InpostIntegrationRepository.php - src/Modules/Settings/ShopproIntegrationsRepository.php - src/Modules/Settings/ShopproOrdersSyncService.php - src/Modules/Settings/ShopproPaymentStatusSyncService.php autonomous: true --- ## Goal Zastąpić 86+ wywołań `throw new RuntimeException()` dedykowanymi klasami wyjątków per moduł — eliminacja naruszeń SonarQube php:S112. ## Purpose SonarQube flaguje `RuntimeException` jako zbyt ogólny — łapanie `catch (RuntimeException)` nie mówi nic o tym, jaki błąd nastąpił. Typowane wyjątki umożliwiają precyzyjny catch w wywołującym kodzie i poprawiają czytelność stacktrace. ## Output Hierarchia klas wyjątków w `src/Core/Exceptions/` + podmienione throw w 13 plikach. Liczba S112 w SonarQube spada z 95 do ~5 (pozostałości w Core). ## Project Context @.paul/PROJECT.md @.paul/STATE.md ## Source Files @src/Modules/Settings/AllegroApiClient.php @src/Modules/Settings/AllegroOAuthClient.php @src/Modules/Settings/AllegroTokenManager.php @src/Modules/Shipments/ApaczkaShipmentService.php @src/Modules/Shipments/AllegroShipmentService.php @src/Modules/Settings/ApaczkaApiClient.php @src/Modules/Settings/IntegrationSecretCipher.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 zakończeniu APPLY (CLI w katalogu projektu) ## AC-1: Hierarchia wyjątków istnieje ```gherkin Given brak folderu src/Core/Exceptions/ When plan zostaje wykonany Then folder src/Core/Exceptions/ istnieje z klasami: OrderProException, AllegroApiException, AllegroOAuthException, ApaczkaApiException, ShipmentException, IntegrationConfigException ``` ## AC-2: Allegro-specific throws podmienione ```gherkin Given AllegroApiClient, AllegroOAuthClient, AllegroTokenManager rzucają RuntimeException When plan zostaje wykonany Then wszystkie throw w tych plikach używają AllegroApiException lub AllegroOAuthException ``` ## AC-3: Apaczka-specific throws podmienione ```gherkin Given ApaczkaApiClient, ApaczkaShipmentService, ApaczkaIntegrationRepository rzucają RuntimeException When plan zostaje wykonany Then wszystkie throw w tych plikach używają ApaczkaApiException ``` ## AC-4: Shipment throws podmienione ```gherkin Given AllegroShipmentService, ShipmentController rzucają RuntimeException When plan zostaje wykonany Then wszystkie throw używają ShipmentException ``` ## AC-5: Brak regresji ```gherkin Given aplikacja działa przed zmianą When klasy wyjątków rozszerzają RuntimeException (łańcuch dziedziczenia zachowany) Then istniejące catch (RuntimeException) w kodzie wywołującym nadal działają ``` Task 1: Utwórz hierarchię klas wyjątków src/Core/Exceptions/OrderProException.php, src/Core/Exceptions/AllegroApiException.php, src/Core/Exceptions/AllegroOAuthException.php, src/Core/Exceptions/ApaczkaApiException.php, src/Core/Exceptions/ShipmentException.php, src/Core/Exceptions/IntegrationConfigException.php Utwórz folder src/Core/Exceptions/ i pliki klas z namespace App\Core\Exceptions. Hierarchia: - OrderProException extends \RuntimeException — baza dla wszystkich własnych wyjątków - AllegroApiException extends OrderProException — błędy HTTP/JSON Allegro API i OAuth - AllegroOAuthException extends AllegroApiException — specyficznie błędy OAuth (token refresh, brak tokenów) - ApaczkaApiException extends OrderProException — błędy API Apaczka (HTTP, curl, payload) - ShipmentException extends OrderProException — błędy tworzenia/pobierania przesyłek (brak zamówienia, brak providera, brak paczki) - IntegrationConfigException extends OrderProException — błędy konfiguracji integracji (brak rekordu w DB, brak klucza API, brak sekretu) Każda klasa: minimalna (tylko class declaration + extends). Brak dodatkowych metod — nie powielać logiki. Nie dodawaj konstruktorów ani innych metod — klasy wyjątków mają być tylko markerami. php -l src/Core/Exceptions/OrderProException.php (i pozostałe 5 plików) — każdy zwraca "No syntax errors" AC-1 satisfied: folder src/Core/Exceptions/ z 6 klasami istnieje i jest poprawny składniowo Task 2: Podmień RuntimeException w plikach Allegro src/Modules/Settings/AllegroApiClient.php, src/Modules/Settings/AllegroOAuthClient.php, src/Modules/Settings/AllegroTokenManager.php, src/Modules/Settings/AllegroIntegrationRepository.php, src/Modules/Settings/AllegroIntegrationController.php, src/Modules/Settings/AllegroOrderImportService.php, src/Modules/Settings/AllegroOrdersSyncService.php W każdym pliku: 1. Dodaj use App\Core\Exceptions\AllegroApiException; (i AllegroOAuthException tam gdzie dotyczy OAuth) 2. Zastąp throw new RuntimeException(...) odpowiednią klasą: - AllegroApiClient.php (18x): HTTP/JSON/curl błędy → AllegroApiException; błędy OAuth (ALLEGRO_HTTP_401) → AllegroApiException - AllegroOAuthClient.php (6x): wszystkie → AllegroOAuthException - AllegroTokenManager.php (3x): brak połączenia OAuth, brak danych, niepowodzenie refresh → AllegroOAuthException - AllegroIntegrationRepository.php (1x): brak rekordu → IntegrationConfigException (użyj use App\Core\Exceptions\IntegrationConfigException) - AllegroIntegrationController.php (1x): brak credentials → IntegrationConfigException - AllegroOrderImportService.php (2x): błędy importu → AllegroApiException - AllegroOrdersSyncService.php (1x): brak aktywnej integracji → IntegrationConfigException Uwaga: NIE zmieniaj logiki catch bloków — tylko throw. NIE zmieniaj komunikatów błędów. Uwaga: \RuntimeException w AllegroIntegrationController (jeśli catch) — NIE ruszać. php -l src/Modules/Settings/AllegroApiClient.php php -l src/Modules/Settings/AllegroOAuthClient.php php -l src/Modules/Settings/AllegroTokenManager.php grep -r "new RuntimeException" src/Modules/Settings/Allegro*.php — powinno zwrócić 0 wyników AC-2 satisfied: pliki Allegro nie zawierają throw new RuntimeException Task 3: Podmień RuntimeException w plikach Apaczka, Shipment i pozostałych src/Modules/Settings/ApaczkaApiClient.php, src/Modules/Settings/ApaczkaIntegrationRepository.php, src/Modules/Shipments/ApaczkaShipmentService.php, src/Modules/Shipments/AllegroShipmentService.php, src/Modules/Shipments/ShipmentController.php, src/Modules/Settings/IntegrationSecretCipher.php, src/Modules/Settings/InpostIntegrationRepository.php, src/Modules/Settings/ShopproIntegrationsRepository.php, src/Modules/Settings/ShopproOrdersSyncService.php, src/Modules/Settings/ShopproPaymentStatusSyncService.php Podmień RuntimeException: - ApaczkaApiClient.php (9x): curl/HTTP/JSON błędy → ApaczkaApiException - ApaczkaIntegrationRepository.php (4x): brak rekordu/klucza → IntegrationConfigException - ApaczkaShipmentService.php (15x): brak zamówienia/paczki/etykiety → ShipmentException; brak konfiguracji (brak app_id) → IntegrationConfigException; brak danych nadawcy → IntegrationConfigException - AllegroShipmentService.php (8x): brak zamówienia/paczki/przesyłki → ShipmentException; brak danych nadawcy → IntegrationConfigException - ShipmentController.php (3x): nieznany provider, brak paczki, brak providera → ShipmentException - IntegrationSecretCipher.php (3x): brak sekretu, błąd szyfrowania → IntegrationConfigException - InpostIntegrationRepository.php (1x): brak rekordu → IntegrationConfigException - ShopproIntegrationsRepository.php (1x): INTEGRATION_NOT_FOUND → IntegrationConfigException - ShopproOrdersSyncService.php (2x): brak danych API, błąd pobierania zamówień → \RuntimeException (zostawić — są wewnątrz try-catch i message pochodzi z zewnętrznego API) - ShopproPaymentStatusSyncService.php (1x): zostawić jako \RuntimeException (message z zewnętrznego API) W każdym pliku dodaj odpowiednie use statements na górze. NIE zmieniaj logiki catch — tylko throw. php -l src/Modules/Shipments/ApaczkaShipmentService.php php -l src/Modules/Shipments/AllegroShipmentService.php php -l src/Modules/Settings/ApaczkaApiClient.php grep -rn "new RuntimeException" src/ — powinno zwrócić maks. 5 wyników (ShopproOrdersSyncService, ShopproPaymentStatusSyncService, CronRunner, AllegroTokenRefreshHandler — intentional pozostałości) AC-3, AC-4, AC-5 satisfied: Apaczka i Shipment pliki używają typowanych wyjątków; łańcuch dziedziczenia od RuntimeException zachowany ## DO NOT CHANGE - Bloki catch (RuntimeException) w controllers/handlers — łańcuch dziedziczenia zachowuje kompatybilność, ale NIE ruszaj istniejących catch - Komunikaty błędów w throw — tylko typ wyjątku się zmienia - src/Core/Exceptions/ — nie tworzyć tu nic poza 6 klasami z tego planu - routes/web.php - Pliki widoków (resources/views/) ## SCOPE LIMITS - Nie refaktoryzuj logiki poza podmianą throw - Nie dodawaj konstruktorów ani metod do klas wyjątków - Nie zmieniaj sposobu obsługi błędów w UI (flash messages, HTTP redirecty) - Core wyjątki (Router.php, Template.php, Translator.php, ConnectionFactory.php, Migrator.php) — zostawić jako RuntimeException (mają sens jako generyczne) Przed zamknięciem planu: - [ ] php -l na wszystkich zmodyfikowanych plikach PHP — zero błędów składniowych - [ ] grep -rn "new RuntimeException" src/ — max 5 wyników (tylko Core + 2 Shoppro intentional) - [ ] ls src/Core/Exceptions/ — 6 plików: OrderProException, AllegroApiException, AllegroOAuthException, ApaczkaApiException, ShipmentException, IntegrationConfigException - [ ] Aplikacja startuje bez błędów (wejście na stronę główną, brak PHP fatal errors w logach) - [ ] sonar-scanner uruchomiony — sprawdź czy S112 violations zmalały - Wszystkie 3 taski ukończone - Zero błędów składniowych PHP - grep "new RuntimeException" src/ zwraca ≤5 wyników - SonarQube S112 spada z 95 do ≤10 Po zakończeniu utwórz `.paul/phases/06-sonarqube-quality/06-01-SUMMARY.md`